diff --git a/disas/riscv-op.c.inc b/disas/riscv-op.c.inc index 1d334e4857..425473ee61 100644 --- a/disas/riscv-op.c.inc +++ b/disas/riscv-op.c.inc @@ -490,6 +490,11 @@ OP(vaadd_vv, "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vaadd_vx, "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vaaddu_vv, "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vaaddu_vx, "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vabd_vv, "vabd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vabd_vx, "vabd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, rvcp_vabd_vx) +OP(vabdu_vv, "vabdu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vabdu_vx, "vabdu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vabs_v, "vabs.v", rv_codec_illegal, rv_fmt_vd_vs2_vm) OP(vadc_vim, "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) OP(vadc_vvm, "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) OP(vadc_vxm, "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) @@ -861,6 +866,10 @@ OP(vsuxei16_v, "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) OP(vsuxei32_v, "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) OP(vsuxei64_v, "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) OP(vsuxei8_v, "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vwabda_vv, "vwabda.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwabda_vx, "vwabda.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwabdau_vv, "vwabdau.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwabdau_vx, "vwabdau.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vwadd_vv, "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vwadd_vx, "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vwadd_wv, "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) diff --git a/disas/riscv.c b/disas/riscv.c index d755172164..ca0d6e90b3 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -104,6 +104,7 @@ static const rvc_constraint rvcc_j[] = { rvc_rd_eq_x0, rvc_end }; static const rvc_constraint rvcc_ret[] = { rvc_rs1_eq_ra, rvc_end }; static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, rvc_end }; +static const rvc_constraint rvcc_vabs_v[] = { rvc_rs1_eq_x0, rvc_end }; static const rvc_constraint rvcc_true[] = { rvc_end }; /* pseudo-instruction metadata */ @@ -243,6 +244,11 @@ static const rv_comp_data rvcp_fsgnjx_q[] = { { }, }; +static const rv_comp_data rvcp_vabd_vx[] = { + { &op_vabs_v, rvcc_vabs_v }, + { }, +}; + /* Convert compressed insns into normal insns via pseudo expansion. */ #define DECOMP(X) &(const rv_comp_data){ &X, rvcc_true } @@ -2025,6 +2031,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) case 48: return &op_vwredsumu_vs; case 49: return &op_vwredsum_vs; case 53: return &op_vwsll_vv; + case 61: return &op_vwabda_vv; + case 62: return &op_vwabdau_vv; } break; case 1: @@ -2167,6 +2175,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) break; } break; + case 21: return &op_vabd_vv; + case 22: return &op_vabdu_vv; case 23: if ((inst >> 25) & 1) { return &op_vcompress_vm; @@ -2352,6 +2362,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) case 46: return &op_vnclipu_wx; case 47: return &op_vnclip_wx; case 53: return &op_vwsll_vx; + case 61: return &op_vwabda_vx; + case 62: return &op_vwabdau_vx; } break; case 5: @@ -2428,6 +2440,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) } } break; + case 21: return &op_vabd_vx; + case 22: return &op_vabdu_vx; case 32: return &op_vdivu_vx; case 33: return &op_vdiv_vx; case 34: return &op_vremu_vx; diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 153fe11815..dab47b6ca3 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -362,30 +362,6 @@ the addition of volatile memory support, it is now necessary to distinguish between persistent and volatile memory backends. As such, memdev is deprecated in favor of persistent-memdev. - -RISC-V CPU properties which start with capital 'Z' (since 8.2) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -All RISC-V CPU properties which start with capital 'Z' are being deprecated -starting in 8.2. The reason is that they were wrongly added with capital 'Z' -in the past. CPU properties were later added with lower-case names, which -is the format we want to use from now on. - -Users which try to use these deprecated properties will receive a warning -recommending to switch to their stable counterparts: - -- "Zifencei" should be replaced with "zifencei" -- "Zicsr" should be replaced with "zicsr" -- "Zihintntl" should be replaced with "zihintntl" -- "Zihintpause" should be replaced with "zihintpause" -- "Zawrs" should be replaced with "zawrs" -- "Zfa" should be replaced with "zfa" -- "Zfh" should be replaced with "zfh" -- "Zfhmin" should be replaced with "zfhmin" -- "Zve32f" should be replaced with "zve32f" -- "Zve64f" should be replaced with "zve64f" -- "Zve64d" should be replaced with "zve64d" - Block device options '''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 6a9944a0c7..225841bd9b 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -1038,6 +1038,13 @@ initial RISC-V QEMU port. Its usage was always been unclear: users don't know what to expect from a CPU called 'any', and in fact the CPU does not do anything special that isn't already done by the default CPUs rv32/rv64. +RISC-V CPU properties which start with capital 'Z' (removed in 10.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +All RISC-V CPU properties which start with capital 'Z' have been removed. +They were wrongly added with capital 'Z' in the past. CPU properties +with lower-case names are used instead. + Power8E and Power8NVL CPUs (removed in 11.1) '''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/system/riscv/tt_atlantis.rst b/docs/system/riscv/tt_atlantis.rst index 539c22354f..d94d064f4f 100644 --- a/docs/system/riscv/tt_atlantis.rst +++ b/docs/system/riscv/tt_atlantis.rst @@ -13,7 +13,7 @@ tt-atlantis QEMU model features * 8-core Ascalon-X CPU Cluster * RISC-V compliant Advanced Interrupt Architecture -* 16550A compatible UART +* DW8250 compatible UART x5 * 4 PRCMs (Clock and Reset Controllers) Known limitations @@ -25,9 +25,8 @@ real platform. Notably: * There is no PCI host bridge, so virtio-pci devices cannot be attached. Boots that need block storage must use ``-initrd`` with an initramfs. -* The DesignWare UART is modelled with QEMU's ns16550-compatible - ``serial_mm`` device; DesignWare-specific registers beyond that - set return 0. +* The Atlantis platform has 5 UARTs but only ``UART1`` is currently exposed + on the command line serial interface. ``UART1`` is the Ascalon console. Supported software ------------------ diff --git a/hw/dma/k230_gsdma.c b/hw/dma/k230_gsdma.c index 7635cd19e8..bd6db9e64d 100644 --- a/hw/dma/k230_gsdma.c +++ b/hw/dma/k230_gsdma.c @@ -304,54 +304,54 @@ static uint64_t k230_gsdma_read(void *opaque, hwaddr addr, unsigned int size) hwaddr ch_off; uint64_t ret = 0; - switch (addr) { - case K230_GSDMA_DMA_CH_EN: - ret = s->dma_ch_en; - break; - case K230_GSDMA_DMA_INT_MASK: - ret = s->dma_int_mask; - break; - case K230_GSDMA_DMA_INT_STAT: - ret = s->dma_int_stat; - break; - case K230_GSDMA_DMA_CFG: - ret = s->dma_cfg; - break; - case K230_GSDMA_DMA_WEIGHT: - ret = s->dma_weight; - break; - default: - if (addr < K230_GSDMA_CH_BASE) { + if (addr < K230_GSDMA_CH_BASE) { + switch (addr) { + case K230_GSDMA_DMA_CH_EN: + ret = s->dma_ch_en; + break; + case K230_GSDMA_DMA_INT_MASK: + ret = s->dma_int_mask; + break; + case K230_GSDMA_DMA_INT_STAT: + ret = s->dma_int_stat; + break; + case K230_GSDMA_DMA_CFG: + ret = s->dma_cfg; + break; + case K230_GSDMA_DMA_WEIGHT: + ret = s->dma_weight; + break; + default: qemu_log_mask(LOG_GUEST_ERROR, "%s: not implement gdma at offset 0x%" HWADDR_PRIx "\n", __func__, addr); + return ret; } - break; - } - - ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE; - ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE; - if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) { - switch (ch_off) { - case K230_GSDMA_CH_CTL: - break; - case K230_GSDMA_CH_STATUS: - ret = s->channels[ch].status; - break; - case K230_GSDMA_CH_CFG: - ret = s->channels[ch].cfg; - break; - case K230_GSDMA_CH_USR_DATA: - ret = s->channels[ch].usr_data; - break; - case K230_GSDMA_CH_LLT_SADDR: - ret = s->channels[ch].llt_saddr; - break; - case K230_GSDMA_CH_CURRENT_LLT: - ret = s->channels[ch].current_llt; - break; - default: - break; + } else { + ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE; + ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE; + if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) { + switch (ch_off) { + case K230_GSDMA_CH_CTL: + break; + case K230_GSDMA_CH_STATUS: + ret = s->channels[ch].status; + break; + case K230_GSDMA_CH_CFG: + ret = s->channels[ch].cfg; + break; + case K230_GSDMA_CH_USR_DATA: + ret = s->channels[ch].usr_data; + break; + case K230_GSDMA_CH_LLT_SADDR: + ret = s->channels[ch].llt_saddr; + break; + case K230_GSDMA_CH_CURRENT_LLT: + ret = s->channels[ch].current_llt; + break; + default: + break; + } } } diff --git a/hw/misc/k230_decomp_gzip.c b/hw/misc/k230_decomp_gzip.c index 0d8a3b2d2e..54303c0e7f 100644 --- a/hw/misc/k230_decomp_gzip.c +++ b/hw/misc/k230_decomp_gzip.c @@ -53,13 +53,13 @@ static bool k230_decomp_gzip_write_mem(K230DecompGzipState *s, hwaddr addr, static hwaddr k230_decomp_gzip_output_addr(K230DecompGzipState *s) { return K230_DECOMP_GZIP_SRAM_OUT_BASE + - s->output.slot * K230_DECOMP_GZIP_BLOCK_SIZE + + (hwaddr) s->output.slot * K230_DECOMP_GZIP_BLOCK_SIZE + s->output.current_offset; } static hwaddr k230_decomp_gzip_input_addr(K230DecompGzipState *s) { - return s->input.slot * K230_DECOMP_GZIP_BLOCK_SIZE + + return (hwaddr) s->input.slot * K230_DECOMP_GZIP_BLOCK_SIZE + K230_DECOMP_GZIP_SRAM_IN_BASE; } @@ -102,7 +102,7 @@ static void k230_decomp_gzip_finish(K230DecompGzipState *s, bool crc_ok) } static bool k230_decomp_gzip_load_input(K230DecompGzipState *s, - uint32_t addr, uint32_t size) + hwaddr addr, uint32_t size) { s->input.current_offset = 0; diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index fb05031228..d89fdfcc86 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -144,7 +144,7 @@ config TENSTORRENT select RISCV_ACLINT select RISCV_APLIC select RISCV_IMSIC - select SERIAL_MM + select DW8250 select DEVICE_TREE select DESIGNWARE_I2C select DS1338 diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index 323a041b4a..0e6970773a 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -1582,107 +1582,96 @@ static guint riscv_iommu_iot_hash(gconstpointer v) /* GV: 0 AV: 0 PSCV: 0 GVMA: 0 */ /* GV: 0 AV: 0 GVMA: 1 */ static -void riscv_iommu_iot_inval_all(gpointer key, gpointer value, gpointer data) +gboolean riscv_iommu_iot_inval_all(gpointer key, gpointer value, gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag; } /* GV: 0 AV: 0 PSCV: 1 GVMA: 0 */ static -void riscv_iommu_iot_inval_pscid(gpointer key, gpointer value, gpointer data) +gboolean riscv_iommu_iot_inval_pscid(gpointer key, gpointer value, + gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag && - iot->pscid == arg->pscid) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag && + iot->pscid == arg->pscid; } /* GV: 0 AV: 1 PSCV: 0 GVMA: 0 */ static -void riscv_iommu_iot_inval_iova(gpointer key, gpointer value, gpointer data) +gboolean riscv_iommu_iot_inval_iova(gpointer key, gpointer value, gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag && - iot->iova == arg->iova) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag && + iot->iova == arg->iova; } /* GV: 0 AV: 1 PSCV: 1 GVMA: 0 */ -static void riscv_iommu_iot_inval_pscid_iova(gpointer key, gpointer value, - gpointer data) +static gboolean riscv_iommu_iot_inval_pscid_iova(gpointer key, + gpointer value, + gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag && - iot->pscid == arg->pscid && - iot->iova == arg->iova) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag && + iot->pscid == arg->pscid && + iot->iova == arg->iova; } /* GV: 1 AV: 0 PSCV: 0 GVMA: 0 */ /* GV: 1 AV: 0 GVMA: 1 */ -static -void riscv_iommu_iot_inval_gscid(gpointer key, gpointer value, gpointer data) +static gboolean riscv_iommu_iot_inval_gscid(gpointer key, gpointer value, + gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag && - iot->gscid == arg->gscid) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag && + iot->gscid == arg->gscid; } /* GV: 1 AV: 0 PSCV: 1 GVMA: 0 */ -static void riscv_iommu_iot_inval_gscid_pscid(gpointer key, gpointer value, - gpointer data) +static gboolean riscv_iommu_iot_inval_gscid_pscid(gpointer key, + gpointer value, + gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag && - iot->gscid == arg->gscid && - iot->pscid == arg->pscid) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag && + iot->gscid == arg->gscid && + iot->pscid == arg->pscid; } /* GV: 1 AV: 1 PSCV: 0 GVMA: 0 */ /* GV: 1 AV: 1 GVMA: 1 */ -static void riscv_iommu_iot_inval_gscid_iova(gpointer key, gpointer value, - gpointer data) +static gboolean riscv_iommu_iot_inval_gscid_iova(gpointer key, + gpointer value, + gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag && - iot->gscid == arg->gscid && - iot->iova == arg->iova) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag && + iot->gscid == arg->gscid && + iot->iova == arg->iova; } /* GV: 1 AV: 1 PSCV: 1 GVMA: 0 */ -static void riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key, gpointer value, - gpointer data) +static gboolean riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key, + gpointer value, + gpointer data) { RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; - if (iot->tag == arg->tag && - iot->gscid == arg->gscid && - iot->pscid == arg->pscid && - iot->iova == arg->iova) { - iot->perm = IOMMU_NONE; - } + return iot->tag == arg->tag && + iot->gscid == arg->gscid && + iot->pscid == arg->pscid && + iot->iova == arg->iova; } -/* caller should keep ref-count for iot_cache object */ +/* caller must hold iot_lock */ static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext *ctx, GHashTable *iot_cache, hwaddr iova, RISCVIOMMUTransTag transtag) { @@ -1695,27 +1684,26 @@ static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext *ctx, return g_hash_table_lookup(iot_cache, &key); } -/* caller should keep ref-count for iot_cache object */ -static void riscv_iommu_iot_update(RISCVIOMMUState *s, - GHashTable *iot_cache, RISCVIOMMUEntry *iot) +/* caller must hold iot_lock */ +static void riscv_iommu_iot_update(RISCVIOMMUState *s, RISCVIOMMUEntry *iot) { if (!s->iot_limit) { return; } if (g_hash_table_size(s->iot_cache) >= s->iot_limit) { - iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash, - riscv_iommu_iot_equal, - g_free, NULL); - g_hash_table_unref(qatomic_xchg(&s->iot_cache, iot_cache)); + GHashTable *old_cache = s->iot_cache; + s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash, + riscv_iommu_iot_equal, + g_free, NULL); + g_hash_table_unref(old_cache); } - g_hash_table_add(iot_cache, iot); + g_hash_table_add(s->iot_cache, iot); } -static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func, +static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHRFunc func, uint32_t gscid, uint32_t pscid, hwaddr iova, RISCVIOMMUTransTag transtag) { - GHashTable *iot_cache; RISCVIOMMUEntry key = { .tag = transtag, .gscid = gscid, @@ -1723,9 +1711,9 @@ static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func, .iova = PPN_DOWN(iova), }; - iot_cache = g_hash_table_ref(s->iot_cache); - g_hash_table_foreach(iot_cache, func, &key); - g_hash_table_unref(iot_cache); + qemu_mutex_lock(&s->iot_lock); + g_hash_table_foreach_remove(s->iot_cache, func, &key); + qemu_mutex_unlock(&s->iot_lock); } static RISCVIOMMUTransTag riscv_iommu_get_transtag(RISCVIOMMUContext *ctx) @@ -1747,15 +1735,14 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, { RISCVIOMMUTransTag transtag = riscv_iommu_get_transtag(ctx); RISCVIOMMUEntry *iot; - IOMMUAccessFlags perm; + IOMMUAccessFlags perm = IOMMU_NONE; bool enable_pid; bool enable_pri; - GHashTable *iot_cache; + hwaddr phys = 0; int fault; riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_URQ); - iot_cache = g_hash_table_ref(s->iot_cache); enable_pri = (iotlb->perm == IOMMU_NONE) && (ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI); enable_pid = (ctx->tc & RISCV_IOMMU_DC_TC_PDTV); @@ -1771,10 +1758,15 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, } } - iot = riscv_iommu_iot_lookup(ctx, iot_cache, iotlb->iova, transtag); - perm = iot ? iot->perm : IOMMU_NONE; + qemu_mutex_lock(&s->iot_lock); + iot = riscv_iommu_iot_lookup(ctx, s->iot_cache, iotlb->iova, transtag); + if (iot) { + perm = iot->perm; + phys = iot->phys; + } + qemu_mutex_unlock(&s->iot_lock); if (perm != IOMMU_NONE) { - iotlb->translated_addr = PPN_PHYS(iot->phys); + iotlb->translated_addr = PPN_PHYS(phys); iotlb->addr_mask = ~TARGET_PAGE_MASK; iotlb->perm = perm; fault = 0; @@ -1805,12 +1797,12 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, iot->pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID); iot->perm = iotlb->perm; iot->tag = transtag; - riscv_iommu_iot_update(s, iot_cache, iot); + qemu_mutex_lock(&s->iot_lock); + riscv_iommu_iot_update(s, iot); + qemu_mutex_unlock(&s->iot_lock); } done: - g_hash_table_unref(iot_cache); - if (enable_pri && fault) { struct riscv_iommu_pq_record pr = {0}; if (enable_pid) { @@ -1969,7 +1961,8 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s) dma_addr_t addr; uint32_t tail, head, ctrl; uint64_t cmd_opcode; - GHFunc func; + GHRFunc iot_func; + GHFunc ctx_func; ctrl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR); tail = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQT) & s->cq_mask; @@ -2032,18 +2025,18 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s) goto cmd_ill; } - func = riscv_iommu_iot_inval_all; + iot_func = riscv_iommu_iot_inval_all; if (gv) { - func = (av) ? riscv_iommu_iot_inval_gscid_iova : + iot_func = (av) ? riscv_iommu_iot_inval_gscid_iova : riscv_iommu_iot_inval_gscid; } riscv_iommu_iot_inval( - s, func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VG); + s, iot_func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VG); riscv_iommu_iot_inval( - s, func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VN); + s, iot_func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VN); break; } @@ -2063,24 +2056,24 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s) if (gv) { transtag = RISCV_IOMMU_TRANS_TAG_VN; if (pscv) { - func = (av) ? riscv_iommu_iot_inval_gscid_pscid_iova : + iot_func = (av) ? riscv_iommu_iot_inval_gscid_pscid_iova : riscv_iommu_iot_inval_gscid_pscid; } else { - func = (av) ? riscv_iommu_iot_inval_gscid_iova : + iot_func = (av) ? riscv_iommu_iot_inval_gscid_iova : riscv_iommu_iot_inval_gscid; } } else { transtag = RISCV_IOMMU_TRANS_TAG_SS; if (pscv) { - func = (av) ? riscv_iommu_iot_inval_pscid_iova : + iot_func = (av) ? riscv_iommu_iot_inval_pscid_iova : riscv_iommu_iot_inval_pscid; } else { - func = (av) ? riscv_iommu_iot_inval_iova : + iot_func = (av) ? riscv_iommu_iot_inval_iova : riscv_iommu_iot_inval_all; } } - riscv_iommu_iot_inval(s, func, gscid, pscid, iova, transtag); + riscv_iommu_iot_inval(s, iot_func, gscid, pscid, iova, transtag); break; } @@ -2088,12 +2081,12 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s) RISCV_IOMMU_CMD_IODIR_OPCODE): if (!(cmd.dword0 & RISCV_IOMMU_CMD_IODIR_DV)) { /* invalidate all device context cache mappings */ - func = riscv_iommu_ctx_inval_all; + ctx_func = riscv_iommu_ctx_inval_all; } else { /* invalidate all device context matching DID */ - func = riscv_iommu_ctx_inval_devid; + ctx_func = riscv_iommu_ctx_inval_devid; } - riscv_iommu_ctx_inval(s, func, + riscv_iommu_ctx_inval(s, ctx_func, get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID), 0); break; @@ -2103,9 +2096,9 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s) /* illegal command arguments IODIR_PDT & DV == 0 */ goto cmd_ill; } else { - func = riscv_iommu_ctx_inval_devid_procid; + ctx_func = riscv_iommu_ctx_inval_devid_procid; } - riscv_iommu_ctx_inval(s, func, + riscv_iommu_ctx_inval(s, ctx_func, get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID), get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_PID)); break; @@ -2281,8 +2274,20 @@ static void riscv_iommu_process_dbg(RISCVIOMMUState *s) if (fault) { iova = RISCV_IOMMU_TR_RESPONSE_FAULT | (((uint64_t) fault) << 10); } else { + uint64_t ppn; + iova = iotlb.translated_addr & ~iotlb.addr_mask; - iova = set_field(0, RISCV_IOMMU_TR_RESPONSE_PPN, PPN_DOWN(iova)); + ppn = PPN_DOWN(iova); + + if (iotlb.addr_mask > TARGET_PAGE_SIZE - 1) { + /* Encode the translation range as trailing ones in the PPN. */ + ppn |= PPN_DOWN(iotlb.addr_mask) >> 1; + iova = RISCV_IOMMU_TR_RESPONSE_S; + } else { + iova = 0; + } + + iova = set_field(iova, RISCV_IOMMU_TR_RESPONSE_PPN, ppn); } riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_TR_RESPONSE, iova); } @@ -2674,6 +2679,7 @@ static void riscv_iommu_instance_init(Object *obj) s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash, riscv_iommu_iot_equal, g_free, NULL); + qemu_mutex_init(&s->iot_lock); s->iommus.le_next = NULL; s->iommus.le_prev = NULL; @@ -2690,6 +2696,8 @@ static void riscv_iommu_instance_finalize(Object *obj) g_hash_table_unref(s->ctx_cache); g_hash_table_unref(s->iot_cache); + + qemu_mutex_destroy(&s->iot_lock); } static void riscv_iommu_realize(DeviceState *dev, Error **errp) @@ -2850,7 +2858,10 @@ void riscv_iommu_reset(RISCVIOMMUState *s) riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_IPSR, 0); g_hash_table_remove_all(s->ctx_cache); + + qemu_mutex_lock(&s->iot_lock); g_hash_table_remove_all(s->iot_cache); + qemu_mutex_unlock(&s->iot_lock); } static const Property riscv_iommu_properties[] = { @@ -2919,7 +2930,8 @@ static IOMMUTLBEntry riscv_iommu_memory_region_translate( /* Translation disabled or invalid. */ iotlb.addr_mask = 0; iotlb.perm = IOMMU_NONE; - } else if (riscv_iommu_translate(as->iommu, ctx, &iotlb, true)) { + } else if (riscv_iommu_translate(as->iommu, ctx, &iotlb, + as->iommu->iot_limit > 0)) { /* Translation disabled or fault reported. */ iotlb.addr_mask = 0; iotlb.perm = IOMMU_NONE; diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h index 7c470ba084..403d10b321 100644 --- a/hw/riscv/riscv-iommu.h +++ b/hw/riscv/riscv-iommu.h @@ -73,6 +73,7 @@ struct RISCVIOMMUState { GHashTable *iot_cache; /* IO Translated Address Cache */ unsigned iot_limit; /* IO Translation Cache size limit */ + QemuMutex iot_lock; /* MMIO Hardware Interface */ MemoryRegion regs_mr; diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c index 4e6c39982c..311de64eda 100644 --- a/hw/riscv/tt_atlantis.c +++ b/hw/riscv/tt_atlantis.c @@ -24,9 +24,8 @@ #include "hw/riscv/fdt-common.h" #include "hw/riscv/riscv_hart.h" -#include "hw/char/serial-mm.h" +#include "hw/char/dw8250.h" #include "hw/intc/riscv_aclint.h" -#include "hw/misc/unimp.h" #include "hw/misc/tt_atlantis_prcm.h" #include "system/system.h" @@ -65,7 +64,11 @@ static const MemMapEntry tt_atlantis_memmap[] = { [TT_ATL_I2C2] = { 0xd4060000, 0x10000 }, [TT_ATL_I2C3] = { 0xd4070000, 0x10000 }, [TT_ATL_I2C4] = { 0xd4080000, 0x10000 }, + [TT_ATL_UART0] = { 0xd4100000, 0x10000 }, [TT_ATL_UART1] = { 0xd4110000, 0x10000 }, + [TT_ATL_UART2] = { 0xd4120000, 0x10000 }, + [TT_ATL_UART3] = { 0xd4130000, 0x10000 }, + [TT_ATL_UART4] = { 0xd4140000, 0x10000 }, [TT_ATL_PRCM_PCIE] = { 0xd8000000, 0x100 }, [TT_ATL_PRCM_MM] = { 0xdc000000, 0x1000 }, [TT_ATL_PRCM_HSIO] = { 0xe00c0000, 0x510 }, @@ -268,11 +271,15 @@ static void create_fdt_uart(void *fdt, const MemMapEntry *mem, int irq, int irqchip_phandle, uint32_t clk_parent_phandle, uint32_t clk_phandle) { + static const char * const compat[2] = { + "snps,dw-apb-uart", "ns16550a" + }; g_autofree char *name = g_strdup_printf("/soc/serial@%"HWADDR_PRIX, mem->base); qemu_fdt_add_subnode(fdt, name); - qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a"); + qemu_fdt_setprop_string_array(fdt, name, "compatible", + (char **)&compat, ARRAY_SIZE(compat)); qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size); qemu_fdt_setprop_cell(fdt, name, "reg-shift", 2); qemu_fdt_setprop_cell(fdt, name, "reg-io-width", 4); @@ -466,17 +473,6 @@ static void load_fdt(TTAtlantisState *ams) create_fdt_memory(ms->fdt, &ams->soc); } -static void mmio_map_unimplemented(MemoryRegion *memory, SysBusDevice *dev, - const char *name, hwaddr addr, uint64_t size) -{ - qdev_prop_set_string(DEVICE(dev), "name", name); - qdev_prop_set_uint64(DEVICE(dev), "size", size); - sysbus_realize(dev, &error_abort); - - memory_region_add_subregion_overlap(memory, addr, - sysbus_mmio_get_region(dev, 0), -1000); -} - static void tt_atlantis_machine_done(Notifier *n, void *data) { TTAtlantisState *ams = container_of(n, TTAtlantisState, machine_done); @@ -539,14 +535,21 @@ static void tt_atlantis_machine_done(Notifier *n, void *data) fdt_load_addr); } +static inline int tt_atlantis_uart_index(int uart_dev) +{ + return uart_dev - TT_ATL_UART0; +} + static void tt_atlantis_soc_init(Object *obj) { TTAtlantisSoCState *s = TT_ATLANTIS_SOC(obj); object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); - object_initialize_child(obj, "uart1", &s->uart1, - TYPE_UNIMPLEMENTED_DEVICE); + for (int i = 0; i < TT_ATL_NUM_UARTS; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], + TYPE_DW8250); + } object_initialize_child(obj, "prcm-rcpu", &s->prcm[TT_ATLANTIS_PRCM_DOMAIN_RCPU], @@ -653,11 +656,6 @@ static void tt_atlantis_soc_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(s->memory, s->memmap[TT_ATL_BOOTROM].base, &s->bootrom); - /* UART1, the soc console (UART0 is for the boot microcontroller) */ - serial_mm_init(s->memory, s->memmap[TT_ATL_UART1].base, 2, - qdev_get_gpio_in(s->irqchip, TT_ATL_UART1_IRQ), - 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); - /* 4 PRCM blocks */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_RCPU]), errp)) { @@ -695,18 +693,22 @@ static void tt_atlantis_soc_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region( SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_MM]), 0)); - /* - * Atlantis contains a DesignWare uart while the QEMU machine - * uses the serial_mm model with the base ns16550 register set. - * Linux's dw driver writes outside of serial_mm's 0x20 sized - * mapping and faults. - * - * Create an unimplemented device region so writes don't fault - * and reads return zero, which keeps Linux happy. - */ - mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->uart1), - "tt-atlantis.uart1", s->memmap[TT_ATL_UART1].base, - s->memmap[TT_ATL_UART1].size); + /* UART1, the soc console (UART0 is for the boot microcontroller) */ + qdev_prop_set_chr(DEVICE(&s->uart[tt_atlantis_uart_index(TT_ATL_UART1)]), + "chardev", serial_hd(0)); + + for (int i = 0; i < TT_ATL_NUM_UARTS; i++) { + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->uart[i]); + if (!sysbus_realize(sbd, errp)) { + return; + } + + memory_region_add_subregion(s->memory, + s->memmap[TT_ATL_UART0 + i].base, + sysbus_mmio_get_region(sbd, 0)); + sysbus_connect_irq(sbd, 0, + qdev_get_gpio_in(s->irqchip, TT_ATL_UART0_IRQ + i)); + } /* I2C */ for (int i = 0; i < TT_ATL_NUM_I2C; i++) { diff --git a/include/hw/intc/riscv_imsic.h b/include/hw/intc/riscv_imsic.h index 0a1df1c2f8..c744836657 100644 --- a/include/hw/intc/riscv_imsic.h +++ b/include/hw/intc/riscv_imsic.h @@ -31,7 +31,6 @@ DECLARE_INSTANCE_CHECKER(RISCVIMSICState, RISCV_IMSIC, TYPE_RISCV_IMSIC) #define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT) #define IMSIC_MMIO_SIZE(__num_pages) ((__num_pages) * IMSIC_MMIO_PAGE_SZ) -#define IMSIC_MMIO_HART_GUEST_MAX_BTIS 6 #define IMSIC_MMIO_GROUP_MIN_SHIFT 24 #define IMSIC_HART_NUM_GUESTS(__guest_bits) \ diff --git a/include/hw/riscv/tt_atlantis.h b/include/hw/riscv/tt_atlantis.h index 577c867d71..f965bf23fc 100644 --- a/include/hw/riscv/tt_atlantis.h +++ b/include/hw/riscv/tt_atlantis.h @@ -13,8 +13,8 @@ #include "hw/core/sysbus.h" #include "hw/i2c/designware_i2c.h" #include "hw/intc/riscv_imsic.h" -#include "hw/misc/unimp.h" #include "hw/misc/tt_atlantis_prcm.h" +#include "hw/char/dw8250.h" #include "hw/riscv/riscv_hart.h" #define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis") @@ -25,6 +25,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisSoCState, TT_ATLANTIS_SOC) #define TT_ATL_NUM_I2C 5 #define TT_ATL_NUM_PRCM 4 +#define TT_ATL_NUM_UARTS 5 struct TTAtlantisSoCState { /*< private >*/ @@ -41,7 +42,7 @@ struct TTAtlantisSoCState { RISCVHartArrayState cpus; DeviceState *irqchip; DesignWareI2CState i2c[TT_ATL_NUM_I2C]; - UnimplementedDeviceState uart1; + DW8250State uart[TT_ATL_NUM_UARTS]; MemoryRegion bootrom; TTAtlantisPRCMState prcm[TT_ATL_NUM_PRCM]; @@ -66,7 +67,11 @@ enum { TT_ATL_I2C2_IRQ = 35, TT_ATL_I2C3_IRQ = 36, TT_ATL_I2C4_IRQ = 37, + TT_ATL_UART0_IRQ = 38, TT_ATL_UART1_IRQ = 39, + TT_ATL_UART2_IRQ = 40, + TT_ATL_UART3_IRQ = 41, + TT_ATL_UART4_IRQ = 42, }; enum { @@ -83,7 +88,11 @@ enum { TT_ATL_MIMSIC, TT_ATL_SAPLIC, TT_ATL_SIMSIC, + TT_ATL_UART0, TT_ATL_UART1, + TT_ATL_UART2, + TT_ATL_UART3, + TT_ATL_UART4, TT_ATL_PRCM_RCPU, TT_ATL_PRCM_HSIO, TT_ATL_PRCM_PCIE, diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ae750f85c6..5a0529fbda 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -222,6 +222,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zksh, PRIV_VERSION_1_12_0, ext_zksh), ISA_EXT_DATA_ENTRY(zkt, PRIV_VERSION_1_12_0, ext_zkt), ISA_EXT_DATA_ENTRY(ztso, PRIV_VERSION_1_12_0, ext_ztso), + ISA_EXPERIMENTAL_EXT_DATA_ENTRY(zvabd, PRIV_VERSION_1_13_0, ext_zvabd), ISA_EXT_DATA_ENTRY(zvbb, PRIV_VERSION_1_12_0, ext_zvbb), ISA_EXT_DATA_ENTRY(zvbc, PRIV_VERSION_1_12_0, ext_zvbc), ISA_EXT_DATA_ENTRY(zve32f, PRIV_VERSION_1_10_0, ext_zve32f), @@ -1549,6 +1550,25 @@ static void riscv_cpu_init(Object *obj) cpu->env.vext_ver = VEXT_VERSION_1_00_0; cpu->cfg.max_satp_mode = -1; + /* + * The way we're handling profiles does not cope well with QMP + * instropection. We have a static array that stores RISCVCPUProfiles + * objs that hold runtime state for the lifetime of the QEMU process. + * Thus setting profile->enabled once, e.g. when instropecting a + * profile CPU, will leave the flag set for subsequent intropections. + * + * For now, clear all 'enabled' flags to avoid misleading QMP w.r.t + * profiles being set. + * + * FIXME: a better long term solution is to remove profile->enabled + * and just use regular cpu->cfg flags, avoiding static variables + * storing dynamic state. This will help us not only with QMP but + * also single-binary support. + */ + for (int i = 0; riscv_profiles[i] != NULL; i++) { + riscv_profiles[i]->enabled = false; + } + if (mcc->def->profile) { mcc->def->profile->enabled = true; } @@ -2297,7 +2317,7 @@ static void prop_marchid_set(Object *obj, Visitor *v, const char *name, g_assert_not_reached(); } - invalid_val = 1LL << (mxlen - 1); + invalid_val = 1ULL << (mxlen - 1); if (value == invalid_val) { error_setg(errp, "Unable to set marchid with MSB (%u) bit set " diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index bcff8f55f1..85fc3ad8bb 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -83,6 +83,7 @@ BOOL_FIELD(ext_zve32x) BOOL_FIELD(ext_zve64f) BOOL_FIELD(ext_zve64d) BOOL_FIELD(ext_zve64x) +BOOL_FIELD(ext_zvabd) BOOL_FIELD(ext_zvbb) BOOL_FIELD(ext_zvbc) BOOL_FIELD(ext_zvkb) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 372f104972..1cffcad580 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1353,6 +1353,32 @@ DEF_HELPER_5(vsm4k_vi, void, ptr, ptr, i32, env, i32) DEF_HELPER_4(vsm4r_vv, void, ptr, ptr, env, i32) DEF_HELPER_4(vsm4r_vs, void, ptr, ptr, env, i32) +/* Zvabd Extension */ +DEF_HELPER_6(vabd_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabd_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vabd_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vabd_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vabd_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vabdu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabdu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabdu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabdu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vabdu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vabdu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vabdu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vabdu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwabda_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwabda_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwabda_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwabda_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwabdau_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwabdau_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwabdau_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwabdau_vx_h, void, ptr, ptr, tl, ptr, env, i32) + /* CFI (zicfiss) helpers */ #ifndef CONFIG_USER_ONLY DEF_HELPER_1(ssamoswap_disabled, void, env) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 46b00411ff..795badc8a7 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -1087,3 +1087,13 @@ sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st + +# *** Zvabd Extension *** +vabd_vv 010101 . ..... ..... 010 ..... 1010111 @r_vm +vabd_vx 010101 . ..... ..... 110 ..... 1010111 @r_vm +vabdu_vv 010110 . ..... ..... 010 ..... 1010111 @r_vm +vabdu_vx 010110 . ..... ..... 110 ..... 1010111 @r_vm +vwabda_vv 111101 . ..... ..... 000 ..... 1010111 @r_vm +vwabda_vx 111101 . ..... ..... 100 ..... 1010111 @r_vm +vwabdau_vv 111110 . ..... ..... 000 ..... 1010111 @r_vm +vwabdau_vx 111110 . ..... ..... 100 ..... 1010111 @r_vm diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index f28d9115c8..5a82a63b82 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -58,6 +58,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level) } static bool cap_has_mp_state; +static bool mp_state_reset; #define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \ type | idx) @@ -1444,10 +1445,31 @@ static int kvm_riscv_put_mp_state(CPUState *cs) return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); } +static int kvm_riscv_mp_state_init_received(CPUState *cs) +{ + struct kvm_mp_state mp_state = { + .mp_state = KVM_MP_STATE_INIT_RECEIVED, + }; + + if (!cap_has_mp_state || !mp_state_reset) { + return 0; + } + + /* Let KVM resets the VCPU, The original MP_STATE is preserved*/ + return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); +} + int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { int ret = 0; + if (KVM_PUT_RESET_STATE == level) { + ret = kvm_riscv_mp_state_init_received(cs); + if (ret) { + return ret; + } + } + ret = kvm_riscv_put_regs_core(cs); if (ret) { return ret; @@ -1624,6 +1646,11 @@ int kvm_arch_get_default_type(MachineState *ms) int kvm_arch_init(MachineState *ms, KVMState *s) { cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); + + if (cap_has_mp_state) { + mp_state_reset = !kvm_vm_enable_cap(s, KVM_CAP_RISCV_MP_STATE_RESET, 0); + } + return 0; } diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 063590f56a..af444e3e6f 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -2108,6 +2108,9 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, } if (xl != MXL_RV32 || env->debugger) { + if (riscv_has_ext(env, RVH)) { + mask |= MSTATUS_MPV | MSTATUS_GVA; + } if ((val & MSTATUS64_SXL) != 0) { mask |= MSTATUS64_SXL; val = riscv_write_uxl(env, val, MSTATUS64_SXL); @@ -2150,7 +2153,7 @@ static RISCVException write_mstatush(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { uint64_t valh = (uint64_t)val << 32; - uint64_t mask = 0; + uint64_t mask = riscv_has_ext(env, RVH) ? MSTATUS_MPV | MSTATUS_GVA : 0; if (riscv_cpu_cfg(env)->ext_smdbltrp) { mask |= MSTATUS_MDT; @@ -3388,10 +3391,19 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); - uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | - MENVCFG_CBZE; + uint64_t mask = MENVCFG_FIOM; bool stce_changed = false; + /* CBIE/CBCFE are read-only zero when Zicbom is not implemented. */ + if (cfg->ext_zicbom) { + mask |= MENVCFG_CBIE | MENVCFG_CBCFE; + } + + /* CBZE is read-only zero when Zicboz is not implemented. */ + if (cfg->ext_zicboz) { + mask |= MENVCFG_CBZE; + } + /* * menvcfg.LPE (Zicfilp) and menvcfg.SSE (Zicfiss) reside in the low * 32 bits and are defined for both RV32 and RV64, so they must be @@ -3492,8 +3504,18 @@ static RISCVException read_senvcfg(CPURISCVState *env, int csrno, static RISCVException write_senvcfg(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE; + uint64_t mask = SENVCFG_FIOM; RISCVException ret; + + /* CBIE/CBCFE are read-only zero when Zicbom is not implemented. */ + if (env_archcpu(env)->cfg.ext_zicbom) { + mask |= SENVCFG_CBIE | SENVCFG_CBCFE; + } + + /* CBZE is read-only zero when Zicboz is not implemented. */ + if (env_archcpu(env)->cfg.ext_zicboz) { + mask |= SENVCFG_CBZE; + } /* Update PMM field only if the value is valid according to Zjpm v1.0 */ if (env_archcpu(env)->cfg.ext_ssnpm && riscv_cpu_mxl(env) == MXL_RV64 && @@ -3550,10 +3572,20 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); - uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; + uint64_t mask = HENVCFG_FIOM; RISCVException ret; bool stce_changed = false; + /* CBIE/CBCFE are read-only zero when Zicbom is not implemented. */ + if (cfg->ext_zicbom) { + mask |= HENVCFG_CBIE | HENVCFG_CBCFE; + } + + /* CBZE is read-only zero when Zicboz is not implemented. */ + if (cfg->ext_zicboz) { + mask |= HENVCFG_CBZE; + } + ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); if (ret != RISCV_EXCP_NONE) { return ret; @@ -5484,14 +5516,14 @@ static RISCVException write_vsscratch(CPURISCVState *env, int csrno, static RISCVException read_vsepc(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->vsepc; + *val = env->vsepc & get_xepc_mask(env); return RISCV_EXCP_NONE; } static RISCVException write_vsepc(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - env->vsepc = val; + env->vsepc = val & get_xepc_mask(env); return RISCV_EXCP_NONE; } @@ -5766,6 +5798,10 @@ static RISCVException write_mnstatus(CPURISCVState *env, int csrno, mask |= MNSTATUS_MNPV; } + if (env_archcpu(env)->cfg.ext_zicfilp) { + mask |= MNSTATUS_MNPELP; + } + /* mnstatus.mnie can only be cleared by hardware. */ env->mnstatus = (env->mnstatus & MNSTATUS_NMIE) | (val & mask); return RISCV_EXCP_NONE; diff --git a/target/riscv/tcg/insn_trans/trans_rvi.c.inc b/target/riscv/tcg/insn_trans/trans_rvi.c.inc index cc1b5dbbad..4784ea1607 100644 --- a/target/riscv/tcg/insn_trans/trans_rvi.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvi.c.inc @@ -424,7 +424,7 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) } if (ctx->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + tcg_gen_mb(TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_BAR_LDAQ); } return out; @@ -485,7 +485,7 @@ static bool gen_store_tl(DisasContext *ctx, arg_sb *a, MemOp memop) TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); if (ctx->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + tcg_gen_mb(TCG_MO_LD_ST | TCG_MO_ST_ST | TCG_BAR_STRL); } tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); diff --git a/target/riscv/tcg/insn_trans/trans_rvv.c.inc b/target/riscv/tcg/insn_trans/trans_rvv.c.inc index a22e2cae6c..7e1295f33e 100644 --- a/target/riscv/tcg/insn_trans/trans_rvv.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvv.c.inc @@ -731,7 +731,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, * around the loop. */ if (is_store && s->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + tcg_gen_mb(TCG_MO_LD_ST | TCG_MO_ST_ST | TCG_BAR_STRL); } mark_vs_dirty(s); @@ -739,7 +739,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, fn(dest, mask, base, tcg_env, desc); if (!is_store && s->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + tcg_gen_mb(TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_BAR_LDAQ); } finalize_rvv_inst(s); @@ -4091,3 +4091,48 @@ GEN_INT_EXT_TRANS(vzext_vf8, 3, 2) GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) + +/* Zvabd Extension */ +#define GEN_ABD_CHECK(NAME, CHECK_FN, MAX_SEW) \ +static bool NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + return CHECK_FN(s, a) && s->cfg_ptr->ext_zvabd && \ + s->sew <= MAX_SEW && \ + (s->sew != MO_64 || s->cfg_ptr->ext_zve64x); \ +} +GEN_ABD_CHECK(vabd_vv_check, opivv_check, MO_64) +GEN_ABD_CHECK(vabd_vx_check, opivx_check, MO_64) +GEN_ABD_CHECK(vwabd_vv_check, opivv_overwrite_widen_check, MO_16) +GEN_ABD_CHECK(vwabd_vx_check, opivx_overwrite_widen_check, MO_16) + +GEN_OPIVV_TRANS(vabd_vv, vabd_vv_check) +GEN_OPIVX_TRANS(vabd_vx, vabd_vx_check) +GEN_OPIVV_TRANS(vabdu_vv, vabd_vv_check) +GEN_OPIVX_TRANS(vabdu_vx, vabd_vx_check) + +#define GEN_ABD_OPIVV_WIDEN_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_gvec_4_ptr * const fns[2] = { \ + gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ + }; \ + return s->sew <= MO_16 && do_opivv_widen(s, a, fns[s->sew], CHECK); \ +} + +#define GEN_ABD_OPIVX_WIDEN_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (CHECK(s, a)) { \ + static gen_helper_opivx * const fns[2] = { \ + gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ + }; \ + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, \ + fns[s->sew], s); \ + } \ + return false; \ +} + +GEN_ABD_OPIVV_WIDEN_TRANS(vwabda_vv, vwabd_vv_check) +GEN_ABD_OPIVX_WIDEN_TRANS(vwabda_vx, vwabd_vx_check) +GEN_ABD_OPIVV_WIDEN_TRANS(vwabdau_vv, vwabd_vv_check) +GEN_ABD_OPIVX_WIDEN_TRANS(vwabdau_vx, vwabd_vx_check) diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c index 41b55519a8..04df53c234 100644 --- a/target/riscv/tcg/pmp.c +++ b/target/riscv/tcg/pmp.c @@ -201,12 +201,20 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) void pmp_unlock_entries(CPURISCVState *env) { - uint32_t pmp_num = pmp_get_num_rules(env); + uint32_t pmp_num = riscv_cpu_cfg(env)->pmp_regions; int i; for (i = 0; i < pmp_num; i++) { env->pmp_state.pmp[i].cfg_reg &= ~(PMP_LOCK | PMP_AMATCH); } + + /* + * addr[] and num_rules are derived from the pmpaddr and pmpcfg write + * paths and are not recomputed at reset. Clear them here so they + * cannot disagree with the architectural fields cleared above. + */ + memset(env->pmp_state.addr, 0, sizeof(env->pmp_state.addr)); + env->pmp_state.num_rules = 0; } static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea) diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 1a4658319b..0165faf06b 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -355,7 +355,8 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, CPURISCVState *env = &cpu->env; PMUCTRState *counter; int64_t irq_trigger_at; - uint64_t curr_ctr_val, curr_ctrh_val; + target_ulong ctr_lo = 0, ctr_hi = 0; + uint64_t curr_ctr_val; uint64_t ctr_val; if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES && @@ -383,12 +384,19 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, return; } - riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx); - ctr_val = counter->mhpmcounter_val; + /* + * riscv_pmu_read_ctr() stores a target_ulong, so on RV32 each call fills + * only 32 bits. Read each half into its own target_ulong and build the + * 64 bit value explicitly instead of passing a cast uint64_t pointer, + * which would leave the upper half uninitialised. + */ + riscv_pmu_read_ctr(env, &ctr_lo, false, ctr_idx); + curr_ctr_val = ctr_lo; if (riscv_cpu_mxl(env) == MXL_RV32) { - riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx); - curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32); + riscv_pmu_read_ctr(env, &ctr_hi, true, ctr_idx); + curr_ctr_val |= (uint64_t)ctr_hi << 32; } + ctr_val = counter->mhpmcounter_val; /* * We can not accommodate for inhibited modes when setting up timer. Check diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index cbff18afb5..2a7796c382 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -760,6 +760,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) return; } + if ((cpu->cfg.ext_zvabd) && !cpu->cfg.ext_zve32x) { + error_setg(errp, + "Zvabd extensions require V or Zve* extensions"); + return; + } + if (cpu->cfg.ext_zicntr && !cpu->cfg.ext_zicsr) { if (cpu_cfg_ext_is_user_set(cpu, CPU_CFG_OFFSET(ext_zicntr))) { error_setg(errp, "zicntr requires zicsr"); diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c index ede9c2563f..79b0f444ef 100644 --- a/target/riscv/tcg/translate.c +++ b/target/riscv/tcg/translate.c @@ -693,7 +693,7 @@ static TCGv get_address_indexed(DisasContext *ctx, int rs1, TCGv offs) */ static void mark_fs_dirty(DisasContext *ctx) { - TCGv tmp; + TCGv_i64 tmp; if (!has_ext(ctx, RVF)) { return; @@ -703,15 +703,15 @@ static void mark_fs_dirty(DisasContext *ctx) /* Remember the state change for the rest of the TB. */ ctx->mstatus_fs = EXT_STATUS_DIRTY; - tmp = tcg_temp_new(); - tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); - tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); + tmp = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); + tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); if (ctx->virt_enabled) { - tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); - tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); } } } @@ -726,21 +726,21 @@ static inline void mark_fs_dirty(DisasContext *ctx) { } */ static void mark_vs_dirty(DisasContext *ctx) { - TCGv tmp; + TCGv_i64 tmp; if (ctx->mstatus_vs != EXT_STATUS_DIRTY) { /* Remember the state change for the rest of the TB. */ ctx->mstatus_vs = EXT_STATUS_DIRTY; - tmp = tcg_temp_new(); - tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); - tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); + tmp = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); + tcg_gen_ori_i64(tmp, tmp, MSTATUS_VS); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); if (ctx->virt_enabled) { - tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); - tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ori_i64(tmp, tmp, MSTATUS_VS); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); } } } diff --git a/target/riscv/tcg/vector_helper.c b/target/riscv/tcg/vector_helper.c index 0d1e4e0964..917a48b510 100644 --- a/target/riscv/tcg/vector_helper.c +++ b/target/riscv/tcg/vector_helper.c @@ -5911,3 +5911,59 @@ GEN_VEXT_INT_EXT(vsext_vf2_d, int64_t, int32_t, H8, H4) GEN_VEXT_INT_EXT(vsext_vf4_w, int32_t, int8_t, H4, H1) GEN_VEXT_INT_EXT(vsext_vf4_d, int64_t, int16_t, H8, H2) GEN_VEXT_INT_EXT(vsext_vf8_d, int64_t, int8_t, H8, H1) + +/* Zvabd Extension */ +#define DO_ABD(N, M) (N > M ? N - M : M - N) +#define DO_ABDACC(N, M, D) (DO_ABD(N, M) + D) + +RVVCALL(OPIVV2, vabd_vv_b, OP_SSS_B, H1, H1, H1, DO_ABD) +RVVCALL(OPIVV2, vabd_vv_h, OP_SSS_H, H2, H2, H2, DO_ABD) +RVVCALL(OPIVV2, vabd_vv_w, OP_SSS_W, H4, H4, H4, DO_ABD) +RVVCALL(OPIVV2, vabd_vv_d, OP_SSS_D, H8, H8, H8, DO_ABD) +RVVCALL(OPIVX2, vabd_vx_b, OP_SSS_B, H1, H1, DO_ABD) +RVVCALL(OPIVX2, vabd_vx_h, OP_SSS_H, H2, H2, DO_ABD) +RVVCALL(OPIVX2, vabd_vx_w, OP_SSS_W, H4, H4, DO_ABD) +RVVCALL(OPIVX2, vabd_vx_d, OP_SSS_D, H8, H8, DO_ABD) +RVVCALL(OPIVV2, vabdu_vv_b, OP_UUU_B, H1, H1, H1, DO_ABD) +RVVCALL(OPIVV2, vabdu_vv_h, OP_UUU_H, H2, H2, H2, DO_ABD) +RVVCALL(OPIVV2, vabdu_vv_w, OP_UUU_W, H4, H4, H4, DO_ABD) +RVVCALL(OPIVV2, vabdu_vv_d, OP_UUU_D, H8, H8, H8, DO_ABD) +RVVCALL(OPIVX2, vabdu_vx_b, OP_UUU_B, H1, H1, DO_ABD) +RVVCALL(OPIVX2, vabdu_vx_h, OP_UUU_H, H2, H2, DO_ABD) +RVVCALL(OPIVX2, vabdu_vx_w, OP_UUU_W, H4, H4, DO_ABD) +RVVCALL(OPIVX2, vabdu_vx_d, OP_UUU_D, H8, H8, DO_ABD) + +RVVCALL(OPIVV3, vwabda_vv_b, WOP_SSS_B, H2, H1, H1, DO_ABDACC) +RVVCALL(OPIVV3, vwabda_vv_h, WOP_SSS_H, H4, H2, H2, DO_ABDACC) +RVVCALL(OPIVX3, vwabda_vx_b, WOP_SSS_B, H2, H1, DO_ABDACC) +RVVCALL(OPIVX3, vwabda_vx_h, WOP_SSS_H, H4, H2, DO_ABDACC) +RVVCALL(OPIVV3, vwabdau_vv_b, WOP_UUU_B, H2, H1, H1, DO_ABDACC) +RVVCALL(OPIVV3, vwabdau_vv_h, WOP_UUU_H, H4, H2, H2, DO_ABDACC) +RVVCALL(OPIVX3, vwabdau_vx_b, WOP_UUU_B, H2, H1, DO_ABDACC) +RVVCALL(OPIVX3, vwabdau_vx_h, WOP_UUU_H, H4, H2, DO_ABDACC) + +GEN_VEXT_VV(vabd_vv_b, 1) +GEN_VEXT_VV(vabd_vv_h, 2) +GEN_VEXT_VV(vabd_vv_w, 4) +GEN_VEXT_VV(vabd_vv_d, 8) +GEN_VEXT_VX(vabd_vx_b, 1) +GEN_VEXT_VX(vabd_vx_h, 2) +GEN_VEXT_VX(vabd_vx_w, 4) +GEN_VEXT_VX(vabd_vx_d, 8) +GEN_VEXT_VV(vabdu_vv_b, 1) +GEN_VEXT_VV(vabdu_vv_h, 2) +GEN_VEXT_VV(vabdu_vv_w, 4) +GEN_VEXT_VV(vabdu_vv_d, 8) +GEN_VEXT_VX(vabdu_vx_b, 1) +GEN_VEXT_VX(vabdu_vx_h, 2) +GEN_VEXT_VX(vabdu_vx_w, 4) +GEN_VEXT_VX(vabdu_vx_d, 8) + +GEN_VEXT_VV(vwabda_vv_b, 2) +GEN_VEXT_VV(vwabda_vv_h, 4) +GEN_VEXT_VX(vwabda_vx_b, 2) +GEN_VEXT_VX(vwabda_vx_h, 4) +GEN_VEXT_VV(vwabdau_vv_b, 2) +GEN_VEXT_VV(vwabdau_vv_h, 4) +GEN_VEXT_VX(vwabdau_vx_b, 2) +GEN_VEXT_VX(vwabdau_vx_h, 4) diff --git a/tests/qtest/iommu-riscv-test.c b/tests/qtest/iommu-riscv-test.c index 2638024891..1cd753c4f2 100644 --- a/tests/qtest/iommu-riscv-test.c +++ b/tests/qtest/iommu-riscv-test.c @@ -19,6 +19,12 @@ #define DMA_LEN 4 +#define DBG_PAGE_SIZE 0x1000ull +#define DBG_NAPOT_SIZE 0x10000ull +#define DBG_SUPERPAGE_SIZE 0x200000ull +#define DBG_TRANSLATED_PA 0x90000000ull +#define DBG_NESTED_GPA 0x200000ull + /* RISC-V virt machine PCI configuration */ #define RISCV_GPEX_PIO_BASE 0x3000000 #define RISCV_BUS_PIO_LIMIT 0x10000 @@ -35,6 +41,64 @@ typedef struct RiscvIommuTestState { uint64_t iommu_base; } RiscvIommuTestState; +typedef struct RiscvIommuDbgTest { + const char *name; + QRIOMMUTransMode mode; + uint64_t s_page_size; + uint64_t g_page_size; + uint64_t pa; + uint64_t expected_response; +} RiscvIommuDbgTest; + +static const RiscvIommuDbgTest debug_tests[] = { + { + .name = "page-4k", + .mode = QRIOMMU_TM_S_STAGE_ONLY, + .s_page_size = DBG_PAGE_SIZE, + .pa = DBG_TRANSLATED_PA + DBG_PAGE_SIZE, + .expected_response = 0x24000400ull, + }, { + .name = "napot-64k", + .mode = QRIOMMU_TM_S_STAGE_ONLY, + .s_page_size = DBG_NAPOT_SIZE, + .pa = DBG_TRANSLATED_PA, + .expected_response = 0x24001e00ull, + }, { + .name = "superpage", + .mode = QRIOMMU_TM_S_STAGE_ONLY, + .s_page_size = DBG_SUPERPAGE_SIZE, + .pa = DBG_TRANSLATED_PA, + .expected_response = 0x2403fe00ull, + }, { + .name = "g-stage-superpage", + .mode = QRIOMMU_TM_G_STAGE_ONLY, + .g_page_size = DBG_SUPERPAGE_SIZE, + .pa = DBG_TRANSLATED_PA, + .expected_response = 0x2403fe00ull, + }, { + .name = "nested-s4k-g2m", + .mode = QRIOMMU_TM_NESTED, + .s_page_size = DBG_PAGE_SIZE, + .g_page_size = DBG_SUPERPAGE_SIZE, + .pa = DBG_TRANSLATED_PA, + .expected_response = 0x24001000ull, + }, { + .name = "nested-s2m-g4k", + .mode = QRIOMMU_TM_NESTED, + .s_page_size = DBG_SUPERPAGE_SIZE, + .g_page_size = DBG_PAGE_SIZE, + .pa = DBG_TRANSLATED_PA, + .expected_response = 0x24001000ull, + }, { + .name = "nested-s2m-g2m", + .mode = QRIOMMU_TM_NESTED, + .s_page_size = DBG_SUPERPAGE_SIZE, + .g_page_size = DBG_SUPERPAGE_SIZE, + .pa = DBG_TRANSLATED_PA, + .expected_response = 0x2403fe00ull, + }, +}; + static void riscv_config_qpci_bus(QGenericPCIBus *qpci) { qpci->gpex_pio_base = RISCV_GPEX_PIO_BASE; @@ -264,6 +328,129 @@ static void test_riscv_iommu_nested(void) run_riscv_iommu_translation(&cfg); } +static void riscv_iommu_dbg_map_leaf(QTestState *qts, uint64_t l1_pa, + uint64_t l2_pa, uint64_t va, uint64_t pa, + uint64_t page_size) +{ + uint64_t pte = ((pa >> 12) << 10) | QRIOMMU_LEAF_PTE_RW_MASK; + uint64_t pte_addr; + + g_assert_cmphex(pa & (page_size - 1), ==, 0); + + if (page_size == DBG_SUPERPAGE_SIZE) { + pte_addr = l1_pa + (((va >> 21) & 0x1ff) * sizeof(uint64_t)); + qtest_writeq(qts, pte_addr, pte); + } else if (page_size == DBG_NAPOT_SIZE) { + /* A 64 KiB NAPOT PTE has N=1 and PPN[3:0]=1000. */ + pte |= BIT_ULL(63) | (8ull << 10); + va &= ~(DBG_NAPOT_SIZE - 1); + for (unsigned i = 0; i < DBG_NAPOT_SIZE / DBG_PAGE_SIZE; i++) { + pte_addr = l2_pa + ((((va >> 12) + i) & 0x1ff) * + sizeof(uint64_t)); + qtest_writeq(qts, pte_addr, pte); + } + } else { + g_assert_cmphex(page_size, ==, DBG_PAGE_SIZE); + pte_addr = l2_pa + (((va >> 12) & 0x1ff) * sizeof(uint64_t)); + qtest_writeq(qts, pte_addr, pte); + } +} + +static uint64_t riscv_iommu_dbg_translate(RiscvIommuTestState *state, + uint64_t iova) +{ + uint64_t request; + + qtest_writeq(state->qts, + state->iommu_base + RISCV_IOMMU_REG_TR_REQ_IOVA, iova); + request = ((uint64_t)state->testdev->devfn << 40) | + RISCV_IOMMU_TR_REQ_CTL_GO_BUSY; + qtest_writeq(state->qts, + state->iommu_base + RISCV_IOMMU_REG_TR_REQ_CTL, request); + + request = qtest_readq(state->qts, + state->iommu_base + RISCV_IOMMU_REG_TR_REQ_CTL); + g_assert_cmpuint(request & RISCV_IOMMU_TR_REQ_CTL_GO_BUSY, ==, 0); + + return qtest_readq(state->qts, + state->iommu_base + RISCV_IOMMU_REG_TR_RESPONSE); +} + +static void test_riscv_iommu_dbg(gconstpointer data) +{ + const RiscvIommuDbgTest *cfg = data; + RiscvIommuTestState state = { 0 }; + uint64_t iova = QRIOMMU_IOVA & ~(DBG_PAGE_SIZE - 1); + uint64_t s_pa = cfg->pa; + uint64_t page_size = cfg->mode == QRIOMMU_TM_G_STAGE_ONLY ? + cfg->g_page_size : cfg->s_page_size; + uint64_t response; + + if (!riscv_iommu_test_setup(&state)) { + return; + } + + riscv_iommu_check(state.qts, state.iommu_base, cfg->mode); + qriommu_build_translation(state.qts, cfg->mode, state.testdev->devfn); + + if (cfg->mode == QRIOMMU_TM_NESTED) { + uint64_t g_l1_pa = QRIOMMU_SPACE_OFFS + QRIOMMU_G_L0_PTE_VAL; + uint64_t g_l2_pa = QRIOMMU_SPACE_OFFS + QRIOMMU_G_L1_PTE_VAL; + uint64_t offset = iova & (DBG_SUPERPAGE_SIZE - 1); + uint64_t gpa = DBG_NESTED_GPA + offset; + uint64_t pte_addr; + uint64_t pte; + + /* Map all S-stage page tables through one 2 MiB G-stage leaf. */ + riscv_iommu_dbg_map_leaf(state.qts, g_l1_pa, g_l2_pa, 0, + QRIOMMU_SPACE_OFFS, DBG_SUPERPAGE_SIZE); + + if (cfg->g_page_size == DBG_PAGE_SIZE) { + pte_addr = g_l1_pa + (((gpa >> 21) & 0x1ff) * sizeof(uint64_t)); + pte = ((g_l2_pa >> 12) << 10) | QRIOMMU_NON_LEAF_PTE_MASK; + qtest_writeq(state.qts, pte_addr, pte); + } + riscv_iommu_dbg_map_leaf(state.qts, g_l1_pa, g_l2_pa, gpa, + cfg->pa + (offset & ~(cfg->g_page_size - 1)), + cfg->g_page_size); + s_pa = gpa & ~(cfg->s_page_size - 1); + page_size = MIN(page_size, cfg->g_page_size); + } + + if (cfg->mode == QRIOMMU_TM_G_STAGE_ONLY) { + riscv_iommu_dbg_map_leaf(state.qts, + QRIOMMU_SPACE_OFFS + QRIOMMU_G_L0_PTE_VAL, + QRIOMMU_SPACE_OFFS + QRIOMMU_G_L1_PTE_VAL, + iova, cfg->pa, cfg->g_page_size); + } else { + riscv_iommu_dbg_map_leaf(state.qts, + QRIOMMU_SPACE_OFFS + QRIOMMU_L0_PTE_VAL, + QRIOMMU_SPACE_OFFS + QRIOMMU_L1_PTE_VAL, + iova, s_pa, cfg->s_page_size); + } + qriommu_program_regs(state.qts, state.iommu_base); + + /* + * The spec permits reporting a smaller range. These tests check QEMU's + * choice to report the effective range returned by an uncached walk. + * No DMA precedes these requests, and debug requests do not fill the IOTLB. + */ + response = riscv_iommu_dbg_translate(&state, iova); + g_assert_cmphex(response, ==, cfg->expected_response); + + if (page_size > DBG_PAGE_SIZE) { + /* Check both ends as well as the interior of the reported range. */ + iova &= ~(page_size - 1); + response = riscv_iommu_dbg_translate(&state, iova); + g_assert_cmphex(response, ==, cfg->expected_response); + response = riscv_iommu_dbg_translate(&state, + iova + page_size - DBG_PAGE_SIZE); + g_assert_cmphex(response, ==, cfg->expected_response); + } + + riscv_iommu_test_teardown(&state); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -275,5 +462,11 @@ int main(int argc, char **argv) test_riscv_iommu_g_stage_only); qtest_add_func("/iommu-testdev/translation/ns-nested", test_riscv_iommu_nested); + for (unsigned i = 0; i < G_N_ELEMENTS(debug_tests); i++) { + g_autofree char *path = g_strdup_printf("/iommu-testdev/debug/%s", + debug_tests[i].name); + + qtest_add_data_func(path, &debug_tests[i], test_riscv_iommu_dbg); + } return g_test_run(); } diff --git a/tests/qtest/k230-decomp-gzip-test.c b/tests/qtest/k230-decomp-gzip-test.c index e80113fd28..249c8ae82c 100644 --- a/tests/qtest/k230-decomp-gzip-test.c +++ b/tests/qtest/k230-decomp-gzip-test.c @@ -46,7 +46,7 @@ static inline hwaddr k230_sram_addr(hwaddr off) static inline hwaddr k230_sram_input_addr(unsigned int slot) { return k230_sram_addr(K230_DECOMP_GZIP_SRAM_IN_BASE + - slot * K230_DECOMP_GZIP_BLOCK_SIZE); + (hwaddr) slot * K230_DECOMP_GZIP_BLOCK_SIZE); } /* diff --git a/tests/tcg/riscv64/system/meson.build b/tests/tcg/riscv64/system/meson.build index 728526dc7a..3c8b018d9e 100644 --- a/tests/tcg/riscv64/system/meson.build +++ b/tests/tcg/riscv64/system/meson.build @@ -25,6 +25,18 @@ tests += { 'test-minstret-ecall.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]}, 'test-minstret-wfi.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]}, 'test-misa-w.S': setup + {'qemu_args': ['-cpu', 'rv64,x-misa-w=true,c=true,v=true', qemu_args]}, + 'test-zvabd.S': setup + {'qemu_args': ['-cpu', 'rv64,v=true,vlen=256,x-zvabd=true', qemu_args]}, + 'test-vsepc-masking.S': setup + { + 'test_name': 'test-vsepc-masking-c', + 'qemu_args': ['-cpu', 'rv64,h=true,c=true', qemu_args], + }, +} + +tests += { + 'test-vsepc-masking.S': { + 'test_name': 'test-vsepc-masking-no-c', + 'qemu_args': ['-cpu', 'rv64,h=true,c=false,zca=false', qemu_args], + }, } tests += { diff --git a/tests/tcg/riscv64/test-vsepc-masking.S b/tests/tcg/riscv64/test-vsepc-masking.S new file mode 100644 index 0000000000..394a7f361c --- /dev/null +++ b/tests/tcg/riscv64/test-vsepc-masking.S @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#define MISA_C (1 << 2) + + .option norvc + .text + .global _start +_start: + csrr s0, misa + andi s0, s0, MISA_C + + lla s1, test_addr + ori t0, s1, 3 + csrw vsepc, t0 + csrr t1, vsepc + + beqz s0, ialign32 + addi t2, s1, 2 /* IALIGN=16: bit 0 reads as zero. */ + j check + +ialign32: + /* IALIGN=32: bits [1:0] read as zero. */ + mv t2, s1 + +check: + li a0, 2 + bne t1, t2, _exit + + li a0, 0 + j _exit + + .balign 4 +test_addr: + nop + +/* Exit code in a0. */ +_exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence. */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 diff --git a/tests/tcg/riscv64/test-zvabd.S b/tests/tcg/riscv64/test-zvabd.S new file mode 100644 index 0000000000..4f91acea0c --- /dev/null +++ b/tests/tcg/riscv64/test-zvabd.S @@ -0,0 +1,659 @@ +/* + * Test the Zvabd vector absolute-difference instructions and the vabs.v + * pseudoinstruction. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + .option arch, +v + .option norvc + + .text + + .global _start +_start: + /* Enable the vector unit (mstatus.VS = Initial). */ + li t0, 1 << 9 + csrs mstatus, t0 + + /* Route synchronous traps to trap_handler (mtvec direct mode). */ + la t0, trap_handler + csrw mtvec, t0 + + /* Run each test function. */ + call test_vabs_v + bnez a0, _exit + call test_vabs_v_mask + bnez a0, _exit + + call test_vabd_vv + bnez a0, _exit + call test_vabd_vv_mask + bnez a0, _exit + + call test_vabd_vx + bnez a0, _exit + call test_vabd_vx_mask + bnez a0, _exit + + call test_vabdu_vv + bnez a0, _exit + call test_vabdu_vv_mask + bnez a0, _exit + + call test_vabdu_vx + bnez a0, _exit + call test_vabdu_vx_mask + bnez a0, _exit + + call test_vwabda_vv + bnez a0, _exit + call test_vwabda_vv_mask + bnez a0, _exit + + call test_vwabda_vx + bnez a0, _exit + call test_vwabda_vx_mask + bnez a0, _exit + + call test_vwabdau_vv + bnez a0, _exit + call test_vwabdau_vv_mask + bnez a0, _exit + + call test_vwabdau_vx + bnez a0, _exit + call test_vwabdau_vx_mask + bnez a0, _exit + + j _exit + +test_vabs_v: + vsetivli zero, 2, e8, m1, ta, ma + + /* Load .arr_neg array in v1 */ + la t0,.arr_neg + vle8.v v1,0(t0) + + /* vabs.v v2, v1 (vabd.vx v2, v1, x0) raw opcode */ + .insn r 0x57, 0x6, 0x2b, x2, x0, x1 + + /* Load .arr_pos in v3 */ + la t1,.arr_pos + vle8.v v3,0(t1) + + /* Compare v2 and v3 into v0 */ + vmsne.vv v0,v2,v3 + vcpop.m a0,v0 + snez a0,a0 + + ret + +test_vabs_v_mask: + vsetivli zero, 2, e8, m1, ta, mu + + /* Load .arr_neg array in v1 */ + la t0, .arr_neg + vle8.v v1, 0(t0) + + /* Zero v2 using .arr_zero */ + la t0,.arr_zero + vle8.v v2,0(t0) + + /* Load .v0_mask array in v0 */ + la t1,.v0_mask + vle8.v v0,0(t1) + + /* vabs.v v2, v1, v0.t raw opcode */ + .insn r 0x57, 0x6, 0x2a, x2, x0, x1 + + /* Load .arr_masked in v3 */ + la t0,.arr_masked + vle8.v v3,0(t0) + + /* Compare v2 and v3 into v0 */ + vmsne.vv v0,v2,v3 + vcpop.m a0,v0 + snez a0,a0 + + ret + +test_vabd_vv: + /* + * Test signed vector-vector absolute difference: + * abs({-5, -7} - {5, 7}) = {10, 14}. + */ + vsetivli zero, 2, e8, m1, ta, mu + + /* Load the two signed source vectors into v1 and v3. */ + la t0, .arr_neg + vle8.v v1, 0(t0) + la t0, .arr_pos + vle8.v v3, 0(t0) + + /* Execute vabd.vv v2, v1, v3. */ + .insn r 0x57, 0x2, 0x2b, x2, x3, x1 + + /* Load the expected result into v3. */ + la t0, .expect_vabd_vv + vle8.v v3, 0(t0) + + /* Compare v2 and v3 into v0 */ + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + + ret + +test_vabd_vv_mask: + /* + * Test masked vabd.vv. Element 0 remains 9 and element 1 becomes + * abs(-7 - 7) = 14. + */ + vsetivli zero, 2, e8, m1, ta, mu + + /* Load the two signed source vectors into v1 and v3. */ + la t0, .arr_neg + vle8.v v1, 0(t0) + la t0, .arr_pos + vle8.v v3, 0(t0) + + /* Load original value into v2 */ + la t0, .arr_init + vle8.v v2, 0(t0) + + /* Load mask value into v0 */ + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x2, 0x2a, x2, x3, x1 + + /* Load the expected result into v3. */ + la t0, .expect_vabd_vv_masked + vle8.v v3, 0(t0) + + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vabd_vx: + /* + * Test signed vector-scalar absolute difference: + * abs({-5, -7} - 3) = {8, 10}. + */ + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_neg + vle8.v v1, 0(t0) + li a2, 3 + + /* Execute vabd.vx v2, v1, a2. */ + .insn r 0x57, 0x6, 0x2b, x2, x12, x1 + + /* Load the expected result into v3. */ + la t0, .expect_vabd_vx + vle8.v v3, 0(t0) + + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vabd_vx_mask: + /* + * Test masked vabd.vx. Element 0 remains 9 and element 1 becomes + * abs(-7 - 3) = 10. + */ + vsetivli zero, 2, e8, m1, ta, mu + + la t0, .arr_neg + vle8.v v1, 0(t0) + li a2, 3 + + la t0, .arr_init + vle8.v v2, 0(t0) + + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x6, 0x2a, x2, x12, x1 + + la t0, .expect_vabd_vx_masked + vle8.v v3, 0(t0) + + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vabdu_vv: + /* + * Test unsigned vector-vector absolute difference: + * abs({0, 255} - {255, 0}) = {255, 255}. + */ + vsetivli zero, 2, e8, m1, ta, mu + + /* Load the two unsigned source vectors into v1 and v3. */ + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + la t0, .arr_unsigned_rhs + vle8.v v3, 0(t0) + + /* Execute vabdu.vv v2, v1, v3. */ + .insn r 0x57, 0x2, 0x2d, x2, x3, x1 + + /* Load the expected result into v3. */ + la t0, .expect_vabdu_vv + vle8.v v3, 0(t0) + + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vabdu_vv_mask: + /* + * Test masked vabdu.vv. Element 0 remains 9 and element 1 becomes + * abs(255 - 0) = 255. + */ + vsetivli zero, 2, e8, m1, ta, mu + + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + la t0, .arr_unsigned_rhs + vle8.v v3, 0(t0) + + la t0, .arr_init + vle8.v v2, 0(t0) + + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x2, 0x2c, x2, x3, x1 + + la t0, .expect_vabdu_vv_masked + vle8.v v3, 0(t0) + + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vabdu_vx: + /* + * Test unsigned vector-scalar absolute difference: + * abs({0, 255} - 128) = {128, 127}. + */ + vsetivli zero, 2, e8, m1, ta, mu + + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + li a2, 128 + + /* Execute vabdu.vx v2, v1, a2. */ + .insn r 0x57, 0x6, 0x2d, x2, x12, x1 + + la t0, .expect_vabdu_vx + vle8.v v3, 0(t0) + + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vabdu_vx_mask: + /* + * Test masked vabdu.vx. Element 0 remains 9 and element 1 becomes + * abs(255 - 128) = 127. + */ + vsetivli zero, 2, e8, m1, ta, mu + + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + li a2, 128 + + la t0, .arr_init + vle8.v v2, 0(t0) + + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x6, 0x2c, x2, x12, x1 + + la t0, .expect_vabdu_vx_masked + vle8.v v3, 0(t0) + + vmsne.vv v0, v2, v3 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabda_vv: + /* + * Test signed widening vector-vector absolute difference and + * accumulation. Start with v4 = {1000, -1000}, and the expected + * widened result is {1000, -1000} + abs({-5, -7} - {5, 7}) = + * {1010, -986}. + */ + /* Load the 16-bit accumulator before selecting 8-bit operands. */ + vsetivli zero, 2, e16, m2, ta, mu + la t0, .arr_signed_acc + vle16.v v4, 0(t0) + + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_neg + vle8.v v1, 0(t0) + la t0, .arr_pos + vle8.v v2, 0(t0) + + /* Execute vwabda.vv v4, v1, v2. */ + .insn r 0x57, 0x0, 0x7b, x4, x2, x1 + + /* Select the widened EEW and compare v4 with the expected result. */ + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabda_vv + vle16.v v6, 0(t0) + + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabda_vv_mask: + /* + * Test masked vwabda.vv. + * Start with v4 = {1000, -1000}, v0 = {0, 1}, and the expected widened + * result is {1000, -1000} + abs({-5, -7} - {5, 7}) = {1000, -986}. + */ + vsetivli zero, 2, e16, m2, ta, mu + la t0, .arr_signed_acc + vle16.v v4, 0(t0) + + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_neg + vle8.v v1, 0(t0) + la t0, .arr_pos + vle8.v v2, 0(t0) + + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x0, 0x7a, x4, x2, x1 + + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabda_vv_masked + + vle16.v v6, 0(t0) + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabda_vx: + /* + * Test signed widening vector-scalar absolute difference and + * accumulation. With scalar 3, v4 becomes {1000 + 8, -1000 + 10}. + */ + /* Load the 16-bit accumulator before selecting 8-bit operands. */ + vsetivli zero, 2, e16, m2, ta, mu + la t0, .arr_signed_acc + vle16.v v4, 0(t0) + + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_neg + vle8.v v1, 0(t0) + li a2, 3 + + /* Execute vwabda.vx v4, v1, a2. */ + .insn r 0x57, 0x4, 0x7b, x4, x12, x1 + + /* Select the widened EEW and compare v4 with the expected result. */ + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabda_vx + vle16.v v6, 0(t0) + + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabda_vx_mask: + /* + * Test masked vwabda.vx. Element 0 remains 1000 while element 1 + * accumulates 10 and becomes -990. + */ + vsetivli zero, 2, e16, m2, ta, mu + + la t0, .arr_signed_acc + vle16.v v4, 0(t0) + + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_neg + vle8.v v1, 0(t0) + li a2, 3 + + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x4, 0x7a, x4, x12, x1 + + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabda_vx_masked + vle16.v v6, 0(t0) + + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabdau_vv: + /* + * Test unsigned widening vector-vector absolute difference and + * accumulation. Start with v4 = {1000, 2000}, adding {255, 255} + * produces {1255, 2255}. + */ + /* Load the unsigned 16-bit accumulator and 8-bit source vectors. */ + vsetivli zero, 2, e16, m2, ta, mu + + la t0, .arr_unsigned_acc + vle16.v v4, 0(t0) + vsetivli zero, 2, e8, m1, ta, mu + + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + la t0, .arr_unsigned_rhs + vle8.v v2, 0(t0) + + /* Execute vwabdau.vv v4, v1, v2. */ + .insn r 0x57, 0x0, 0x7d, x4, x2, x1 + + /* Select the widened EEW and compare v4 with the expected result. */ + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabdau_vv + vle16.v v6, 0(t0) + + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabdau_vv_mask: + /* + * Test masked vwabdau.vv. Element 0 remains 1000 while element 1 + * accumulates 255 and becomes 2255. + */ + vsetivli zero, 2, e16, m2, ta, mu + + la t0, .arr_unsigned_acc + vle16.v v4, 0(t0) + + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + la t0, .arr_unsigned_rhs + vle8.v v2, 0(t0) + + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x0, 0x7c, x4, x2, x1 + + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabdau_vv_masked + vle16.v v6, 0(t0) + + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabdau_vx: + /* + * Test unsigned widening vector-scalar absolute difference and + * accumulation. With scalar 128, v4 becomes {1000 + 128, 2000 + 127}. + */ + /* Load the unsigned 16-bit accumulator and 8-bit source vector. */ + vsetivli zero, 2, e16, m2, ta, mu + + la t0, .arr_unsigned_acc + vle16.v v4, 0(t0) + + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + li a2, 128 + + /* Execute vwabdau.vx v4, v1, a2. */ + .insn r 0x57, 0x4, 0x7d, x4, x12, x1 + + /* Select the widened EEW and compare v4 with the expected result. */ + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabdau_vx + vle16.v v6, 0(t0) + + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + +test_vwabdau_vx_mask: + /* + * Test masked vwabdau.vx. Element 0 remains 1000 while element 1 + * accumulates 127 and becomes 2127. + */ + vsetivli zero, 2, e16, m2, ta, mu + + la t0, .arr_unsigned_acc + vle16.v v4, 0(t0) + + vsetivli zero, 2, e8, m1, ta, mu + la t0, .arr_unsigned_lhs + vle8.v v1, 0(t0) + li a2, 128 + + la t0, .v0_mask + vle8.v v0, 0(t0) + + .insn r 0x57, 0x4, 0x7c, x4, x12, x1 + + vsetivli zero, 2, e16, m2, ta, mu + la t0, .expect_vwabdau_vx_masked + vle16.v v6, 0(t0) + + vmsne.vv v0, v4, v6 + vcpop.m a0, v0 + snez a0, a0 + ret + + +/* Exit through the semihosting SYS_EXIT_EXTENDED call with a0 as the code. */ +_exit: + la a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .balign 4 +trap_handler: + csrr t4, mcause + la t5, trap_mcause + sd t4, 0(t5) + csrr t4, mtval + la t5, trap_mtval + sd t4, 0(t5) + li a0, 1 + j _exit + + .data + .balign 8 +semiargs: + .space 16 +trap_mcause: + .space 8 +trap_mtval: + .space 8 +.arr_neg: + .byte -5, -7 +.arr_pos: + .byte 5, 7 +.arr_zero: + .byte 0, 0 +.arr_init: + .byte 9, 9 +.v0_mask: + .byte 0b10 +.arr_masked: + .byte 0, 7 + +/* Unsigned input vectors used by vabdu and vwabdau. */ +.arr_unsigned_lhs: + .byte 0, 255 +.arr_unsigned_rhs: + .byte 255, 0 + .balign 2 + +/* Nonzero accumulators verify the add part of widening operations. */ +.arr_signed_acc: + .half 1000, -1000 +.arr_unsigned_acc: + .half 1000, 2000 + +/* Expected results for the unmasked and masked forms. */ +.expect_vabd_vv: + .byte 10, 14 +.expect_vabd_vv_masked: + .byte 9, 14 +.expect_vabd_vx: + .byte 8, 10 +.expect_vabd_vx_masked: + .byte 9, 10 +.expect_vabdu_vv: + .byte 255, 255 +.expect_vabdu_vv_masked: + .byte 9, 255 +.expect_vabdu_vx: + .byte 128, 127 +.expect_vabdu_vx_masked: + .byte 9, 127 +.expect_vwabda_vv: + .half 1010, -986 +.expect_vwabda_vv_masked: + .half 1000, -986 +.expect_vwabda_vx: + .half 1008, -990 +.expect_vwabda_vx_masked: + .half 1000, -990 +.expect_vwabdau_vv: + .half 1255, 2255 +.expect_vwabdau_vv_masked: + .half 1000, 2255 +.expect_vwabdau_vx: + .half 1128, 2127 +.expect_vwabdau_vx_masked: + .half 1000, 2127