diff options
155 files changed, 3442 insertions, 1765 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 29aac4fce..f1f925007 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -268,6 +268,7 @@ S: Maintained F: hw/xilinx_zynq.c F: hw/zynq_slcr.c F: hw/cadence_* +F: hw/xilinx_spips.c CRIS Machines ------------- @@ -349,9 +350,31 @@ PowerPC Machines 405 M: Alexander Graf <agraf@suse.de> L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: hw/ppc405_boards.c +Bamboo +M: Alexander Graf <agraf@suse.de> +L: qemu-ppc@nongnu.org +S: Odd Fixes +F: hw/ppc440_bamboo.c + +e500 +M: Alexander Graf <agraf@suse.de> +M: Scott Wood <scottwood@freescale.com> +L: qemu-ppc@nongnu.org +S: Supported +F: hw/ppc/e500.[hc] +F: hw/ppc/e500plat.c + +mpc8544ds +M: Alexander Graf <agraf@suse.de> +M: Scott Wood <scottwood@freescale.com> +L: qemu-ppc@nongnu.org +S: Supported +F: hw/ppc/mpc8544ds.c +F: hw/mpc8544_guts.c + New World M: Alexander Graf <agraf@suse.de> L: qemu-ppc@nongnu.org @@ -374,6 +397,19 @@ S: Odd Fixes F: hw/ppc_prep.c F: hw/prep_pci.[hc] +sPAPR +M: David Gibson <david@gibson.dropbear.id.au> +M: Alexander Graf <agraf@suse.de> +L: qemu-ppc@nongnu.org +S: Supported +F: hw/spapr* + +virtex_ml507 +M: Edgar E. Iglesias <edgar.iglesias@gmail.com> +L: qemu-ppc@nongnu.org +S: Odd Fixes +F: hw/virtex_ml507.c + SH4 Machines ------------ R2D @@ -457,6 +493,19 @@ S: Supported F: hw/pci* F: hw/piix* +ppc4xx +M: Alexander Graf <agraf@suse.de> +L: qemu-ppc@nongnu.org +S: Odd Fixes +F: hw/ppc4xx*.[hc] + +ppce500 +M: Alexander Graf <agraf@suse.de> +M: Scott Wood <scottwood@freescale.com> +L: qemu-ppc@nongnu.org +S: Supported +F: hw/ppce500_* + SCSI M: Paolo Bonzini <pbonzini@redhat.com> S: Supported @@ -469,6 +518,12 @@ M: Paul Brook <paul@codesourcery.com> S: Odd Fixes F: hw/lsi53c895a.c +SSI +M: Peter Crosthwaite <peter.crosthwaite@petalogix.com> +S: Maintained +F: hw/ssi.* +F: hw/m25p80.c + USB M: Gerd Hoffmann <kraxel@redhat.com> S: Maintained @@ -517,6 +572,7 @@ F: hw/xilinx_intc.c F: hw/xilinx_ethlite.c F: hw/xilinx_timer.c F: hw/xilinx.h +F: hw/xilinx_spi.c Subsystems ---------- diff --git a/block/qed-table.c b/block/qed-table.c index ce07b0554..de845ec3d 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -103,7 +103,6 @@ static void qed_write_table_cb(void *opaque, int ret) out: qemu_vfree(write_table_cb->table); gencb_complete(&write_table_cb->gencb, ret); - return; } /** diff --git a/blockdev.c b/blockdev.c index 1db9efecf..636fc5632 100644 --- a/blockdev.c +++ b/blockdev.c @@ -836,7 +836,6 @@ exit: QSIMPLEQ_FOREACH_SAFE(states, &snap_bdrv_states, entry, next) { g_free(states); } - return; } @@ -356,6 +356,9 @@ CPUArchState *cpu_copy(CPUArchState *env); CPUArchState *qemu_get_cpu(int cpu); #define CPU_DUMP_CODE 0x00010000 +#define CPU_DUMP_FPU 0x00020000 /* dump FPU register state, not just integer */ +/* dump info about TCG QEMU's condition code optimization state */ +#define CPU_DUMP_CCOP 0x00040000 void cpu_dump_state(CPUArchState *env, FILE *f, fprintf_function cpu_fprintf, int flags); diff --git a/cpu-exec.c b/cpu-exec.c index 134b3c4fc..252da8688 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -552,7 +552,7 @@ int cpu_exec(CPUArchState *env) #if defined(TARGET_I386) env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP) | (DF & DF_MASK); - log_cpu_state(env, X86_DUMP_CCOP); + log_cpu_state(env, CPU_DUMP_CCOP); env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_M68K) cpu_m68k_flush_flags(env, env->cc_op); @@ -395,11 +395,7 @@ void hw_error(const char *fmt, ...) fprintf(stderr, "\n"); for(env = first_cpu; env != NULL; env = env->next_cpu) { fprintf(stderr, "CPU #%d:\n", env->cpu_index); -#ifdef TARGET_I386 - cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU); -#else - cpu_dump_state(env, stderr, fprintf, 0); -#endif + cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU); } va_end(ap); abort(); @@ -613,7 +609,7 @@ static void qemu_tcg_init_cpu_signals(void) } #endif /* _WIN32 */ -QemuMutex qemu_global_mutex; +static QemuMutex qemu_global_mutex; static QemuCond qemu_io_proceeded_cond; static bool iothread_requesting_mutex; diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index f335a725f..2f1a5c994 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -22,6 +22,7 @@ CONFIG_ADS7846=y CONFIG_MAX111X=y CONFIG_SSI=y CONFIG_SSI_SD=y +CONFIG_SSI_M25P80=y CONFIG_LAN9118=y CONFIG_SMC91C111=y CONFIG_DS1338=y diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak index 64c9485de..2f442e5ae 100644 --- a/default-configs/microblaze-softmmu.mak +++ b/default-configs/microblaze-softmmu.mak @@ -5,3 +5,5 @@ CONFIG_PFLASH_CFI01=y CONFIG_SERIAL=y CONFIG_XILINX=y CONFIG_XILINX_AXI=y +CONFIG_SSI=y +CONFIG_SSI_M25P80=y diff --git a/default-configs/microblazeel-softmmu.mak b/default-configs/microblazeel-softmmu.mak index a9622760c..af9a3cde0 100644 --- a/default-configs/microblazeel-softmmu.mak +++ b/default-configs/microblazeel-softmmu.mak @@ -5,3 +5,5 @@ CONFIG_PFLASH_CFI01=y CONFIG_SERIAL=y CONFIG_XILINX=y CONFIG_XILINX_AXI=y +CONFIG_SSI=y +CONFIG_SSI_M25P80=y diff --git a/device_tree.c b/device_tree.c index d7a9b6bb8..a9236133c 100644 --- a/device_tree.c +++ b/device_tree.c @@ -304,3 +304,18 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) g_free(dupname); return retval; } + +void qemu_devtree_dumpdtb(void *fdt, int size) +{ + QemuOpts *machine_opts; + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + const char *dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); + if (dumpdtb) { + /* Dump the dtb to a file and quit */ + exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1); + } + } + +} diff --git a/device_tree.h b/device_tree.h index f7a3e6cfc..f0b3f35e0 100644 --- a/device_tree.h +++ b/device_tree.h @@ -49,4 +49,6 @@ int qemu_devtree_add_subnode(void *fdt, const char *name); sizeof(qdt_tmp)); \ } while (0) +void qemu_devtree_dumpdtb(void *fdt, int size); + #endif /* __DEVICE_TREE_H__ */ @@ -1742,20 +1742,12 @@ void cpu_abort(CPUArchState *env, const char *fmt, ...) fprintf(stderr, "qemu: fatal: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); -#ifdef TARGET_I386 - cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); -#else - cpu_dump_state(env, stderr, fprintf, 0); -#endif + cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU | CPU_DUMP_CCOP); if (qemu_log_enabled()) { qemu_log("qemu: fatal: "); qemu_log_vprintf(fmt, ap2); qemu_log("\n"); -#ifdef TARGET_I386 - log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP); -#else - log_cpu_state(env, 0); -#endif + log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP); qemu_log_flush(); qemu_log_close(); } diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 4b5254011..8b9cdc96e 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -505,7 +505,6 @@ static void virtfs_reset(V9fsPDU *pdu) error_report("9pfs:%s: One or more uncluncked fids " "found during reset", __func__); } - return; } #define P9_QID_TYPE_DIR 0x80 @@ -934,7 +933,6 @@ static void v9fs_version(void *opaque) out: complete_pdu(s, pdu, offset); v9fs_string_free(&version); - return; } static void v9fs_attach(void *opaque) @@ -1314,7 +1312,6 @@ out_nofid: g_free(wnames); g_free(qids); } - return; } static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path) @@ -2257,7 +2254,6 @@ static void v9fs_flush(void *opaque) free_pdu(pdu->s, cancel_pdu); } complete_pdu(s, pdu, 7); - return; } static void v9fs_link(void *opaque) @@ -2763,7 +2759,6 @@ out: put_fid(pdu, fidp); out_nofid: complete_pdu(s, pdu, retval); - return; } static void v9fs_mknod(void *opaque) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 24392f568..66ff86897 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -36,6 +36,7 @@ common-obj-$(CONFIG_APPLESMC) += applesmc.o common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o +common-obj-y += fifo.o # PPC devices common-obj-$(CONFIG_PREP_PCI) += prep_pci.o @@ -174,6 +175,7 @@ common-obj-y += scsi-disk.o cdrom.o hd-geometry.o block-common.o common-obj-y += scsi-generic.o scsi-bus.o common-obj-y += hid.o common-obj-$(CONFIG_SSI) += ssi.o +common-obj-$(CONFIG_SSI_M25P80) += m25p80.o common-obj-$(CONFIG_SSI_SD) += ssi-sd.o common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o diff --git a/hw/ads7846.c b/hw/ads7846.c index 41c7f101c..2ea9e55bb 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -119,11 +119,12 @@ static int ads7856_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_ads7846 = { .name = "ads7846", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, .post_load = ads7856_post_load, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, ADS7846State), VMSTATE_INT32_ARRAY(input, ADS7846State, 8), VMSTATE_INT32(noise, ADS7846State), VMSTATE_INT32(cycle, ADS7846State), diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 9eb939f38..5ea04c75a 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -77,7 +77,7 @@ static void clipper_init(ram_addr_t ram_size, isa_create_simple(isa_bus, "i8042"); /* VGA setup. Don't bother loading the bios. */ - alpha_pci_vga_setup(pci_bus); + pci_vga_init(pci_bus); /* Serial code setup. */ for (i = 0; i < MAX_SERIAL_PORTS; ++i) { diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index ea546f83f..8079a46ae 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -10,8 +10,6 @@ #include "alpha_sys.h" #include "qemu-log.h" #include "sysemu.h" -#include "vmware_vga.h" -#include "vga-pci.h" /* PCI IO reads/writes, to byte-word addressable memory. */ @@ -109,25 +107,3 @@ const MemoryRegionOps alpha_pci_iack_ops = { .max_access_size = 4, }, }; - -void alpha_pci_vga_setup(PCIBus *pci_bus) -{ - switch (vga_interface_type) { -#ifdef CONFIG_SPICE - case VGA_QXL: - pci_create_simple(pci_bus, -1, "qxl-vga"); - return; -#endif - case VGA_CIRRUS: - pci_cirrus_vga_init(pci_bus); - return; - case VGA_VMWARE: - pci_vmsvga_init(pci_bus); - return; - } - /* If VGA is enabled at all, and one of the above didn't work, then - fallback to Standard VGA. */ - if (vga_interface_type != VGA_NONE) { - pci_vga_init(pci_bus); - } -} diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index de40f8b61..7604d09c8 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -19,6 +19,4 @@ extern const MemoryRegionOps alpha_pci_bw_io_ops; extern const MemoryRegionOps alpha_pci_conf1_ops; extern const MemoryRegionOps alpha_pci_iack_ops; -void alpha_pci_vga_setup(PCIBus *pci_bus); - #endif diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2b39fb3c8..6d049e7de 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -1,6 +1,7 @@ obj-y = integratorcp.o versatilepb.o arm_pic.o obj-y += arm_boot.o obj-y += xilinx_zynq.o zynq_slcr.o +obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o diff --git a/hw/blizzard.c b/hw/blizzard.c index d1c9d8151..06e19b364 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -878,8 +878,6 @@ void s1d13745_write_block(void *opaque, int dc, len -= 2; buf += 2; } - - return; } static void blizzard_update_display(void *opaque) diff --git a/hw/bt-hci.c b/hw/bt-hci.c index 47f9a4e49..e54cfd781 100644 --- a/hw/bt-hci.c +++ b/hw/bt-hci.c @@ -786,7 +786,6 @@ static void bt_hci_lmp_connection_request(struct bt_link_s *link) memcpy(¶ms.dev_class, &link->host->class, sizeof(params.dev_class)); params.link_type = ACL_LINK; bt_hci_event(hci, EVT_CONN_REQUEST, ¶ms, EVT_CONN_REQUEST_SIZE); - return; } static void bt_hci_conn_accept_timeout(void *opaque) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 4284c1e2a..df059307b 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -28,7 +28,6 @@ */ #include "hw.h" #include "pci.h" -#include "vga-pci.h" #include "console.h" #include "vga_int.h" #include "loader.h" @@ -2970,11 +2969,6 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) return 0; } -DeviceState *pci_cirrus_vga_init(PCIBus *bus) -{ - return &pci_create_simple(bus, -1, "cirrus-vga")->qdev; -} - static void cirrus_vga_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c index 2bdc615b4..eec0fe314 100644 --- a/hw/device-hotplug.c +++ b/hw/device-hotplug.c @@ -89,5 +89,4 @@ err: if (dinfo) { drive_put_ref(dinfo); } - return; } diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index 80af22cc3..60b33c788 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -347,8 +347,6 @@ static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset, TARGET_FMT_plx "\n", offset); break; } - - return; } /* Get combiner group and bit from irq number */ @@ -380,8 +378,6 @@ static void exynos4210_combiner_handler(void *opaque, int irq, int level) } exynos4210_combiner_update(s, group_n); - - return; } static void exynos4210_combiner_reset(DeviceState *d) diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 7d03dd9ae..4fea09873 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -193,8 +193,6 @@ static void exynos4210_irq_handler(void *opaque, int irq, int level) /* Bypass */ qemu_set_irq(s->board_irqs[irq], level); - - return; } /* @@ -410,8 +408,6 @@ static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) } qemu_irq_lower(s->out); - - return; } static void exynos4210_irq_gate_reset(DeviceState *d) diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c index 7a22b1f90..6f94ce230 100644 --- a/hw/exynos4210_mct.c +++ b/hw/exynos4210_mct.c @@ -574,8 +574,6 @@ static void exynos4210_gfrc_event(void *opaque) exynos4210_gfrc_set_count(&s->g_timer, distance); exynos4210_gfrc_start(&s->g_timer); - - return; } /* @@ -1286,8 +1286,6 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) fdctrl->msr |= FD_MSR_DIO; /* IO based transfer: calculate len */ fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); - - return; } /* Prepare a transfer of deleted data */ diff --git a/hw/fifo.c b/hw/fifo.c new file mode 100644 index 000000000..68a955a77 --- /dev/null +++ b/hw/fifo.c @@ -0,0 +1,78 @@ +/* + * Generic FIFO component, implemented as a circular buffer. + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "fifo.h" + +void fifo8_create(Fifo8 *fifo, uint32_t capacity) +{ + fifo->data = g_new(uint8_t, capacity); + fifo->capacity = capacity; + fifo->head = 0; + fifo->num = 0; +} + +void fifo8_destroy(Fifo8 *fifo) +{ + g_free(fifo->data); +} + +void fifo8_push(Fifo8 *fifo, uint8_t data) +{ + if (fifo->num == fifo->capacity) { + abort(); + } + fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; + fifo->num++; +} + +uint8_t fifo8_pop(Fifo8 *fifo) +{ + uint8_t ret; + + if (fifo->num == 0) { + abort(); + } + ret = fifo->data[fifo->head++]; + fifo->head %= fifo->capacity; + fifo->num--; + return ret; +} + +void fifo8_reset(Fifo8 *fifo) +{ + fifo->num = 0; +} + +bool fifo8_is_empty(Fifo8 *fifo) +{ + return (fifo->num == 0); +} + +bool fifo8_is_full(Fifo8 *fifo) +{ + return (fifo->num == fifo->capacity); +} + +const VMStateDescription vmstate_fifo8 = { + .name = "Fifo8", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, 0, capacity), + VMSTATE_UINT32(head, Fifo8), + VMSTATE_UINT32(num, Fifo8), + VMSTATE_END_OF_LIST() + } +}; diff --git a/hw/fifo.h b/hw/fifo.h new file mode 100644 index 000000000..f23890abf --- /dev/null +++ b/hw/fifo.h @@ -0,0 +1,99 @@ +#ifndef FIFO_H +#define FIFO_H + +#include "hw.h" + +typedef struct { + /* All fields are private */ + uint8_t *data; + uint32_t capacity; + uint32_t head; + uint32_t num; +} Fifo8; + +/** + * fifo8_create: + * @fifo: struct Fifo8 to initialise with new FIFO + * @capacity: capacity of the newly created FIFO + * + * Create a FIFO of the specified size. Clients should call fifo8_destroy() + * when finished using the fifo. The FIFO is initially empty. + */ + +void fifo8_create(Fifo8 *fifo, uint32_t capacity); + +/** + * fifo8_destroy: + * @fifo: FIFO to cleanup + * + * Cleanup a FIFO created with fifo8_create(). Frees memory created for FIFO + *storage. The FIFO is no longer usable after this has been called. + */ + +void fifo8_destroy(Fifo8 *fifo); + +/** + * fifo8_push: + * @fifo: FIFO to push to + * @data: data byte to push + * + * Push a data byte to the FIFO. Behaviour is undefined if the FIFO is full. + * Clients are responsible for checking for fullness using fifo8_is_full(). + */ + +void fifo8_push(Fifo8 *fifo, uint8_t data); + +/** + * fifo8_pop: + * @fifo: fifo to pop from + * + * Pop a data byte from the FIFO. Behaviour is undefined if the FIFO is empty. + * Clients are responsible for checking for emptyness using fifo8_is_empty(). + * + * Returns: The popped data byte. + */ + +uint8_t fifo8_pop(Fifo8 *fifo); + +/** + * fifo8_reset: + * @fifo: FIFO to reset + * + * Reset a FIFO. All data is discarded and the FIFO is emptied. + */ + +void fifo8_reset(Fifo8 *fifo); + +/** + * fifo8_is_empty: + * @fifo: FIFO to check + * + * Check if a FIFO is empty. + * + * Returns: True if the fifo is empty, false otherwise. + */ + +bool fifo8_is_empty(Fifo8 *fifo); + +/** + * fifo8_is_full: + * @fifo: FIFO to check + * + * Check if a FIFO is full. + * + * Returns: True if the fifo is full, false otherwise. + */ + +bool fifo8_is_full(Fifo8 *fifo); + +extern const VMStateDescription vmstate_fifo8; + +#define VMSTATE_FIFO8(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(Fifo8), \ + .vmsd = &vmstate_fifo8, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, Fifo8), \ +} + +#endif /* FIFO_H */ diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 85a00a579..27fa6f51f 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -107,5 +107,4 @@ void framebuffer_update_display( DIRTY_MEMORY_VGA); *first_row = first; *last_row = last; - return; } diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 848cb3142..f22872514 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -89,7 +89,6 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) done: bdrv_acct_done(s->bs, &s->acct); io->dma_end(opaque); - return; } static void pmac_ide_transfer_cb(void *opaque, int ret) @@ -38,24 +38,37 @@ void qemu_set_irq(qemu_irq irq, int level) irq->handler(irq->opaque, irq->n, level); } -qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler, + void *opaque, int n) { qemu_irq *s; struct IRQState *p; int i; - s = (qemu_irq *)g_malloc0(sizeof(qemu_irq) * n); - p = (struct IRQState *)g_malloc0(sizeof(struct IRQState) * n); - for (i = 0; i < n; i++) { - p->handler = handler; - p->opaque = opaque; - p->n = i; + if (!old) { + n_old = 0; + } + s = old ? g_renew(qemu_irq, old, n + n_old) : g_new(qemu_irq, n); + p = old ? g_renew(struct IRQState, s[0], n + n_old) : + g_new(struct IRQState, n); + for (i = 0; i < n + n_old; i++) { + if (i >= n_old) { + p->handler = handler; + p->opaque = opaque; + p->n = i; + } s[i] = p; p++; } return s; } +qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +{ + return qemu_extend_irqs(NULL, 0, handler, opaque, n); +} + + void qemu_free_irqs(qemu_irq *s) { g_free(s[0]); @@ -23,8 +23,17 @@ static inline void qemu_irq_pulse(qemu_irq irq) qemu_set_irq(irq, 0); } -/* Returns an array of N IRQs. */ +/* Returns an array of N IRQs. Each IRQ is assigned the argument handler and + * opaque data. + */ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); + +/* Extends an Array of IRQs. Old IRQs have their handlers and opaque data + * preserved. New IRQs are assigned the argument handler and opaque data. + */ +qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler, + void *opaque, int n); + void qemu_free_irqs(qemu_irq *s); /* Returns a new IRQ with opposite polarity. */ diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 47c93d37b..214f19457 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -19,6 +19,7 @@ #include "hw.h" #include "monitor.h" #include "sysbus.h" +#include "sysemu.h" #include "isa.h" #include "exec-memory.h" @@ -166,6 +167,25 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name) return dev; } +ISADevice *isa_vga_init(ISABus *bus) +{ + switch (vga_interface_type) { + case VGA_CIRRUS: + return isa_create_simple(bus, "isa-cirrus-vga"); + case VGA_QXL: + fprintf(stderr, "%s: qxl: no PCI bus\n", __func__); + return NULL; + case VGA_STD: + return isa_create_simple(bus, "isa-vga"); + case VGA_VMWARE: + fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__); + return NULL; + case VGA_NONE: + default: + return NULL; + } +} + static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent) { ISADevice *d = ISA_DEVICE(dev); @@ -47,6 +47,8 @@ ISADevice *isa_create(ISABus *bus, const char *name); ISADevice *isa_try_create(ISABus *bus, const char *name); ISADevice *isa_create_simple(ISABus *bus, const char *name); +ISADevice *isa_vga_init(ISABus *bus); + /** * isa_register_ioport: Install an I/O port region on the ISA bus. * diff --git a/hw/ivshmem.c b/hw/ivshmem.c index 59f1aa426..5c4ccb85f 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -149,7 +149,6 @@ static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val) s->intrstatus = val; ivshmem_update_irq(s, val); - return; } static uint32_t ivshmem_IntrStatus_read(IVShmemState *s) @@ -510,8 +509,6 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd); } - - return; } /* Select the MSI-X vectors used by device. @@ -536,7 +533,6 @@ static void ivshmem_reset(DeviceState *d) s->intrstatus = 0; ivshmem_use_msix(s); - return; } static uint64_t ivshmem_get_size(IVShmemState * s) { diff --git a/hw/leon3.c b/hw/leon3.c index 878d3aa55..7a9729dc2 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -210,7 +210,7 @@ static void leon3_generic_hw_init(ram_addr_t ram_size, } } -QEMUMachine leon3_generic_machine = { +static QEMUMachine leon3_generic_machine = { .name = "leon3_generic", .desc = "Leon-3 generic", .init = leon3_generic_hw_init, diff --git a/hw/m25p80.c b/hw/m25p80.c new file mode 100644 index 000000000..9a56de802 --- /dev/null +++ b/hw/m25p80.c @@ -0,0 +1,598 @@ +/* + * ST M25P80 emulator. Emulate all SPI flash devices based on the m25p80 command + * set. Known devices table current as of Jun/2012 and taken from linux. + * See drivers/mtd/devices/m25p80.c. + * + * Copyright (C) 2011 Edgar E. Iglesias <edgar.iglesias@gmail.com> + * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com> + * Copyright (C) 2012 PetaLogix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) a later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "blockdev.h" +#include "ssi.h" +#include "devices.h" + +#ifdef M25P80_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +/* Fields for FlashPartInfo->flags */ + +/* erase capabilities */ +#define ER_4K 1 +#define ER_32K 2 +/* set to allow the page program command to write 0s back to 1. Useful for + * modelling EEPROM with SPI flash command set + */ +#define WR_1 0x100 + +typedef struct FlashPartInfo { + const char *part_name; + /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */ + uint32_t jedec; + /* extended jedec code */ + uint16_t ext_jedec; + /* there is confusion between manufacturers as to what a sector is. In this + * device model, a "sector" is the size that is erased by the ERASE_SECTOR + * command (opcode 0xd8). + */ + uint32_t sector_size; + uint32_t n_sectors; + uint32_t page_size; + uint8_t flags; +} FlashPartInfo; + +/* adapted from linux */ + +#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\ + .part_name = (_part_name),\ + .jedec = (_jedec),\ + .ext_jedec = (_ext_jedec),\ + .sector_size = (_sector_size),\ + .n_sectors = (_n_sectors),\ + .page_size = 256,\ + .flags = (_flags),\ + +static const FlashPartInfo known_devices[] = { + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) }, + { INFO("at25fs040", 0x1f6604, 0, 64 << 10, 8, ER_4K) }, + + { INFO("at25df041a", 0x1f4401, 0, 64 << 10, 8, ER_4K) }, + { INFO("at25df321a", 0x1f4701, 0, 64 << 10, 64, ER_4K) }, + { INFO("at25df641", 0x1f4800, 0, 64 << 10, 128, ER_4K) }, + + { INFO("at26f004", 0x1f0400, 0, 64 << 10, 8, ER_4K) }, + { INFO("at26df081a", 0x1f4501, 0, 64 << 10, 16, ER_4K) }, + { INFO("at26df161a", 0x1f4601, 0, 64 << 10, 32, ER_4K) }, + { INFO("at26df321", 0x1f4700, 0, 64 << 10, 64, ER_4K) }, + + /* EON -- en25xxx */ + { INFO("en25f32", 0x1c3116, 0, 64 << 10, 64, ER_4K) }, + { INFO("en25p32", 0x1c2016, 0, 64 << 10, 64, 0) }, + { INFO("en25q32b", 0x1c3016, 0, 64 << 10, 64, 0) }, + { INFO("en25p64", 0x1c2017, 0, 64 << 10, 128, 0) }, + + /* Intel/Numonyx -- xxxs33b */ + { INFO("160s33b", 0x898911, 0, 64 << 10, 32, 0) }, + { INFO("320s33b", 0x898912, 0, 64 << 10, 64, 0) }, + { INFO("640s33b", 0x898913, 0, 64 << 10, 128, 0) }, + + /* Macronix */ + { INFO("mx25l4005a", 0xc22013, 0, 64 << 10, 8, ER_4K) }, + { INFO("mx25l8005", 0xc22014, 0, 64 << 10, 16, 0) }, + { INFO("mx25l1606e", 0xc22015, 0, 64 << 10, 32, ER_4K) }, + { INFO("mx25l3205d", 0xc22016, 0, 64 << 10, 64, 0) }, + { INFO("mx25l6405d", 0xc22017, 0, 64 << 10, 128, 0) }, + { INFO("mx25l12805d", 0xc22018, 0, 64 << 10, 256, 0) }, + { INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) }, + { INFO("mx25l25635e", 0xc22019, 0, 64 << 10, 512, 0) }, + { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { INFO("s25sl004a", 0x010212, 0, 64 << 10, 8, 0) }, + { INFO("s25sl008a", 0x010213, 0, 64 << 10, 16, 0) }, + { INFO("s25sl016a", 0x010214, 0, 64 << 10, 32, 0) }, + { INFO("s25sl032a", 0x010215, 0, 64 << 10, 64, 0) }, + { INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) }, + { INFO("s25sl064a", 0x010216, 0, 64 << 10, 128, 0) }, + { INFO("s25fl256s0", 0x010219, 0x4d00, 256 << 10, 128, 0) }, + { INFO("s25fl256s1", 0x010219, 0x4d01, 64 << 10, 512, 0) }, + { INFO("s25fl512s", 0x010220, 0x4d00, 256 << 10, 256, 0) }, + { INFO("s70fl01gs", 0x010221, 0x4d00, 256 << 10, 256, 0) }, + { INFO("s25sl12800", 0x012018, 0x0300, 256 << 10, 64, 0) }, + { INFO("s25sl12801", 0x012018, 0x0301, 64 << 10, 256, 0) }, + { INFO("s25fl129p0", 0x012018, 0x4d00, 256 << 10, 64, 0) }, + { INFO("s25fl129p1", 0x012018, 0x4d01, 64 << 10, 256, 0) }, + { INFO("s25fl016k", 0xef4015, 0, 64 << 10, 32, ER_4K | ER_32K) }, + { INFO("s25fl064k", 0xef4017, 0, 64 << 10, 128, ER_4K | ER_32K) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */ + { INFO("sst25vf040b", 0xbf258d, 0, 64 << 10, 8, ER_4K) }, + { INFO("sst25vf080b", 0xbf258e, 0, 64 << 10, 16, ER_4K) }, + { INFO("sst25vf016b", 0xbf2541, 0, 64 << 10, 32, ER_4K) }, + { INFO("sst25vf032b", 0xbf254a, 0, 64 << 10, 64, ER_4K) }, + { INFO("sst25wf512", 0xbf2501, 0, 64 << 10, 1, ER_4K) }, + { INFO("sst25wf010", 0xbf2502, 0, 64 << 10, 2, ER_4K) }, + { INFO("sst25wf020", 0xbf2503, 0, 64 << 10, 4, ER_4K) }, + { INFO("sst25wf040", 0xbf2504, 0, 64 << 10, 8, ER_4K) }, + + /* ST Microelectronics -- newer production may have feature updates */ + { INFO("m25p05", 0x202010, 0, 32 << 10, 2, 0) }, + { INFO("m25p10", 0x202011, 0, 32 << 10, 4, 0) }, + { INFO("m25p20", 0x202012, 0, 64 << 10, 4, 0) }, + { INFO("m25p40", 0x202013, 0, 64 << 10, 8, 0) }, + { INFO("m25p80", 0x202014, 0, 64 << 10, 16, 0) }, + { INFO("m25p16", 0x202015, 0, 64 << 10, 32, 0) }, + { INFO("m25p32", 0x202016, 0, 64 << 10, 64, 0) }, + { INFO("m25p64", 0x202017, 0, 64 << 10, 128, 0) }, + { INFO("m25p128", 0x202018, 0, 256 << 10, 64, 0) }, + + { INFO("m45pe10", 0x204011, 0, 64 << 10, 2, 0) }, + { INFO("m45pe80", 0x204014, 0, 64 << 10, 16, 0) }, + { INFO("m45pe16", 0x204015, 0, 64 << 10, 32, 0) }, + + { INFO("m25pe80", 0x208014, 0, 64 << 10, 16, 0) }, + { INFO("m25pe16", 0x208015, 0, 64 << 10, 32, ER_4K) }, + + { INFO("m25px32", 0x207116, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px32-s0", 0x207316, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px32-s1", 0x206316, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px64", 0x207117, 0, 64 << 10, 128, 0) }, + + /* Winbond -- w25x "blocks" are 64k, "sectors" are 4KiB */ + { INFO("w25x10", 0xef3011, 0, 64 << 10, 2, ER_4K) }, + { INFO("w25x20", 0xef3012, 0, 64 << 10, 4, ER_4K) }, + { INFO("w25x40", 0xef3013, 0, 64 << 10, 8, ER_4K) }, + { INFO("w25x80", 0xef3014, 0, 64 << 10, 16, ER_4K) }, + { INFO("w25x16", 0xef3015, 0, 64 << 10, 32, ER_4K) }, + { INFO("w25x32", 0xef3016, 0, 64 << 10, 64, ER_4K) }, + { INFO("w25q32", 0xef4016, 0, 64 << 10, 64, ER_4K) }, + { INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) }, + { INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) }, + + /* Numonyx -- n25q128 */ + { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, + + { }, +}; + +typedef enum { + NOP = 0, + PP = 0x2, + READ = 0x3, + WRDI = 0x4, + RDSR = 0x5, + WREN = 0x6, + FAST_READ = 0xb, + ERASE_4K = 0x20, + ERASE_32K = 0x52, + ERASE_SECTOR = 0xd8, + JEDEC_READ = 0x9f, + BULK_ERASE = 0xc7, +} FlashCMD; + +typedef enum { + STATE_IDLE, + STATE_PAGE_PROGRAM, + STATE_READ, + STATE_COLLECTING_DATA, + STATE_READING_DATA, +} CMDState; + +typedef struct Flash { + SSISlave ssidev; + uint32_t r; + + BlockDriverState *bdrv; + + uint8_t *storage; + uint32_t size; + int page_size; + + uint8_t state; + uint8_t data[16]; + uint32_t len; + uint32_t pos; + uint8_t needed_bytes; + uint8_t cmd_in_progress; + uint64_t cur_addr; + bool write_enable; + + int64_t dirty_page; + + char *part_name; + const FlashPartInfo *pi; + +} Flash; + +static void bdrv_sync_complete(void *opaque, int ret) +{ + /* do nothing. Masters do not directly interact with the backing store, + * only the working copy so no mutexing required. + */ +} + +static void flash_sync_page(Flash *s, int page) +{ + if (s->bdrv) { + int bdrv_sector, nb_sectors; + QEMUIOVector iov; + + bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE; + nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE); + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, + bdrv_sync_complete, NULL); + } +} + +static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) +{ + int64_t start, end, nb_sectors; + QEMUIOVector iov; + + if (!s->bdrv) { + return; + } + + assert(!(len % BDRV_SECTOR_SIZE)); + start = off / BDRV_SECTOR_SIZE; + end = (off + len) / BDRV_SECTOR_SIZE; + nb_sectors = end - start; + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE), + nb_sectors * BDRV_SECTOR_SIZE); + bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL); +} + +static void flash_erase(Flash *s, int offset, FlashCMD cmd) +{ + uint32_t len; + uint8_t capa_to_assert = 0; + + switch (cmd) { + case ERASE_4K: + len = 4 << 10; + capa_to_assert = ER_4K; + break; + case ERASE_32K: + len = 32 << 10; + capa_to_assert = ER_32K; + break; + case ERASE_SECTOR: + len = s->pi->sector_size; + break; + case BULK_ERASE: + len = s->size; + break; + default: + abort(); + } + + DB_PRINT("offset = %#x, len = %d\n", offset, len); + if ((s->pi->flags & capa_to_assert) != capa_to_assert) { + hw_error("m25p80: %dk erase size not supported by device\n", len); + } + + if (!s->write_enable) { + DB_PRINT("erase with write protect!\n"); + return; + } + memset(s->storage + offset, 0xff, len); + flash_sync_area(s, offset, len); +} + +static inline void flash_sync_dirty(Flash *s, int64_t newpage) +{ + if (s->dirty_page >= 0 && s->dirty_page != newpage) { + flash_sync_page(s, s->dirty_page); + s->dirty_page = newpage; + } +} + +static inline +void flash_write8(Flash *s, uint64_t addr, uint8_t data) +{ + int64_t page = addr / s->pi->page_size; + uint8_t prev = s->storage[s->cur_addr]; + + if (!s->write_enable) { + DB_PRINT("write with write protect!\n"); + } + + if ((prev ^ data) & data) { + DB_PRINT("programming zero to one! addr=%lx %x -> %x\n", + addr, prev, data); + } + + if (s->pi->flags & WR_1) { + s->storage[s->cur_addr] = data; + } else { + s->storage[s->cur_addr] &= data; + } + + flash_sync_dirty(s, page); + s->dirty_page = page; +} + +static void complete_collecting_data(Flash *s) +{ + s->cur_addr = s->data[0] << 16; + s->cur_addr |= s->data[1] << 8; + s->cur_addr |= s->data[2]; + + switch (s->cmd_in_progress) { + case PP: + s->state = STATE_PAGE_PROGRAM; + break; + case READ: + case FAST_READ: + s->state = STATE_READ; + break; + case ERASE_4K: + case ERASE_32K: + case ERASE_SECTOR: + flash_erase(s, s->cur_addr, s->cmd_in_progress); + break; + default: + break; + } +} + +static void decode_new_cmd(Flash *s, uint32_t value) +{ + s->cmd_in_progress = value; + DB_PRINT("decoded new command:%x\n", value); + + switch (value) { + + case ERASE_4K: + case ERASE_32K: + case ERASE_SECTOR: + case READ: + case PP: + s->needed_bytes = 3; + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case FAST_READ: + s->needed_bytes = 4; + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case WRDI: + s->write_enable = false; + break; + case WREN: + s->write_enable = true; + break; + + case RDSR: + s->data[0] = (!!s->write_enable) << 1; + s->pos = 0; + s->len = 1; + s->state = STATE_READING_DATA; + break; + + case JEDEC_READ: + DB_PRINT("populated jedec code\n"); + s->data[0] = (s->pi->jedec >> 16) & 0xff; + s->data[1] = (s->pi->jedec >> 8) & 0xff; + s->data[2] = s->pi->jedec & 0xff; + if (s->pi->ext_jedec) { + s->data[3] = (s->pi->ext_jedec >> 8) & 0xff; + s->data[4] = s->pi->ext_jedec & 0xff; + s->len = 5; + } else { + s->len = 3; + } + s->pos = 0; + s->state = STATE_READING_DATA; + break; + + case BULK_ERASE: + if (s->write_enable) { + DB_PRINT("chip erase\n"); + flash_erase(s, 0, BULK_ERASE); + } else { + DB_PRINT("chip erase with write protect!\n"); + } + break; + case NOP: + break; + default: + DB_PRINT("Unknown cmd %x\n", value); + break; + } +} + +static int m25p80_cs(SSISlave *ss, bool select) +{ + Flash *s = FROM_SSI_SLAVE(Flash, ss); + + if (select) { + s->len = 0; + s->pos = 0; + s->state = STATE_IDLE; + flash_sync_dirty(s, -1); + } + + DB_PRINT("%sselect\n", select ? "de" : ""); + + return 0; +} + +static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) +{ + Flash *s = FROM_SSI_SLAVE(Flash, ss); + uint32_t r = 0; + + switch (s->state) { + + case STATE_PAGE_PROGRAM: + DB_PRINT("page program cur_addr=%lx data=%x\n", s->cur_addr, + (uint8_t)tx); + flash_write8(s, s->cur_addr, (uint8_t)tx); + s->cur_addr++; + break; + + case STATE_READ: + r = s->storage[s->cur_addr]; + DB_PRINT("READ 0x%lx=%x\n", s->cur_addr, r); + s->cur_addr = (s->cur_addr + 1) % s->size; + break; + + case STATE_COLLECTING_DATA: + s->data[s->len] = (uint8_t)tx; + s->len++; + + if (s->len == s->needed_bytes) { + complete_collecting_data(s); + } + break; + + case STATE_READING_DATA: + r = s->data[s->pos]; + s->pos++; + if (s->pos == s->len) { + s->pos = 0; + s->state = STATE_IDLE; + } + break; + + default: + case STATE_IDLE: + decode_new_cmd(s, (uint8_t)tx); + break; + } + + return r; +} + +static int m25p80_init(SSISlave *ss) +{ + DriveInfo *dinfo; + Flash *s = FROM_SSI_SLAVE(Flash, ss); + const FlashPartInfo *i; + + if (!s->part_name) { /* default to actual m25p80 if no partname given */ + s->part_name = (char *)"m25p80"; + } + + i = known_devices; + for (i = known_devices;; i++) { + assert(i); + if (!i->part_name) { + fprintf(stderr, "Unknown SPI flash part: \"%s\"\n", s->part_name); + return 1; + } else if (!strcmp(i->part_name, s->part_name)) { + s->pi = i; + break; + } + } + + s->size = s->pi->sector_size * s->pi->n_sectors; + s->dirty_page = -1; + s->storage = qemu_blockalign(s->bdrv, s->size); + + dinfo = drive_get_next(IF_MTD); + + if (dinfo && dinfo->bdrv) { + DB_PRINT("Binding to IF_MTD drive\n"); + s->bdrv = dinfo->bdrv; + /* FIXME: Move to late init */ + if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size, + BDRV_SECTOR_SIZE))) { + fprintf(stderr, "Failed to initialize SPI flash!\n"); + return 1; + } + } else { + memset(s->storage, 0xFF, s->size); + } + + return 0; +} + +static void m25p80_pre_save(void *opaque) +{ + flash_sync_dirty((Flash *)opaque, -1); +} + +static const VMStateDescription vmstate_m25p80 = { + .name = "xilinx_spi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = m25p80_pre_save, + .fields = (VMStateField[]) { + VMSTATE_UINT8(state, Flash), + VMSTATE_UINT8_ARRAY(data, Flash, 16), + VMSTATE_UINT32(len, Flash), + VMSTATE_UINT32(pos, Flash), + VMSTATE_UINT8(needed_bytes, Flash), + VMSTATE_UINT8(cmd_in_progress, Flash), + VMSTATE_UINT64(cur_addr, Flash), + VMSTATE_BOOL(write_enable, Flash), + VMSTATE_END_OF_LIST() + } +}; + +static Property m25p80_properties[] = { + DEFINE_PROP_STRING("partname", Flash, part_name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void m25p80_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = m25p80_init; + k->transfer = m25p80_transfer8; + k->set_cs = m25p80_cs; + k->cs_polarity = SSI_CS_LOW; + dc->props = m25p80_properties; + dc->vmsd = &vmstate_m25p80; +} + +static const TypeInfo m25p80_info = { + .name = "m25p80", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(Flash), + .class_init = m25p80_class_init, +}; + +static void m25p80_register_types(void) +{ + type_register_static(&m25p80_info); +} + +type_init(m25p80_register_types) diff --git a/hw/max111x.c b/hw/max111x.c index 706d89f4f..67640f109 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -99,10 +99,11 @@ static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) static const VMStateDescription vmstate_max111x = { .name = "max111x", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, MAX111xState), VMSTATE_UINT8(tb1, MAX111xState), VMSTATE_UINT8(rb2, MAX111xState), VMSTATE_UINT8(rb3, MAX111xState), diff --git a/hw/megasas.c b/hw/megasas.c index c728aea69..0e57740fd 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -652,7 +652,6 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size) } } cmd->iov_size = 0; - return; } static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index 274d2c543..3028e651c 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -1,6 +1,7 @@ obj-y = petalogix_s3adsp1800_mmu.o obj-y += petalogix_ml605_mmu.o obj-y += microblaze_boot.o +obj-y += xilinx_spi.o obj-y += microblaze_pic_cpu.o obj-y += xilinx_ethlite.o diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 38e4b8615..d4a8672f2 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -392,7 +392,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, network_init(); } -QEMUMachine mips_fulong2e_machine = { +static QEMUMachine mips_fulong2e_machine = { .name = "fulong2e", .desc = "Fulong 2e mini pc", .init = mips_fulong2e_init, diff --git a/hw/mips_malta.c b/hw/mips_malta.c index ad23f26e5..632b466e3 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -33,7 +33,6 @@ #include "mips.h" #include "mips_cpudevs.h" #include "pci.h" -#include "vmware_vga.h" #include "qemu-char.h" #include "sysemu.h" #include "arch_init.h" @@ -48,7 +47,6 @@ #include "blockdev.h" #include "exec-memory.h" #include "sysbus.h" /* SysBusDevice */ -#include "vga-pci.h" //#define DEBUG_BOARD_INIT @@ -987,13 +985,7 @@ void mips_malta_init (ram_addr_t ram_size, network_init(); /* Optional PCI video card */ - if (cirrus_vga_enabled) { - pci_cirrus_vga_init(pci_bus); - } else if (vmsvga_enabled) { - pci_vmsvga_init(pci_bus); - } else if (std_vga_enabled) { - pci_vga_init(pci_bus); - } + pci_vga_init(pci_bus); } static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev) @@ -366,7 +366,6 @@ void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) g_free(dev->msix_entry_used); dev->msix_entry_used = NULL; dev->cap_present &= ~QEMU_PCI_CAP_MSIX; - return; } void msix_uninit_exclusive_bar(PCIDevice *dev) @@ -27,7 +27,6 @@ #include "fdc.h" #include "ide.h" #include "pci.h" -#include "vmware_vga.h" #include "monitor.h" #include "fw_cfg.h" #include "hpet_emul.h" @@ -51,7 +50,6 @@ #include "exec-memory.h" #include "arch_init.h" #include "bitmap.h" -#include "vga-pci.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -992,34 +990,13 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) { DeviceState *dev = NULL; - if (cirrus_vga_enabled) { - if (pci_bus) { - dev = pci_cirrus_vga_init(pci_bus); - } else { - dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev; - } - } else if (vmsvga_enabled) { - if (pci_bus) { - dev = pci_vmsvga_init(pci_bus); - } else { - fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); - } -#ifdef CONFIG_SPICE - } else if (qxl_enabled) { - if (pci_bus) { - dev = &pci_create_simple(pci_bus, -1, "qxl-vga")->qdev; - } else { - fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__); - } -#endif - } else if (std_vga_enabled) { - if (pci_bus) { - dev = pci_vga_init(pci_bus); - } else { - dev = isa_vga_init(isa_bus); - } + if (pci_bus) { + PCIDevice *pcidev = pci_vga_init(pci_bus); + dev = pcidev ? &pcidev->qdev : NULL; + } else if (isa_bus) { + ISADevice *isadev = isa_vga_init(isa_bus); + dev = isadev ? &isadev->qdev : NULL; } - return dev; } @@ -176,19 +176,6 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; -static inline DeviceState *isa_vga_init(ISABus *bus) -{ - ISADevice *dev; - - dev = isa_try_create(bus, "isa-vga"); - if (!dev) { - fprintf(stderr, "Warning: isa-vga not available\n"); - return NULL; - } - qdev_init_nofail(&dev->qdev); - return &dev->qdev; -} - int isa_vga_mm_init(target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, int it_shift, MemoryRegion *address_space); @@ -1474,6 +1474,24 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, return res; } +PCIDevice *pci_vga_init(PCIBus *bus) +{ + switch (vga_interface_type) { + case VGA_CIRRUS: + return pci_create_simple(bus, -1, "cirrus-vga"); + case VGA_QXL: + return pci_create_simple(bus, -1, "qxl-vga"); + case VGA_STD: + return pci_create_simple(bus, -1, "VGA"); + case VGA_VMWARE: + return pci_create_simple(bus, -1, "vmware-svga"); + case VGA_NONE: + default: /* Other non-PCI types. Checking for unsupported types is already + done in vl.c. */ + return NULL; + } +} + /* Whether a given bus number is in range of the secondary * bus of the given bridge device. */ static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) @@ -334,6 +334,9 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr); PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, const char *default_devaddr); + +PCIDevice *pci_vga_init(PCIBus *bus); + int pci_bus_num(PCIBus *s); void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index dced648f4..b9bfbed4c 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -36,6 +36,7 @@ #include "blockdev.h" #include "pc.h" #include "exec-memory.h" +#include "ssi.h" #include "microblaze_boot.h" #include "microblaze_pic_cpu.h" @@ -47,6 +48,8 @@ #define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb" +#define NUM_SPI_FLASHES 4 + #define MEMORY_BASEADDR 0x50000000 #define FLASH_BASEADDR 0x86000000 #define INTC_BASEADDR 0x81800000 @@ -79,6 +82,7 @@ petalogix_ml605_init(ram_addr_t ram_size, MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev, *dma, *eth0; MicroBlazeCPU *cpu; + SysBusDevice *busdev; CPUMBState *env; DriveInfo *dinfo; int i; @@ -139,6 +143,29 @@ petalogix_ml605_init(ram_addr_t ram_size, xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0], 100 * 1000000); + { + SSIBus *spi; + + dev = qdev_create(NULL, "xlnx.xps-spi"); + qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0x40a00000); + sysbus_connect_irq(busdev, 0, irq[4]); + + spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); + + for (i = 0; i < NUM_SPI_FLASHES; i++) { + qemu_irq cs_line; + + dev = ssi_create_slave_no_init(spi, "m25p80"); + qdev_prop_set_string(dev, "partname", "n25q128"); + qdev_init_nofail(dev); + cs_line = qdev_get_gpio_in(dev, 0); + sysbus_connect_irq(busdev, i+1, cs_line); + } + } + microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, machine_cpu_reset); diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 855890d1f..3b437da9c 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -442,7 +442,6 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, pfl->bypass = 0; pfl->wcycle = 0; pfl->cmd = 0; - return; } diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 8cb154958..39337ec30 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -474,7 +474,6 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, do_bypass: pfl->wcycle = 2; pfl->cmd = 0; - return; } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 6f0de6d95..d23f9b2f6 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -36,7 +36,7 @@ #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define UIMAGE_LOAD_BASE 0 -#define DTC_LOAD_PAD 0x500000 +#define DTC_LOAD_PAD 0x1800000 #define DTC_PAD_MASK 0xFFFFF #define INITRD_LOAD_PAD 0x2000000 #define INITRD_PAD_MASK 0xFFFFFF @@ -139,12 +139,10 @@ static int ppce500_load_device_tree(CPUPPCState *env, 0x0, 0x10000, }; QemuOpts *machine_opts; - const char *dumpdtb = NULL; const char *dtb_file = NULL; machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); if (machine_opts) { - dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); dtb_file = qemu_opt_get(machine_opts, "dtb"); toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); } @@ -334,18 +332,7 @@ static int ppce500_load_device_tree(CPUPPCState *env, } done: - if (dumpdtb) { - /* Dump the dtb to a file and quit */ - FILE *f = fopen(dumpdtb, "wb"); - size_t len; - len = fwrite(fdt, fdt_size, 1, f); - fclose(f); - if (len != fdt_size) { - exit(1); - } - exit(0); - } - + qemu_devtree_dumpdtb(fdt, fdt_size); ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; @@ -375,6 +362,10 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env) the device tree top */ dt_end = bi->dt_base + bi->dt_size; ps = booke206_page_size_to_tlb(dt_end) + 1; + if (ps & 1) { + /* e500v2 can only do even TLB size bits */ + ps++; + } size = (ps << MAS1_TSIZE_SHIFT); tlb->mas1 = MAS1_VALID | size; tlb->mas2 = 0; @@ -553,7 +544,8 @@ void ppce500_init(PPCE500Params *params) /* Load initrd. */ if (params->initrd_filename) { - initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; + initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) & + ~INITRD_PAD_MASK; initrd_size = load_image_targphys(params->initrd_filename, initrd_base, ram_size - initrd_base); diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 89e5013b5..b52ab2f17 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -191,7 +191,8 @@ enum { typedef struct ppc4xx_pob_t ppc4xx_pob_t; struct ppc4xx_pob_t { uint32_t bear; - uint32_t besr[2]; + uint32_t besr0; + uint32_t besr1; }; static uint32_t dcr_read_pob (void *opaque, int dcrn) @@ -205,8 +206,10 @@ static uint32_t dcr_read_pob (void *opaque, int dcrn) ret = pob->bear; break; case POB0_BESR0: + ret = pob->besr0; + break; case POB0_BESR1: - ret = pob->besr[dcrn - POB0_BESR0]; + ret = pob->besr1; break; default: /* Avoid gcc warning */ @@ -227,9 +230,12 @@ static void dcr_write_pob (void *opaque, int dcrn, uint32_t val) /* Read only */ break; case POB0_BESR0: + /* Write-clear */ + pob->besr0 &= ~val; + break; case POB0_BESR1: /* Write-clear */ - pob->besr[dcrn - POB0_BESR0] &= ~val; + pob->besr1 &= ~val; break; } } @@ -241,8 +247,8 @@ static void ppc4xx_pob_reset (void *opaque) pob = opaque; /* No error */ pob->bear = 0x00000000; - pob->besr[0] = 0x0000000; - pob->besr[1] = 0x0000000; + pob->besr0 = 0x0000000; + pob->besr1 = 0x0000000; } static void ppc4xx_pob_init(CPUPPCState *env) diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index e95cfe831..b8d3c9c98 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -67,7 +67,6 @@ #include "hw/usb.h" #include "blockdev.h" #include "exec-memory.h" -#include "vga-pci.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 1dcd8a6c3..2c4a47813 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -43,7 +43,6 @@ #include "kvm_ppc.h" #include "blockdev.h" #include "exec-memory.h" -#include "vga-pci.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 592b7b255..15444303e 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -39,7 +39,6 @@ #include "blockdev.h" #include "arch_init.h" #include "exec-memory.h" -#include "vga-pci.h" //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 59db02584..1a997c9c8 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -172,7 +172,6 @@ static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode) kp->kpc |= KPC_MI; qemu_irq_raise(kp->irq); } - return; } static uint64_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset, @@ -34,7 +34,6 @@ int qdev_hotplug = 0; static bool qdev_hot_added = false; static bool qdev_hot_removed = false; -/* Register a new device type. */ const VMStateDescription *qdev_get_vmsd(DeviceState *dev) { DeviceClass *dc = DEVICE_GET_CLASS(dev); @@ -52,11 +51,6 @@ const char *qdev_fw_name(DeviceState *dev) return object_get_typename(OBJECT(dev)); } -bool qdev_exists(const char *name) -{ - return !!object_class_by_name(name); -} - static void qdev_property_add_legacy(DeviceState *dev, Property *prop, Error **errp); @@ -291,9 +285,9 @@ BusState *qdev_get_parent_bus(DeviceState *dev) void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) { - assert(dev->num_gpio_in == 0); - dev->num_gpio_in = n; - dev->gpio_in = qemu_allocate_irqs(handler, dev, n); + dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler, + dev, n); + dev->num_gpio_in += n; } void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) @@ -153,7 +153,6 @@ typedef struct GlobalProperty { DeviceState *qdev_create(BusState *bus, const char *name); DeviceState *qdev_try_create(BusState *bus, const char *name); -bool qdev_exists(const char *name); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; @@ -822,7 +822,6 @@ static void complete (SB16State *s) ldebug ("\n"); s->cmd = -1; - return; } static void legacy_reset (SB16State *s) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 99bb02ebf..1b0afa635 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1437,7 +1437,6 @@ invalid_param_len: invalid_field: scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); - return; } static inline bool check_lba_range(SCSIDiskState *s, @@ -1535,7 +1534,6 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) invalid_param_len: scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); - return; } static void scsi_disk_emulate_write_data(SCSIRequest *req) diff --git a/hw/spapr.c b/hw/spapr.c index c34b767c6..09b8e9922 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -46,7 +46,6 @@ #include "kvm.h" #include "kvm_ppc.h" #include "pci.h" -#include "vga-pci.h" #include "exec-memory.h" #include "hw/usb.h" @@ -85,9 +84,11 @@ #define PHANDLE_XICP 0x00001111 +#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) + sPAPREnvironment *spapr; -int spapr_allocate_irq(int hint, enum xics_irq_type type) +int spapr_allocate_irq(int hint, bool lsi) { int irq; @@ -103,13 +104,13 @@ int spapr_allocate_irq(int hint, enum xics_irq_type type) return 0; } - xics_set_irq_type(spapr->icp, irq, type); + xics_set_irq_type(spapr->icp, irq, lsi); return irq; } /* Allocate block of consequtive IRQs, returns a number of the first */ -int spapr_allocate_irq_block(int num, enum xics_irq_type type) +int spapr_allocate_irq_block(int num, bool lsi) { int first = -1; int i; @@ -117,7 +118,7 @@ int spapr_allocate_irq_block(int num, enum xics_irq_type type) for (i = 0; i < num; ++i) { int irq; - irq = spapr_allocate_irq(0, type); + irq = spapr_allocate_irq(0, lsi); if (!irq) { return -1; } @@ -134,12 +135,13 @@ int spapr_allocate_irq_block(int num, enum xics_irq_type type) return first; } -static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) +static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; CPUPPCState *env; char cpu_model[32]; int smt = kvmppc_smt_threads(); + uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; assert(spapr->cpu_model); @@ -163,8 +165,16 @@ static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) return offset; } - ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, - sizeof(associativity)); + if (nb_numa_nodes > 1) { + ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, + sizeof(associativity)); + if (ret < 0) { + return ret; + } + } + + ret = fdt_setprop(fdt, offset, "ibm,pft-size", + pft_size_prop, sizeof(pft_size_prop)); if (ret < 0) { return ret; } @@ -206,45 +216,36 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, return (p - prop) * sizeof(uint32_t); } +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + + static void *spapr_create_fdt_skel(const char *cpu_model, - target_phys_addr_t rma_size, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, target_phys_addr_t kernel_size, const char *boot_device, - const char *kernel_cmdline, - long hash_shift) + const char *kernel_cmdline) { void *fdt; CPUPPCState *env; - uint64_t mem_reg_property[2]; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); - uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; char qemu_hypertas_prop[] = "hcall-memop1"; + uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; - int i; char *modelname; - int smt = kvmppc_smt_threads(); + int i, smt = kvmppc_smt_threads(); unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; - uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; - uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), - cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(0x0)}; - char mem_name[32]; - target_phys_addr_t node0_size, mem_start; - -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) fdt = g_malloc0(FDT_MAX_SIZE); _FDT((fdt_create(fdt, FDT_MAX_SIZE))); @@ -289,55 +290,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); - /* memory node(s) */ - node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; - if (rma_size > node0_size) { - rma_size = node0_size; - } - - /* RMA */ - mem_reg_property[0] = 0; - mem_reg_property[1] = cpu_to_be64(rma_size); - _FDT((fdt_begin_node(fdt, "memory@0"))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - - /* RAM: Node 0 */ - if (node0_size > rma_size) { - mem_reg_property[0] = cpu_to_be64(rma_size); - mem_reg_property[1] = cpu_to_be64(node0_size - rma_size); - - sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size); - _FDT((fdt_begin_node(fdt, mem_name))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - } - - /* RAM: Node 1 and beyond */ - mem_start = node0_size; - for (i = 1; i < nb_numa_nodes; i++) { - mem_reg_property[0] = cpu_to_be64(mem_start); - mem_reg_property[1] = cpu_to_be64(node_mem[i]); - associativity[3] = associativity[4] = cpu_to_be32(i); - sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); - _FDT((fdt_begin_node(fdt, mem_name))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - mem_start += node_mem[i]; - } - /* cpus */ _FDT((fdt_begin_node(fdt, "cpus"))); @@ -389,8 +341,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); - _FDT((fdt_property(fdt, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); @@ -489,6 +439,68 @@ static void *spapr_create_fdt_skel(const char *cpu_model, return fdt; } +static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) +{ + uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), + cpu_to_be32(0x0), cpu_to_be32(0x0), + cpu_to_be32(0x0)}; + char mem_name[32]; + target_phys_addr_t node0_size, mem_start; + uint64_t mem_reg_property[2]; + int i, off; + + /* memory node(s) */ + node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + if (spapr->rma_size > node0_size) { + spapr->rma_size = node0_size; + } + + /* RMA */ + mem_reg_property[0] = 0; + mem_reg_property[1] = cpu_to_be64(spapr->rma_size); + off = fdt_add_subnode(fdt, 0, "memory@0"); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + + /* RAM: Node 0 */ + if (node0_size > spapr->rma_size) { + mem_reg_property[0] = cpu_to_be64(spapr->rma_size); + mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size); + + sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + } + + /* RAM: Node 1 and beyond */ + mem_start = node0_size; + for (i = 1; i < nb_numa_nodes; i++) { + mem_reg_property[0] = cpu_to_be64(mem_start); + mem_reg_property[1] = cpu_to_be64(node_mem[i]); + associativity[3] = associativity[4] = cpu_to_be32(i); + sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + mem_start += node_mem[i]; + } + + return 0; +} + static void spapr_finalize_fdt(sPAPREnvironment *spapr, target_phys_addr_t fdt_addr, target_phys_addr_t rtas_addr, @@ -503,6 +515,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, /* open out the base tree into a temp buffer for the final tweaks */ _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); + ret = spapr_populate_memory(spapr, fdt); + if (ret < 0) { + fprintf(stderr, "couldn't setup memory nodes in fdt\n"); + exit(1); + } + ret = spapr_populate_vdevice(spapr->vio_bus, fdt); if (ret < 0) { fprintf(stderr, "couldn't setup vio devices in fdt\n"); @@ -525,11 +543,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, } /* Advertise NUMA via ibm,associativity */ - if (nb_numa_nodes > 1) { - ret = spapr_set_associativity(fdt, spapr); - if (ret < 0) { - fprintf(stderr, "Couldn't set up NUMA device tree properties\n"); - } + ret = spapr_fixup_cpu_dt(fdt, spapr); + if (ret < 0) { + fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); } if (!spapr->has_graphics) { @@ -556,15 +572,49 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) static void emulate_spapr_hypercall(CPUPPCState *env) { - env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); + if (msr_pr) { + hcall_dprintf("Hypercall made with MSR[PR]=1\n"); + env->gpr[3] = H_PRIVILEGE; + } else { + env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); + } } -static void spapr_reset(void *opaque) +static void spapr_reset_htab(sPAPREnvironment *spapr) { - sPAPREnvironment *spapr = (sPAPREnvironment *)opaque; + long shift; + + /* allocate hash page table. For now we always make this 16mb, + * later we should probably make it scale to the size of guest + * RAM */ + + shift = kvmppc_reset_htab(spapr->htab_shift); - /* flush out the hash table */ - memset(spapr->htab, 0, spapr->htab_size); + if (shift > 0) { + /* Kernel handles htab, we don't need to allocate one */ + spapr->htab_shift = shift; + } else { + if (!spapr->htab) { + /* Allocate an htab if we don't yet have one */ + spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr)); + } + + /* And clear it */ + memset(spapr->htab, 0, HTAB_SIZE(spapr)); + } + + /* Update the RMA size if necessary */ + if (spapr->vrma_adjust) { + spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); + } +} + +static void ppc_spapr_reset(void) +{ + /* Reset the hash table & recalc the RMA */ + spapr_reset_htab(spapr); + + qemu_devices_reset(); /* Load the fdt */ spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, @@ -581,19 +631,31 @@ static void spapr_reset(void *opaque) static void spapr_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; cpu_reset(CPU(cpu)); + + /* All CPUs start halted. CPU0 is unhalted from the machine level + * reset code and the rest are explicitly started up by the guest + * using an RTAS call */ + env->halted = 1; + + env->spr[SPR_HIOR] = 0; + + env->external_htab = spapr->htab; + env->htab_base = -1; + env->htab_mask = HTAB_SIZE(spapr) - 1; + env->spr[SPR_SDR1] = (unsigned long)spapr->htab | + (spapr->htab_shift - 18); } /* Returns whether we want to use VGA or not */ static int spapr_vga_init(PCIBus *pci_bus) { switch (vga_interface_type) { - case VGA_STD: - pci_vga_init(pci_bus); - return 1; case VGA_NONE: - return 0; + case VGA_STD: + return pci_vga_init(pci_bus) != NULL; default: fprintf(stderr, "This vga model is not supported," "currently it only supports -vga std\n"); @@ -616,11 +678,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, int i; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - target_phys_addr_t rma_alloc_size, rma_size; + target_phys_addr_t rma_alloc_size; uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, rtas_limit, fw_size; - long pteg_shift = 17; char *filename; msi_supported = true; @@ -637,20 +698,46 @@ static void ppc_spapr_init(ram_addr_t ram_size, hw_error("qemu: Unable to create RMA\n"); exit(1); } + if (rma_alloc_size && (rma_alloc_size < ram_size)) { - rma_size = rma_alloc_size; + spapr->rma_size = rma_alloc_size; } else { - rma_size = ram_size; + spapr->rma_size = ram_size; + + /* With KVM, we don't actually know whether KVM supports an + * unbounded RMA (PR KVM) or is limited by the hash table size + * (HV KVM using VRMA), so we always assume the latter + * + * In that case, we also limit the initial allocations for RTAS + * etc... to 256M since we have no way to know what the VRMA size + * is going to be as it depends on the size of the hash table + * isn't determined yet. + */ + if (kvm_enabled()) { + spapr->vrma_adjust = 1; + spapr->rma_size = MIN(spapr->rma_size, 0x10000000); + } } /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(rma_size, 0x80000000); + rtas_limit = MIN(spapr->rma_size, 0x80000000); spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; load_limit = spapr->fdt_addr - FW_OVERHEAD; + /* We aim for a hash table of size 1/128 the size of RAM. The + * normal rule of thumb is 1/64 the size of RAM, but that's much + * more than needed for the Linux guests we support. */ + spapr->htab_shift = 18; /* Minimum architected size */ + while (spapr->htab_shift <= 46) { + if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) { + break; + } + spapr->htab_shift++; + } + /* init CPUs */ if (cpu_model == NULL) { cpu_model = kvm_enabled() ? "host" : "POWER7"; @@ -665,11 +752,16 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); - qemu_register_reset(spapr_cpu_reset, cpu); - env->hreset_vector = 0x60; + /* PAPR always has exception vectors in RAM not ROM */ env->hreset_excp_prefix = 0; - env->gpr[3] = env->cpu_index; + + /* Tell KVM that we're in PAPR mode */ + if (kvm_enabled()) { + kvmppc_set_papr(env); + } + + qemu_register_reset(spapr_cpu_reset, cpu); } /* allocate RAM */ @@ -683,27 +775,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, memory_region_add_subregion(sysmem, nonrma_base, ram); } - /* allocate hash page table. For now we always make this 16mb, - * later we should probably make it scale to the size of guest - * RAM */ - spapr->htab_size = 1ULL << (pteg_shift + 7); - spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size); - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->external_htab = spapr->htab; - env->htab_base = -1; - env->htab_mask = spapr->htab_size - 1; - - /* Tell KVM that we're in PAPR mode */ - env->spr[SPR_SDR1] = (unsigned long)spapr->htab | - ((pteg_shift + 7) - 18); - env->spr[SPR_HIOR] = 0; - - if (kvm_enabled()) { - kvmppc_set_papr(env); - } - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, rtas_limit - spapr->rtas_addr); @@ -776,7 +847,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } - if (rma_size < (MIN_RMA_SLOF << 20)) { + if (spapr->rma_size < (MIN_RMA_SLOF << 20)) { fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); exit(1); @@ -827,26 +898,19 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->entry_point = 0x100; - /* SLOF will startup the secondary CPUs using RTAS */ - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->halted = 1; - } - /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, initrd_base, initrd_size, kernel_size, - boot_device, kernel_cmdline, - pteg_shift + 7); + boot_device, kernel_cmdline); assert(spapr->fdt_skel != NULL); - - qemu_register_reset(spapr_reset, spapr); } static QEMUMachine spapr_machine = { .name = "pseries", .desc = "pSeries Logical Partition (PAPR compliant)", .init = ppc_spapr_init, + .reset = ppc_spapr_reset, .max_cpus = MAX_CPUS, .no_parallel = 1, .use_scsi = 1, diff --git a/hw/spapr.h b/hw/spapr.h index ac34a171e..e984e3fc3 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -15,7 +15,9 @@ typedef struct sPAPREnvironment { target_phys_addr_t ram_limit; void *htab; - long htab_size; + long htab_shift; + target_phys_addr_t rma_size; + int vrma_adjust; target_phys_addr_t fdt_addr, rtas_addr; long rtas_size; void *fdt_skel; @@ -289,17 +291,17 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, target_ulong *args); -int spapr_allocate_irq(int hint, enum xics_irq_type type); -int spapr_allocate_irq_block(int num, enum xics_irq_type type); +int spapr_allocate_irq(int hint, bool lsi); +int spapr_allocate_irq_block(int num, bool lsi); static inline int spapr_allocate_msi(int hint) { - return spapr_allocate_irq(hint, XICS_MSI); + return spapr_allocate_irq(hint, false); } static inline int spapr_allocate_lsi(int hint) { - return spapr_allocate_irq(hint, XICS_LSI); + return spapr_allocate_irq(hint, true); } static inline uint32_t rtas_ld(target_ulong phys, int n) @@ -336,6 +338,8 @@ typedef struct sPAPRTCE { void spapr_iommu_init(void); DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size); void spapr_tce_free(DMAContext *dma); +void spapr_tce_reset(DMAContext *dma); +void spapr_tce_set_bypass(DMAContext *dma, bool bypass); int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size); int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index abd847f96..194d9c24b 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -39,22 +39,6 @@ #define HPTE_V_1TB_SEG 0x4000000000000000ULL #define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL -#define HPTE_V_HVLOCK 0x40ULL - -static inline int lock_hpte(void *hpte, target_ulong bits) -{ - uint64_t pteh; - - pteh = ldq_p(hpte); - - /* We're protected by qemu's global lock here */ - if (pteh & bits) { - return 0; - } - stq_p(hpte, pteh | HPTE_V_HVLOCK); - return 1; -} - static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, target_ulong pte_index) { @@ -151,8 +135,7 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, if (i == 8) { return H_PTEG_FULL; } - if (((ldq_p(hpte) & HPTE_V_VALID) == 0) && - lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + if ((ldq_p(hpte) & HPTE_V_VALID) == 0) { break; } hpte += HASH_PTE_SIZE_64; @@ -160,7 +143,7 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, } else { i = 0; hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + if (ldq_p(hpte) & HPTE_V_VALID) { return H_PTEG_FULL; } } @@ -168,7 +151,6 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, /* eieio(); FIXME: need some sort of barrier for smp? */ stq_p(hpte, pteh); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); args[0] = pte_index + i; return H_SUCCESS; } @@ -193,11 +175,6 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, } hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { - /* We have no real concurrency in qemu soft-emulation, so we - * will never actually have a contested lock */ - assert(0); - } v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); @@ -205,16 +182,13 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, if ((v & HPTE_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || ((flags & H_ANDCOND) && (v & avpn) != 0)) { - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return REMOVE_NOT_FOUND; } - *vp = v & ~HPTE_V_HVLOCK; + *vp = v; *rp = r; stq_p(hpte, 0); rb = compute_tlbie_rb(v, r, ptex); ppc_tlb_invalidate_one(env, rb); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return REMOVE_SUCCESS; } @@ -324,19 +298,12 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr, } hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { - /* We have no real concurrency in qemu soft-emulation, so we - * will never actually have a contested lock */ - assert(0); - } v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); if ((v & HPTE_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return H_NOT_FOUND; } @@ -350,8 +317,7 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr, ppc_tlb_invalidate_one(env, rb); stq_p(hpte + (HASH_PTE_SIZE_64/2), r); /* Don't need a memory barrier, due to qemu's global lock */ - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + stq_p(hpte, v); return H_SUCCESS; } @@ -544,6 +510,8 @@ static target_ulong h_cede(CPUPPCState *env, sPAPREnvironment *spapr, hreg_compute_hflags(env); if (!cpu_has_work(env)) { env->halted = 1; + env->exception_index = EXCP_HLT; + env->exit_request = 1; } return H_SUCCESS; } @@ -713,11 +681,6 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, target_ulong *args) { - if (msr_pr) { - hcall_dprintf("Hypercall made with MSR[PR]=1\n"); - return H_PRIVILEGE; - } - if ((opcode <= MAX_HCALL_OPCODE) && ((opcode & 0x3) == 0)) { spapr_hcall_fn fn = papr_hypercall_table[opcode / 4]; diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index 53b731773..38034c07b 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -42,6 +42,7 @@ struct sPAPRTCETable { uint32_t liobn; uint32_t window_size; sPAPRTCE *table; + bool bypass; int fd; QLIST_ENTRY(sPAPRTCETable) list; }; @@ -78,6 +79,12 @@ static int spapr_tce_translate(DMAContext *dma, DMA_ADDR_FMT "\n", tcet->liobn, addr); #endif + if (tcet->bypass) { + *paddr = addr; + *len = (target_phys_addr_t)-1; + return 0; + } + /* Check if we are in bound */ if (addr >= tcet->window_size) { #ifdef DEBUG_TCE @@ -162,6 +169,23 @@ void spapr_tce_free(DMAContext *dma) } } +void spapr_tce_set_bypass(DMAContext *dma, bool bypass) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + + tcet->bypass = bypass; +} + +void spapr_tce_reset(DMAContext *dma) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(sPAPRTCE); + + tcet->bypass = false; + memset(tcet->table, 0, table_size); +} + static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, target_ulong tce) { diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 661c05bc3..b628f89a0 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -351,7 +351,7 @@ static void rtas_ibm_change_msi(sPAPREnvironment *spapr, /* There is no cached config, allocate MSIs */ if (!phb->msi_table[ndev].nvec) { - irq = spapr_allocate_irq_block(req_num, XICS_MSI); + irq = spapr_allocate_irq_block(req_num, true); if (irq < 0) { fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev); rtas_st(rets, 0, -1); /* Hardware error */ @@ -595,6 +595,15 @@ static int spapr_phb_init(SysBusDevice *s) return 0; } +static void spapr_phb_reset(DeviceState *qdev) +{ + SysBusDevice *s = sysbus_from_qdev(qdev); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); + + /* Reset the IOMMU state */ + spapr_tce_reset(sphb->dma); +} + static Property spapr_phb_properties[] = { DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0), DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), @@ -613,6 +622,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) sdc->init = spapr_phb_init; dc->props = spapr_phb_properties; + dc->reset = spapr_phb_reset; } static const TypeInfo spapr_phb_info = { diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index ae1859515..b808f8001 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -184,6 +184,11 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, return; } + /* This will make sure qemu state is up to date with kvm, and + * mark it dirty so our changes get flushed back before the + * new cpu enters */ + kvm_cpu_synchronize_state(env); + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); env->nip = start; env->gpr[3] = r3; diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 7ca445216..848806d3f 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -316,17 +316,10 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - if (dev->dma) { - spapr_tce_free(dev->dma); + spapr_tce_reset(dev->dma); } - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); - - dev->crq.qladdr = 0; - dev->crq.qsize = 0; - dev->crq.qnext = 0; + free_crq(dev); } static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, @@ -348,16 +341,14 @@ static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, -3); return; } - if (enable) { - spapr_tce_free(dev->dma); - dev->dma = NULL; - } else { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + if (!dev->dma) { + rtas_st(rets, 0, -3); + return; } + spapr_tce_set_bypass(dev->dma, !!enable); + rtas_st(rets, 0, 0); } @@ -409,9 +400,10 @@ static void spapr_vio_busdev_reset(DeviceState *qdev) VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - if (dev->crq.qsize) { - free_crq(dev); - } + /* Shut down the request queue and TCEs if necessary */ + spapr_vio_quiesce_one(dev); + + dev->signal_state = 0; if (pc->reset) { pc->reset(dev); @@ -422,7 +414,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev) { VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn; char *id; if (dev->reg != -1) { @@ -464,8 +455,10 @@ static int spapr_vio_busdev_init(DeviceState *qdev) return -1; } - liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + if (pc->rtce_window_size) { + uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; + dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + } return pc->init(dev); } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index ea6aa43e2..cc85d2610 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -60,7 +60,6 @@ typedef struct VIOsPAPRDeviceClass { struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; - uint32_t flags; uint32_t irq; target_ulong signal_state; VIOsPAPR_CRQ crq; @@ -132,7 +131,6 @@ void spapr_vscsi_create(VIOsPAPRBus *bus); VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); -int spapr_tce_set_bypass(uint32_t unit, uint32_t enable); void spapr_vio_quiesce(void); #endif /* _HW_SPAPR_VIO_H */ diff --git a/hw/spitz.c b/hw/spitz.c index 20e783519..24346dcd5 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1083,10 +1083,11 @@ static TypeInfo spitz_keyboard_info = { static const VMStateDescription vmstate_corgi_ssp_regs = { .name = "corgi-ssp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), VMSTATE_END_OF_LIST(), } @@ -1115,6 +1116,7 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), VMSTATE_UINT32(bl_intensity, SpitzLCDTG), VMSTATE_UINT32(bl_power, SpitzLCDTG), VMSTATE_END_OF_LIST(), diff --git a/hw/ssd0323.c b/hw/ssd0323.c index b101c5112..9c42d648e 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -279,6 +279,7 @@ static void ssd0323_cd(void *opaque, int n, int level) static void ssd0323_save(QEMUFile *f, void *opaque) { + SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; int i; @@ -296,10 +297,13 @@ static void ssd0323_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->remap); qemu_put_be32(f, s->mode); qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + qemu_put_be32(f, ss->cs); } static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) { + SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; int i; @@ -321,6 +325,8 @@ static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) s->mode = qemu_get_be32(f); qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + ss->cs = qemu_get_be32(f); + return 0; } @@ -348,6 +354,7 @@ static void ssd0323_class_init(ObjectClass *klass, void *data) k->init = ssd0323_init; k->transfer = ssd0323_transfer; + k->cs_polarity = SSI_CS_HIGH; } static TypeInfo ssd0323_info = { diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index b519bdb29..c5505ee24 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -197,6 +197,7 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val) static void ssi_sd_save(QEMUFile *f, void *opaque) { + SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; int i; @@ -209,10 +210,13 @@ static void ssi_sd_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->arglen); qemu_put_be32(f, s->response_pos); qemu_put_be32(f, s->stopping); + + qemu_put_be32(f, ss->cs); } static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) { + SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; int i; @@ -229,6 +233,8 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) s->response_pos = qemu_get_be32(f); s->stopping = qemu_get_be32(f); + ss->cs = qemu_get_be32(f); + return 0; } @@ -250,6 +256,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->init = ssi_sd_init; k->transfer = ssi_sd_transfer; + k->cs_polarity = SSI_CS_LOW; } static TypeInfo ssi_sd_info = { @@ -2,6 +2,8 @@ * QEMU Synchronous Serial Interface support * * Copyright (c) 2009 CodeSourcery. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. * Written by Paul Brook * * This code is licensed under the GNU GPL v2. @@ -25,17 +27,40 @@ static const TypeInfo ssi_bus_info = { .instance_size = sizeof(SSIBus), }; +static void ssi_cs_default(void *opaque, int n, int level) +{ + SSISlave *s = SSI_SLAVE(opaque); + bool cs = !!level; + assert(n == 0); + if (s->cs != cs) { + SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); + if (ssc->set_cs) { + ssc->set_cs(s, cs); + } + } + s->cs = cs; +} + +static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val) +{ + SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev); + + if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) || + (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) || + ssc->cs_polarity == SSI_CS_NONE) { + return ssc->transfer(dev, val); + } + return 0; +} + static int ssi_slave_init(DeviceState *dev) { SSISlave *s = SSI_SLAVE(dev); SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); - SSIBus *bus; - BusChild *kid; - bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev)); - kid = QTAILQ_FIRST(&bus->qbus.children); - if (kid->child != dev || QTAILQ_NEXT(kid, sibling) != NULL) { - hw_error("Too many devices on SSI bus"); + if (ssc->transfer_raw == ssi_transfer_raw_default && + ssc->cs_polarity != SSI_CS_NONE) { + qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1); } return ssc->init(s); @@ -43,9 +68,14 @@ static int ssi_slave_init(DeviceState *dev) static void ssi_slave_class_init(ObjectClass *klass, void *data) { + SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = ssi_slave_init; dc->bus_type = TYPE_SSI_BUS; + if (!ssc->transfer_raw) { + ssc->transfer_raw = ssi_transfer_raw_default; + } } static TypeInfo ssi_slave_info = { @@ -56,10 +86,15 @@ static TypeInfo ssi_slave_info = { .abstract = true, }; +DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name) +{ + return qdev_create(&bus->qbus, name); +} + DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { - DeviceState *dev; - dev = qdev_create(&bus->qbus, name); + DeviceState *dev = ssi_create_slave_no_init(bus, name); + qdev_init_nofail(dev); return dev; } @@ -74,18 +109,29 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name) uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { BusChild *kid; - SSISlave *slave; SSISlaveClass *ssc; + uint32_t r = 0; - kid = QTAILQ_FIRST(&bus->qbus.children); - if (!kid) { - return 0; + QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + SSISlave *slave = SSI_SLAVE(kid->child); + ssc = SSI_SLAVE_GET_CLASS(slave); + r |= ssc->transfer_raw(slave, val); } - slave = SSI_SLAVE(kid->child); - ssc = SSI_SLAVE_GET_CLASS(slave); - return ssc->transfer(slave, val); + + return r; } +const VMStateDescription vmstate_ssi_slave = { + .name = "SSISlave", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(cs, SSISlave), + VMSTATE_END_OF_LIST() + } +}; + static void ssi_slave_register_types(void) { type_register_static(&ssi_bus_info); @@ -93,3 +139,36 @@ static void ssi_slave_register_types(void) } type_init(ssi_slave_register_types) + +typedef struct SSIAutoConnectArg { + qemu_irq **cs_linep; + SSIBus *bus; +} SSIAutoConnectArg; + +static int ssi_auto_connect_slave(Object *child, void *opaque) +{ + SSIAutoConnectArg *arg = opaque; + SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE); + qemu_irq cs_line; + + if (!dev) { + return 0; + } + + cs_line = qdev_get_gpio_in(DEVICE(dev), 0); + qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus); + **arg->cs_linep = cs_line; + (*arg->cs_linep)++; + return 0; +} + +void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line, + SSIBus *bus) +{ + SSIAutoConnectArg arg = { + .cs_linep = &cs_line, + .bus = bus + }; + + object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg); +} @@ -23,28 +23,70 @@ typedef struct SSISlave SSISlave; #define SSI_SLAVE_GET_CLASS(obj) \ OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE) +typedef enum { + SSI_CS_NONE = 0, + SSI_CS_LOW, + SSI_CS_HIGH, +} SSICSMode; + /* Slave devices. */ typedef struct SSISlaveClass { DeviceClass parent_class; int (*init)(SSISlave *dev); + + /* if you have standard or no CS behaviour, just override transfer. + * This is called when the device cs is active (true by default). + */ uint32_t (*transfer)(SSISlave *dev, uint32_t val); + /* called when the CS line changes. Optional, devices only need to implement + * this if they have side effects associated with the cs line (beyond + * tristating the txrx lines). + */ + int (*set_cs)(SSISlave *dev, bool select); + /* define whether or not CS exists and is active low/high */ + SSICSMode cs_polarity; + + /* if you have non-standard CS behaviour override this to take control + * of the CS behaviour at the device level. transfer, set_cs, and + * cs_polarity are unused if this is overwritten. Transfer_raw will + * always be called for the device for every txrx access to the parent bus + */ + uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val); } SSISlaveClass; struct SSISlave { DeviceState qdev; + + /* Chip select state */ + bool cs; }; #define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev) #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev) +extern const VMStateDescription vmstate_ssi_slave; + +#define VMSTATE_SSI_SLAVE(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(SSISlave), \ + .vmsd = &vmstate_ssi_slave, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, SSISlave), \ +} + DeviceState *ssi_create_slave(SSIBus *bus, const char *name); +DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name); /* Master interface. */ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); uint32_t ssi_transfer(SSIBus *bus, uint32_t val); +/* Automatically connect all children nodes a spi controller as slaves */ +void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_lines, + SSIBus *bus); + /* max111x.c */ void max111x_set_input(DeviceState *dev, int line, uint8_t value); diff --git a/hw/stellaris.c b/hw/stellaris.c index 562fbbf49..353ca4c04 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1154,57 +1154,6 @@ static int stellaris_adc_init(SysBusDevice *dev) return 0; } -/* Some boards have both an OLED controller and SD card connected to - the same SSI port, with the SD card chip select connected to a - GPIO pin. Technically the OLED chip select is connected to the SSI - Fss pin. We do not bother emulating that as both devices should - never be selected simultaneously, and our OLED controller ignores stray - 0xff commands that occur when deselecting the SD card. */ - -typedef struct { - SSISlave ssidev; - qemu_irq irq; - int current_dev; - SSIBus *bus[2]; -} stellaris_ssi_bus_state; - -static void stellaris_ssi_bus_select(void *opaque, int irq, int level) -{ - stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; - - s->current_dev = level; -} - -static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val) -{ - stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev); - - return ssi_transfer(s->bus[s->current_dev], val); -} - -static const VMStateDescription vmstate_stellaris_ssi_bus = { - .name = "stellaris_ssi_bus", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(current_dev, stellaris_ssi_bus_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_ssi_bus_init(SSISlave *dev) -{ - stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev); - - s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); - s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); - qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1); - - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s); - return 0; -} - /* Board init. */ static stellaris_board_info stellaris_boards[] = { { "LM3S811EVB", @@ -1305,19 +1254,25 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (1 << 4)) { dev = sysbus_create_simple("pl022", 0x40008000, pic[7]); if (board->peripherals & BP_OLED_SSI) { - DeviceState *mux; void *bus; - + DeviceState *sddev; + DeviceState *ssddev; + + /* Some boards have both an OLED controller and SD card connected to + * the same SSI port, with the SD card chip select connected to a + * GPIO pin. Technically the OLED chip select is connected to the + * SSI Fss pin. We do not bother emulating that as both devices + * should never be selected simultaneously, and our OLED controller + * ignores stray 0xff commands that occur when deselecting the SD + * card. + */ bus = qdev_get_child_bus(dev, "ssi"); - mux = ssi_create_slave(bus, "evb6965-ssi"); - gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0); - - bus = qdev_get_child_bus(mux, "ssi0"); - ssi_create_slave(bus, "ssi-sd"); - bus = qdev_get_child_bus(mux, "ssi1"); - dev = ssi_create_slave(bus, "ssd0323"); - gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0); + sddev = ssi_create_slave(bus, "ssi-sd"); + ssddev = ssi_create_slave(bus, "ssd0323"); + gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0), + qdev_get_gpio_in(ssddev, 0)); + gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1); /* Make sure the select pin is high. */ qemu_irq_raise(gpio_out[GPIO_D][0]); @@ -1394,21 +1349,6 @@ static void stellaris_machine_init(void) machine_init(stellaris_machine_init); -static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data) -{ - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = stellaris_ssi_bus_init; - k->transfer = stellaris_ssi_bus_transfer; -} - -static TypeInfo stellaris_ssi_bus_info = { - .name = "evb6965-ssi", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(stellaris_ssi_bus_state), - .class_init = stellaris_ssi_bus_class_init, -}; - static void stellaris_i2c_class_init(ObjectClass *klass, void *data) { SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); @@ -1456,7 +1396,6 @@ static void stellaris_register_types(void) type_register_static(&stellaris_i2c_info); type_register_static(&stellaris_gptm_info); type_register_static(&stellaris_adc_info); - type_register_static(&stellaris_ssi_bus_info); } type_init(stellaris_register_types) diff --git a/hw/sun4u.c b/hw/sun4u.c index 07cd04273..137a7c666 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -39,7 +39,6 @@ #include "elf.h" #include "blockdev.h" #include "exec-memory.h" -#include "vga-pci.h" //#define DEBUG_IRQ //#define DEBUG_EBUS @@ -472,7 +472,6 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val, default: break; } - return; } static const MemoryRegionOps tcx_dac_ops = { diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 5a0057a36..4389380e9 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -576,7 +576,6 @@ bad_target: */ usb_uas_queue_response(uas, req->tag, UAS_RC_INVALID_INFO_UNIT, 0); g_free(req); - return; } static void usb_uas_task(UASDevice *uas, uas_ui *ui) @@ -640,7 +639,6 @@ bad_target: incorrect_lun: usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0); - return; } static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index c36184ae4..59c7055cb 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1470,8 +1470,6 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) if (old_state != port->ctrl) ohci_set_interrupt(ohci, OHCI_INTR_RHSC); - - return; } static uint64_t ohci_mem_read(void *opaque, diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index e79a8724c..3a41b067c 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -807,7 +807,6 @@ static void xhci_events_update(XHCIState *xhci, int v) DPRINTF("xhci_events_update(): event ring no longer full\n"); intr->er_full = 0; } - return; } static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v) diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 7a9203471..b3f807714 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -211,7 +211,8 @@ static void versatile_init(ram_addr_t ram_size, cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("pl190", 0x10140000, - cpu_pic[0], cpu_pic[1], NULL); + cpu_pic[ARM_PIC_CPU_IRQ], + cpu_pic[ARM_PIC_CPU_FIQ], NULL); for (n = 0; n < 32; n++) { pic[n] = qdev_get_gpio_in(dev, n); } diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 9abbada8f..996d47f23 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -24,7 +24,6 @@ #include "hw.h" #include "console.h" #include "pci.h" -#include "vga-pci.h" #include "vga_int.h" #include "pixel_ops.h" #include "qemu-timer.h" @@ -47,7 +46,7 @@ static const VMStateDescription vmstate_vga_pci = { } }; -static int pci_vga_initfn(PCIDevice *dev) +static int pci_std_vga_initfn(PCIDevice *dev) { PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); VGACommonState *s = &d->vga; @@ -70,11 +69,6 @@ static int pci_vga_initfn(PCIDevice *dev) return 0; } -DeviceState *pci_vga_init(PCIBus *bus) -{ - return &pci_create_simple(bus, -1, "VGA")->qdev; -} - static Property vga_pci_properties[] = { DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), DEFINE_PROP_END_OF_LIST(), @@ -86,7 +80,7 @@ static void vga_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->no_hotplug = 1; - k->init = pci_vga_initfn; + k->init = pci_std_vga_initfn; k->romfile = "vgabios-stdvga.bin"; k->vendor_id = PCI_VENDOR_ID_QEMU; k->device_id = PCI_DEVICE_ID_QEMU_VGA; diff --git a/hw/vga-pci.h b/hw/vga-pci.h deleted file mode 100644 index 49abf1309..000000000 --- a/hw/vga-pci.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef VGA_PCI_H -#define VGA_PCI_H - -#include "qemu-common.h" - -/* vga-pci.c */ -DeviceState *pci_vga_init(PCIBus *bus); - -/* cirrus_vga.c */ -DeviceState *pci_cirrus_vga_init(PCIBus *bus); - -#endif diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index e815a04e9..6f7074e55 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -25,7 +25,6 @@ #include "loader.h" #include "console.h" #include "pci.h" -#include "vmware_vga.h" #undef VERBOSE #define HW_RECT_ACCEL diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h deleted file mode 100644 index 000fbddc0..000000000 --- a/hw/vmware_vga.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef QEMU_VMWARE_VGA_H -#define QEMU_VMWARE_VGA_H - -#include "qemu-common.h" - -/* vmware_vga.c */ -static inline DeviceState *pci_vmsvga_init(PCIBus *bus) -{ - PCIDevice *dev; - - dev = pci_create_simple(bus, -1, "vmware-svga"); - return &dev->qdev; -} - -#endif diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index a6a12e593..db1497469 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -153,7 +153,6 @@ static void xen_domain_poll(void *opaque) quit: qemu_system_shutdown_request(); - return; } static int xen_domain_watcher(void) @@ -165,11 +165,12 @@ struct ics_irq_state { int server; uint8_t priority; uint8_t saved_priority; - enum xics_irq_type type; - int asserted:1; - int sent:1; - int rejected:1; - int masked_pending:1; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; + bool lsi; }; struct ics_state { @@ -191,8 +192,8 @@ static void resend_msi(struct ics_state *ics, int srcno) struct ics_irq_state *irq = ics->irqs + srcno; /* FIXME: filter by server#? */ - if (irq->rejected) { - irq->rejected = 0; + if (irq->status & XICS_STATUS_REJECTED) { + irq->status &= ~XICS_STATUS_REJECTED; if (irq->priority != 0xff) { icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); @@ -204,8 +205,10 @@ static void resend_lsi(struct ics_state *ics, int srcno) { struct ics_irq_state *irq = ics->irqs + srcno; - if ((irq->priority != 0xff) && irq->asserted && !irq->sent) { - irq->sent = 1; + if ((irq->priority != 0xff) + && (irq->status & XICS_STATUS_ASSERTED) + && !(irq->status & XICS_STATUS_SENT)) { + irq->status |= XICS_STATUS_SENT; icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } } @@ -216,7 +219,7 @@ static void set_irq_msi(struct ics_state *ics, int srcno, int val) if (val) { if (irq->priority == 0xff) { - irq->masked_pending = 1; + irq->status |= XICS_STATUS_MASKED_PENDING; /* masked pending */ ; } else { icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); @@ -228,7 +231,11 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val) { struct ics_irq_state *irq = ics->irqs + srcno; - irq->asserted = val; + if (val) { + irq->status |= XICS_STATUS_ASSERTED; + } else { + irq->status &= ~XICS_STATUS_ASSERTED; + } resend_lsi(ics, srcno); } @@ -237,7 +244,7 @@ static void ics_set_irq(void *opaque, int srcno, int val) struct ics_state *ics = (struct ics_state *)opaque; struct ics_irq_state *irq = ics->irqs + srcno; - if (irq->type == XICS_LSI) { + if (irq->lsi) { set_irq_lsi(ics, srcno, val); } else { set_irq_msi(ics, srcno, val); @@ -248,11 +255,12 @@ static void write_xive_msi(struct ics_state *ics, int srcno) { struct ics_irq_state *irq = ics->irqs + srcno; - if (!irq->masked_pending || (irq->priority == 0xff)) { + if (!(irq->status & XICS_STATUS_MASKED_PENDING) + || (irq->priority == 0xff)) { return; } - irq->masked_pending = 0; + irq->status &= ~XICS_STATUS_MASKED_PENDING; icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } @@ -262,15 +270,16 @@ static void write_xive_lsi(struct ics_state *ics, int srcno) } static void ics_write_xive(struct ics_state *ics, int nr, int server, - uint8_t priority) + uint8_t priority, uint8_t saved_priority) { int srcno = nr - ics->offset; struct ics_irq_state *irq = ics->irqs + srcno; irq->server = server; irq->priority = priority; + irq->saved_priority = saved_priority; - if (irq->type == XICS_LSI) { + if (irq->lsi) { write_xive_lsi(ics, srcno); } else { write_xive_msi(ics, srcno); @@ -281,8 +290,8 @@ static void ics_reject(struct ics_state *ics, int nr) { struct ics_irq_state *irq = ics->irqs + nr - ics->offset; - irq->rejected = 1; /* Irrelevant but harmless for LSI */ - irq->sent = 0; /* Irrelevant but harmless for MSI */ + irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ + irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ } static void ics_resend(struct ics_state *ics) @@ -293,7 +302,7 @@ static void ics_resend(struct ics_state *ics) struct ics_irq_state *irq = ics->irqs + i; /* FIXME: filter by server#? */ - if (irq->type == XICS_LSI) { + if (irq->lsi) { resend_lsi(ics, i); } else { resend_msi(ics, i); @@ -306,8 +315,8 @@ static void ics_eoi(struct ics_state *ics, int nr) int srcno = nr - ics->offset; struct ics_irq_state *irq = ics->irqs + srcno; - if (irq->type == XICS_LSI) { - irq->sent = 0; + if (irq->lsi) { + irq->status &= ~XICS_STATUS_SENT; } } @@ -325,14 +334,12 @@ qemu_irq xics_get_qirq(struct icp_state *icp, int irq) return icp->ics->qirqs[irq - icp->ics->offset]; } -void xics_set_irq_type(struct icp_state *icp, int irq, - enum xics_irq_type type) +void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) { assert((irq >= icp->ics->offset) && (irq < (icp->ics->offset + icp->ics->nr_irqs))); - assert((type == XICS_MSI) || (type == XICS_LSI)); - icp->ics->irqs[irq - icp->ics->offset].type = type; + icp->ics->irqs[irq - icp->ics->offset].lsi = lsi; } static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr, @@ -399,7 +406,7 @@ static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, return; } - ics_write_xive(ics, nr, server, priority); + ics_write_xive(ics, nr, server, priority, priority); rtas_st(rets, 0, 0); /* Success */ } @@ -447,14 +454,8 @@ static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, return; } - /* This is a NOP for now, since the described PAPR semantics don't - * seem to gel with what Linux does */ -#if 0 - struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); - - irq->saved_priority = irq->priority; - ics_write_xive_msi(xics, nr, irq->server, 0xff); -#endif + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, + ics->irqs[nr - ics->offset].priority); rtas_st(rets, 0, 0); /* Success */ } @@ -478,22 +479,40 @@ static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, return; } - /* This is a NOP for now, since the described PAPR semantics don't - * seem to gel with what Linux does */ -#if 0 - struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); - - ics_write_xive_msi(xics, nr, irq->server, irq->saved_priority); -#endif + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, + ics->irqs[nr - ics->offset].saved_priority, + ics->irqs[nr - ics->offset].saved_priority); rtas_st(rets, 0, 0); /* Success */ } +static void xics_reset(void *opaque) +{ + struct icp_state *icp = (struct icp_state *)opaque; + struct ics_state *ics = icp->ics; + int i; + + for (i = 0; i < icp->nr_servers; i++) { + icp->ss[i].xirr = 0; + icp->ss[i].pending_priority = 0; + icp->ss[i].mfrr = 0xff; + /* Make all outputs are deasserted */ + qemu_set_irq(icp->ss[i].output, 0); + } + + for (i = 0; i < ics->nr_irqs; i++) { + /* Reset everything *except* the type */ + ics->irqs[i].server = 0; + ics->irqs[i].status = 0; + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } +} + struct icp_state *xics_system_init(int nr_irqs) { CPUPPCState *env; int max_server_num; - int i; struct icp_state *icp; struct ics_state *ics; @@ -508,10 +527,6 @@ struct icp_state *xics_system_init(int nr_irqs) icp->nr_servers = max_server_num + 1; icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); - for (i = 0; i < icp->nr_servers; i++) { - icp->ss[i].mfrr = 0xff; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { struct icp_server_state *ss = &icp->ss[env->cpu_index]; @@ -539,11 +554,6 @@ struct icp_state *xics_system_init(int nr_irqs) icp->ics = ics; ics->icp = icp; - for (i = 0; i < nr_irqs; i++) { - ics->irqs[i].priority = 0xff; - ics->irqs[i].saved_priority = 0xff; - } - ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); spapr_register_hypercall(H_CPPR, h_cppr); @@ -556,5 +566,7 @@ struct icp_state *xics_system_init(int nr_irqs) spapr_rtas_register("ibm,int-off", rtas_int_off); spapr_rtas_register("ibm,int-on", rtas_int_on); + qemu_register_reset(xics_reset, icp); + return icp; } @@ -31,14 +31,8 @@ struct icp_state; -enum xics_irq_type { - XICS_MSI, /* Message-signalled (edge) interrupt */ - XICS_LSI, /* Level-signalled interrupt */ -}; - qemu_irq xics_get_qirq(struct icp_state *icp, int irq); -void xics_set_irq_type(struct icp_state *icp, int irq, - enum xics_irq_type type); +void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi); struct icp_state *xics_system_init(int nr_irqs); diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c new file mode 100644 index 000000000..5cdf967c2 --- /dev/null +++ b/hw/xilinx_spi.c @@ -0,0 +1,385 @@ +/* + * QEMU model of the Xilinx SPI Controller + * + * Copyright (C) 2010 Edgar E. Iglesias. + * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com> + * Copyright (C) 2012 PetaLogix + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "sysemu.h" +#include "qemu-log.h" +#include "fifo.h" + +#include "ssi.h" + +#ifdef XILINX_SPI_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +#define R_DGIER (0x1c / 4) +#define R_DGIER_IE (1 << 31) + +#define R_IPISR (0x20 / 4) +#define IRQ_DRR_NOT_EMPTY (1 << (31 - 23)) +#define IRQ_DRR_OVERRUN (1 << (31 - 26)) +#define IRQ_DRR_FULL (1 << (31 - 27)) +#define IRQ_TX_FF_HALF_EMPTY (1 << 6) +#define IRQ_DTR_UNDERRUN (1 << 3) +#define IRQ_DTR_EMPTY (1 << (31 - 29)) + +#define R_IPIER (0x28 / 4) +#define R_SRR (0x40 / 4) +#define R_SPICR (0x60 / 4) +#define R_SPICR_TXFF_RST (1 << 5) +#define R_SPICR_RXFF_RST (1 << 6) +#define R_SPICR_MTI (1 << 8) + +#define R_SPISR (0x64 / 4) +#define SR_TX_FULL (1 << 3) +#define SR_TX_EMPTY (1 << 2) +#define SR_RX_FULL (1 << 1) +#define SR_RX_EMPTY (1 << 0) + +#define R_SPIDTR (0x68 / 4) +#define R_SPIDRR (0x6C / 4) +#define R_SPISSR (0x70 / 4) +#define R_TX_FF_OCY (0x74 / 4) +#define R_RX_FF_OCY (0x78 / 4) +#define R_MAX (0x7C / 4) + +#define FIFO_CAPACITY 256 + +typedef struct XilinxSPI { + SysBusDevice busdev; + MemoryRegion mmio; + + qemu_irq irq; + int irqline; + + uint8_t num_cs; + qemu_irq *cs_lines; + + SSIBus *spi; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + + uint32_t regs[R_MAX]; +} XilinxSPI; + +static void txfifo_reset(XilinxSPI *s) +{ + fifo8_reset(&s->tx_fifo); + + s->regs[R_SPISR] &= ~SR_TX_FULL; + s->regs[R_SPISR] |= SR_TX_EMPTY; +} + +static void rxfifo_reset(XilinxSPI *s) +{ + fifo8_reset(&s->rx_fifo); + + s->regs[R_SPISR] |= SR_RX_EMPTY; + s->regs[R_SPISR] &= ~SR_RX_FULL; +} + +static void xlx_spi_update_cs(XilinxSPI *s) +{ + int i; + + for (i = 0; i < s->num_cs; ++i) { + qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i)); + } +} + +static void xlx_spi_update_irq(XilinxSPI *s) +{ + uint32_t pending; + + s->regs[R_IPISR] |= + (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) | + (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0); + + pending = s->regs[R_IPISR] & s->regs[R_IPIER]; + + pending = pending && (s->regs[R_DGIER] & R_DGIER_IE); + pending = !!pending; + + /* This call lies right in the data paths so don't call the + irq chain unless things really changed. */ + if (pending != s->irqline) { + s->irqline = pending; + DB_PRINT("irq_change of state %d ISR:%x IER:%X\n", + pending, s->regs[R_IPISR], s->regs[R_IPIER]); + qemu_set_irq(s->irq, pending); + } + +} + +static void xlx_spi_do_reset(XilinxSPI *s) +{ + memset(s->regs, 0, sizeof s->regs); + + rxfifo_reset(s); + txfifo_reset(s); + + s->regs[R_SPISSR] = ~0; + xlx_spi_update_irq(s); + xlx_spi_update_cs(s); +} + +static void xlx_spi_reset(DeviceState *d) +{ + xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d)); +} + +static inline int spi_master_enabled(XilinxSPI *s) +{ + return !(s->regs[R_SPICR] & R_SPICR_MTI); +} + +static void spi_flush_txfifo(XilinxSPI *s) +{ + uint32_t tx; + uint32_t rx; + + while (!fifo8_is_empty(&s->tx_fifo)) { + tx = (uint32_t)fifo8_pop(&s->tx_fifo); + DB_PRINT("data tx:%x\n", tx); + rx = ssi_transfer(s->spi, tx); + DB_PRINT("data rx:%x\n", rx); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_IPISR] |= IRQ_DRR_OVERRUN; + } else { + fifo8_push(&s->rx_fifo, (uint8_t)rx); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_SPISR] |= SR_RX_FULL; + s->regs[R_IPISR] |= IRQ_DRR_FULL; + } + } + + s->regs[R_SPISR] &= ~SR_RX_EMPTY; + s->regs[R_SPISR] &= ~SR_TX_FULL; + s->regs[R_SPISR] |= SR_TX_EMPTY; + + s->regs[R_IPISR] |= IRQ_DTR_EMPTY; + s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY; + } + +} + +static uint64_t +spi_read(void *opaque, target_phys_addr_t addr, unsigned int size) +{ + XilinxSPI *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_SPIDRR: + if (fifo8_is_empty(&s->rx_fifo)) { + DB_PRINT("Read from empty FIFO!\n"); + return 0xdeadbeef; + } + + s->regs[R_SPISR] &= ~SR_RX_FULL; + r = fifo8_pop(&s->rx_fifo); + if (fifo8_is_empty(&s->rx_fifo)) { + s->regs[R_SPISR] |= SR_RX_EMPTY; + } + break; + + case R_SPISR: + r = s->regs[addr]; + break; + + default: + if (addr < ARRAY_SIZE(s->regs)) { + r = s->regs[addr]; + } + break; + + } + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r); + xlx_spi_update_irq(s); + return r; +} + +static void +spi_write(void *opaque, target_phys_addr_t addr, + uint64_t val64, unsigned int size) +{ + XilinxSPI *s = opaque; + uint32_t value = val64; + + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value); + addr >>= 2; + switch (addr) { + case R_SRR: + if (value != 0xa) { + DB_PRINT("Invalid write to SRR %x\n", value); + } else { + xlx_spi_do_reset(s); + } + break; + + case R_SPIDTR: + s->regs[R_SPISR] &= ~SR_TX_EMPTY; + fifo8_push(&s->tx_fifo, (uint8_t)value); + if (fifo8_is_full(&s->tx_fifo)) { + s->regs[R_SPISR] |= SR_TX_FULL; + } + if (!spi_master_enabled(s)) { + goto done; + } else { + DB_PRINT("DTR and master enabled\n"); + } + spi_flush_txfifo(s); + break; + + case R_SPISR: + DB_PRINT("Invalid write to SPISR %x\n", value); + break; + + case R_IPISR: + /* Toggle the bits. */ + s->regs[addr] ^= value; + break; + + /* Slave Select Register. */ + case R_SPISSR: + s->regs[addr] = value; + xlx_spi_update_cs(s); + break; + + case R_SPICR: + /* FIXME: reset irq and sr state to empty queues. */ + if (value & R_SPICR_RXFF_RST) { + rxfifo_reset(s); + } + + if (value & R_SPICR_TXFF_RST) { + txfifo_reset(s); + } + value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST); + s->regs[addr] = value; + + if (!(value & R_SPICR_MTI)) { + spi_flush_txfifo(s); + } + break; + + default: + if (addr < ARRAY_SIZE(s->regs)) { + s->regs[addr] = value; + } + break; + } + +done: + xlx_spi_update_irq(s); +} + +static const MemoryRegionOps spi_ops = { + .read = spi_read, + .write = spi_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static int xilinx_spi_init(SysBusDevice *dev) +{ + int i; + XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev); + + DB_PRINT("\n"); + + s->spi = ssi_create_bus(&dev->qdev, "spi"); + + sysbus_init_irq(dev, &s->irq); + s->cs_lines = g_new(qemu_irq, s->num_cs); + ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi); + for (i = 0; i < s->num_cs; ++i) { + sysbus_init_irq(dev, &s->cs_lines[i]); + } + + memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4); + sysbus_init_mmio(dev, &s->mmio); + + s->irqline = -1; + + fifo8_create(&s->tx_fifo, FIFO_CAPACITY); + fifo8_create(&s->rx_fifo, FIFO_CAPACITY); + + return 0; +} + +static const VMStateDescription vmstate_xilinx_spi = { + .name = "xilinx_spi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_FIFO8(tx_fifo, XilinxSPI), + VMSTATE_FIFO8(rx_fifo, XilinxSPI), + VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static Property xilinx_spi_properties[] = { + DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xilinx_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_spi_init; + dc->reset = xlx_spi_reset; + dc->props = xilinx_spi_properties; + dc->vmsd = &vmstate_xilinx_spi; +} + +static TypeInfo xilinx_spi_info = { + .name = "xlnx.xps-spi", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XilinxSPI), + .class_init = xilinx_spi_class_init, +}; + +static void xilinx_spi_register_types(void) +{ + type_register_static(&xilinx_spi_info); +} + +type_init(xilinx_spi_register_types) diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c new file mode 100644 index 000000000..f64a7828f --- /dev/null +++ b/hw/xilinx_spips.c @@ -0,0 +1,354 @@ +/* + * QEMU model of the Xilinx Zynq SPI controller + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "sysemu.h" +#include "ptimer.h" +#include "qemu-log.h" +#include "fifo.h" +#include "ssi.h" + +#ifdef XILINX_SPIPS_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +/* config register */ +#define R_CONFIG (0x00 / 4) +#define MODEFAIL_GEN_EN (1 << 17) +#define MAN_START_COM (1 << 16) +#define MAN_START_EN (1 << 15) +#define MANUAL_CS (1 << 14) +#define CS (0xF << 10) +#define CS_SHIFT (10) +#define PERI_SEL (1 << 9) +#define REF_CLK (1 << 8) +#define FIFO_WIDTH (3 << 6) +#define BAUD_RATE_DIV (7 << 3) +#define CLK_PH (1 << 2) +#define CLK_POL (1 << 1) +#define MODE_SEL (1 << 0) + +/* interrupt mechanism */ +#define R_INTR_STATUS (0x04 / 4) +#define R_INTR_EN (0x08 / 4) +#define R_INTR_DIS (0x0C / 4) +#define R_INTR_MASK (0x10 / 4) +#define IXR_TX_FIFO_UNDERFLOW (1 << 6) +#define IXR_RX_FIFO_FULL (1 << 5) +#define IXR_RX_FIFO_NOT_EMPTY (1 << 4) +#define IXR_TX_FIFO_FULL (1 << 3) +#define IXR_TX_FIFO_NOT_FULL (1 << 2) +#define IXR_TX_FIFO_MODE_FAIL (1 << 1) +#define IXR_RX_FIFO_OVERFLOW (1 << 0) +#define IXR_ALL ((IXR_TX_FIFO_UNDERFLOW<<1)-1) + +#define R_EN (0x14 / 4) +#define R_DELAY (0x18 / 4) +#define R_TX_DATA (0x1C / 4) +#define R_RX_DATA (0x20 / 4) +#define R_SLAVE_IDLE_COUNT (0x24 / 4) +#define R_TX_THRES (0x28 / 4) +#define R_RX_THRES (0x2C / 4) +#define R_MOD_ID (0xFC / 4) + +#define R_MAX (R_MOD_ID+1) + +/* size of TXRX FIFOs */ +#define NUM_CS_LINES 4 +#define RXFF_A 32 +#define TXFF_A 32 + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq; + int irqline; + + qemu_irq cs_lines[NUM_CS_LINES]; + SSIBus *spi; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + + uint32_t regs[R_MAX]; +} XilinxSPIPS; + +static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) +{ + int i; + bool found = false; + int field = s->regs[R_CONFIG] >> CS_SHIFT; + + for (i = 0; i < NUM_CS_LINES; i++) { + if (~field & (1 << i) && !found) { + found = true; + DB_PRINT("selecting slave %d\n", i); + qemu_set_irq(s->cs_lines[i], 0); + } else { + qemu_set_irq(s->cs_lines[i], 1); + } + } +} + +static void xilinx_spips_update_ixr(XilinxSPIPS *s) +{ + /* These are set/cleared as they occur */ + s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW | + IXR_TX_FIFO_MODE_FAIL); + /* these are pure functions of fifo state, set them here */ + s->regs[R_INTR_STATUS] |= + (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) | + (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) | + (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) | + (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0); + /* drive external interrupt pin */ + int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] & + IXR_ALL); + if (new_irqline != s->irqline) { + s->irqline = new_irqline; + qemu_set_irq(s->irq, s->irqline); + } +} + +static void xilinx_spips_reset(DeviceState *d) +{ + XilinxSPIPS *s = DO_UPCAST(XilinxSPIPS, busdev.qdev, d); + + int i; + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + fifo8_reset(&s->rx_fifo); + fifo8_reset(&s->rx_fifo); + /* non zero resets */ + s->regs[R_CONFIG] |= MODEFAIL_GEN_EN; + s->regs[R_SLAVE_IDLE_COUNT] = 0xFF; + s->regs[R_TX_THRES] = 1; + s->regs[R_RX_THRES] = 1; + /* FIXME: move magic number definition somewhere sensible */ + s->regs[R_MOD_ID] = 0x01090106; + xilinx_spips_update_ixr(s); + xilinx_spips_update_cs_lines(s); +} + +static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) +{ + for (;;) { + uint32_t r; + uint8_t value; + + if (fifo8_is_empty(&s->tx_fifo)) { + s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW; + break; + } else { + value = fifo8_pop(&s->tx_fifo); + } + + r = ssi_transfer(s->spi, (uint32_t)value); + DB_PRINT("tx = %02x rx = %02x\n", value, r); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW; + DB_PRINT("rx FIFO overflow"); + } else { + fifo8_push(&s->rx_fifo, (uint8_t)r); + } + } + xilinx_spips_update_ixr(s); +} + +static uint64_t xilinx_spips_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + XilinxSPIPS *s = opaque; + uint32_t mask = ~0; + uint32_t ret; + + addr >>= 2; + switch (addr) { + case R_CONFIG: + mask = 0x0002FFFF; + break; + case R_INTR_STATUS: + case R_INTR_MASK: + mask = IXR_ALL; + break; + case R_EN: + mask = 0x1; + break; + case R_SLAVE_IDLE_COUNT: + mask = 0xFF; + break; + case R_MOD_ID: + mask = 0x01FFFFFF; + break; + case R_INTR_EN: + case R_INTR_DIS: + case R_TX_DATA: + mask = 0; + break; + case R_RX_DATA: + ret = (uint32_t)fifo8_pop(&s->rx_fifo); + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + xilinx_spips_update_ixr(s); + return ret; + } + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask); + return s->regs[addr] & mask; + +} + +static void xilinx_spips_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) +{ + int mask = ~0; + int man_start_com = 0; + XilinxSPIPS *s = opaque; + + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value); + addr >>= 2; + switch (addr) { + case R_CONFIG: + mask = 0x0002FFFF; + if (value & MAN_START_COM) { + man_start_com = 1; + } + break; + case R_INTR_STATUS: + mask = IXR_ALL; + s->regs[R_INTR_STATUS] &= ~(mask & value); + goto no_reg_update; + case R_INTR_DIS: + mask = IXR_ALL; + s->regs[R_INTR_MASK] &= ~(mask & value); + goto no_reg_update; + case R_INTR_EN: + mask = IXR_ALL; + s->regs[R_INTR_MASK] |= mask & value; + goto no_reg_update; + case R_EN: + mask = 0x1; + break; + case R_SLAVE_IDLE_COUNT: + mask = 0xFF; + break; + case R_RX_DATA: + case R_INTR_MASK: + case R_MOD_ID: + mask = 0; + break; + case R_TX_DATA: + fifo8_push(&s->tx_fifo, (uint8_t)value); + goto no_reg_update; + } + s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask); +no_reg_update: + if (man_start_com) { + xilinx_spips_flush_txfifo(s); + } + xilinx_spips_update_ixr(s); + xilinx_spips_update_cs_lines(s); +} + +static const MemoryRegionOps spips_ops = { + .read = xilinx_spips_read, + .write = xilinx_spips_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int xilinx_spips_init(SysBusDevice *dev) +{ + XilinxSPIPS *s = FROM_SYSBUS(typeof(*s), dev); + int i; + + DB_PRINT("inited device model\n"); + + s->spi = ssi_create_bus(&dev->qdev, "spi"); + + ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi); + sysbus_init_irq(dev, &s->irq); + for (i = 0; i < NUM_CS_LINES; ++i) { + sysbus_init_irq(dev, &s->cs_lines[i]); + } + + memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4); + sysbus_init_mmio(dev, &s->iomem); + + s->irqline = -1; + + fifo8_create(&s->rx_fifo, RXFF_A); + fifo8_create(&s->tx_fifo, TXFF_A); + + return 0; +} + +static int xilinx_spips_post_load(void *opaque, int version_id) +{ + xilinx_spips_update_ixr((XilinxSPIPS *)opaque); + xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque); + return 0; +} + +static const VMStateDescription vmstate_xilinx_spips = { + .name = "xilinx_spips", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = xilinx_spips_post_load, + .fields = (VMStateField[]) { + VMSTATE_FIFO8(tx_fifo, XilinxSPIPS), + VMSTATE_FIFO8(rx_fifo, XilinxSPIPS), + VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static void xilinx_spips_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = xilinx_spips_init; + dc->reset = xilinx_spips_reset; + dc->vmsd = &vmstate_xilinx_spips; +} + +static const TypeInfo xilinx_spips_info = { + .name = "xilinx,spips", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XilinxSPIPS), + .class_init = xilinx_spips_class_init, +}; + +static void xilinx_spips_register_types(void) +{ + type_register_static(&xilinx_spips_info); +} + +type_init(xilinx_spips_register_types) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 7e6c27359..fd46ba252 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -24,6 +24,9 @@ #include "flash.h" #include "blockdev.h" #include "loader.h" +#include "ssi.h" + +#define NUM_SPI_FLASHES 4 #define FLASH_SIZE (64 * 1024 * 1024) #define FLASH_SECTOR_SIZE (128 * 1024) @@ -46,6 +49,34 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) sysbus_connect_irq(s, 0, irq); } +static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq) +{ + DeviceState *dev; + SysBusDevice *busdev; + SSIBus *spi; + int i; + + dev = qdev_create(NULL, "xilinx,spips"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, base_addr); + sysbus_connect_irq(busdev, 0, irq); + + spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); + + for (i = 0; i < NUM_SPI_FLASHES; ++i) { + qemu_irq cs_line; + + dev = ssi_create_slave_no_init(spi, "m25p80"); + qdev_prop_set_string(dev, "partname", "n25q128"); + qdev_init_nofail(dev); + + cs_line = qdev_get_gpio_in(dev, 0); + sysbus_connect_irq(busdev, i+1, cs_line); + } + +} + static void zynq_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -113,6 +144,9 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, pic[n] = qdev_get_gpio_in(dev, n); } + zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET]); + zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET]); + sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); @@ -161,10 +161,11 @@ static int zipit_lcd_init(SSISlave *dev) static VMStateDescription vmstate_zipit_lcd_state = { .name = "zipit-lcd", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), VMSTATE_INT32(selected, ZipitLCD), VMSTATE_INT32(enabled, ZipitLCD), VMSTATE_BUFFER(buf, ZipitLCD), diff --git a/libcacard/vcard.c b/libcacard/vcard.c index b02556ee0..539177bb4 100644 --- a/libcacard/vcard.c +++ b/libcacard/vcard.c @@ -200,7 +200,6 @@ vcard_free(VCard *vcard) } vcard_buffer_response_delete(vcard->vcard_buffer_response); g_free(vcard); - return; } void diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index e1cae5bc5..5f565e0b4 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -168,7 +168,6 @@ vcard_emul_delete_key(VCardKey *key) if (key->slot) { PK11_FreeSlot(key->slot); } - return; } /* @@ -418,7 +417,6 @@ vcard_emul_reset(VCard *card, VCardPower power) /* TODO: we may also need to send insertion/removal events? */ slot = vcard_emul_card_get_slot(card); PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */ - return; } @@ -535,7 +533,6 @@ vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) memcpy(atr, nss_atr, len); *atr_len = len; - return; } /* diff --git a/libcacard/vreader.c b/libcacard/vreader.c index ec126dfa4..96d2407e7 100644 --- a/libcacard/vreader.c +++ b/libcacard/vreader.c @@ -93,7 +93,6 @@ vreader_free(VReader *reader) reader->reader_private_free(reader->reader_private); } g_free(reader); - return; } static VCard * diff --git a/linux-user/signal.c b/linux-user/signal.c index 78691473f..15bc4e8f6 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -2762,7 +2762,6 @@ static void setup_frame(int sig, struct target_sigaction * ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); force_sig(TARGET_SIGSEGV/*, current*/); - return; } long do_sigreturn(CPUMIPSState *regs) @@ -2871,7 +2870,6 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); force_sig(TARGET_SIGSEGV/*, current*/); - return; } long do_rt_sigreturn(CPUMIPSState *env) @@ -898,13 +898,7 @@ static void do_info_registers(Monitor *mon) { CPUArchState *env; env = mon_get_cpu(); -#ifdef TARGET_I386 - cpu_dump_state(env, (FILE *)mon, monitor_fprintf, - X86_DUMP_FPU); -#else - cpu_dump_state(env, (FILE *)mon, monitor_fprintf, - 0); -#endif + cpu_dump_state(env, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU); } static void do_cpu_set_nr(Monitor *mon, const QDict *qdict) diff --git a/os-posix.c b/os-posix.c index f855abb09..488e48005 100644 --- a/os-posix.c +++ b/os-posix.c @@ -193,7 +193,6 @@ void os_parse_cmd_args(int index, const char *optarg) break; #endif } - return; } static void change_process_uid(void) diff --git a/qemu-barrier.h b/qemu-barrier.h index 16f09429c..faa83d265 100644 --- a/qemu-barrier.h +++ b/qemu-barrier.h @@ -6,6 +6,8 @@ #if defined(__i386__) +#include "compiler.h" /* QEMU_GNUC_PREREQ */ + /* * Because of the strongly ordered x86 storage model, wmb() and rmb() are nops * on x86(well, a compiler barrier only). Well, at least as long as diff --git a/qemu-common.h b/qemu-common.h index 15d9e4ed7..b54612b1a 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -223,11 +223,19 @@ int qemu_pipe(int pipefd[2]); #endif #ifdef _WIN32 -/* MinGW needs a type cast for the 'buf' argument. */ +/* MinGW needs type casts for the 'buf' and 'optval' arguments. */ +#define qemu_getsockopt(sockfd, level, optname, optval, optlen) \ + getsockopt(sockfd, level, optname, (void *)optval, optlen) +#define qemu_setsockopt(sockfd, level, optname, optval, optlen) \ + setsockopt(sockfd, level, optname, (const void *)optval, optlen) #define qemu_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags) #define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \ sendto(sockfd, (const void *)buf, len, flags, destaddr, addrlen) #else +#define qemu_getsockopt(sockfd, level, optname, optval, optlen) \ + getsockopt(sockfd, level, optname, optval, optlen) +#define qemu_setsockopt(sockfd, level, optname, optval, optlen) \ + setsockopt(sockfd, level, optname, optval, optlen) #define qemu_recv(sockfd, buf, len, flags) recv(sockfd, buf, len, flags) #define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \ sendto(sockfd, buf, len, flags, destaddr, addrlen) diff --git a/qemu-sockets.c b/qemu-sockets.c index 1f14e8bc6..2b1ed2f0e 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -266,7 +266,6 @@ static void wait_for_connect(void *opaque) s->callback(s->fd, s->opaque); } g_free(s); - return; } static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, @@ -282,7 +281,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, inet_strfamily(addr->ai_family), strerror(errno)); return -1; } - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (connect_state != NULL) { socket_set_nonblock(sock); } diff --git a/qga/commands-posix.c b/qga/commands-posix.c index b9f357cb9..726930a90 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -988,8 +988,6 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) { error_set(err, QERR_UNSUPPORTED); - - return; } #endif diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 54bc5462e..5bd8fb27f 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -180,8 +180,6 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) { error_set(err, QERR_UNSUPPORTED); - - return; } typedef enum { @@ -2201,7 +2201,6 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp) the_end: if (saved_vm_running) vm_start(); - return; } int load_vmstate(const char *name) diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h index 1a1af91e1..be4426b8e 100644 --- a/slirp/ip_icmp.h +++ b/slirp/ip_icmp.h @@ -92,8 +92,8 @@ struct icmp { /* * Lower bounds on packet lengths for various types. - * For the error advice packets must first insure that the - * packet is large enought to contain the returned ip header. + * For the error advice packets must first ensure that the + * packet is large enough to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. diff --git a/slirp/ip_input.c b/slirp/ip_input.c index ce24faf16..6f4cff8fd 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -213,7 +213,6 @@ ip_input(struct mbuf *m) return; bad: m_free(m); - return; } #define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink))) diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 942aaf44f..6440eae7f 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -1281,8 +1281,6 @@ drop: * Drop space held by incoming segment and return. */ m_free(m); - - return; } static void diff --git a/slirp/udp.c b/slirp/udp.c index ced509656..9286cb7d3 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -231,7 +231,6 @@ udp_input(register struct mbuf *m, int iphlen) return; bad: m_free(m); - return; } int udp_output2(struct socket *so, struct mbuf *m, @@ -105,10 +105,7 @@ typedef enum { } VGAInterfaceType; extern int vga_interface_type; -#define cirrus_vga_enabled (vga_interface_type == VGA_CIRRUS) -#define std_vga_enabled (vga_interface_type == VGA_STD) #define xenfb_enabled (vga_interface_type == VGA_XENFB) -#define vmsvga_enabled (vga_interface_type == VGA_VMWARE) #define qxl_enabled (vga_interface_type == VGA_QXL) extern int graphic_width; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7fac94f81..ff4de10f1 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -423,8 +423,6 @@ void armv7m_nvic_complete_irq(void *opaque, int irq); (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \ ((crm) << 7) | ((opc1) << 3) | (opc2)) -#define DECODE_CPREG_CRN(enc) (((enc) >> 7) & 0xf) - /* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a * special-behaviour cp reg and bits [15..8] indicate what behaviour * it has. Otherwise it is a simple cp reg, where CONST indicates that diff --git a/target-arm/helper.h b/target-arm/helper.h index afdb2b5b1..8b9adf131 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -1,8 +1,8 @@ #include "def-helper.h" -DEF_HELPER_1(clz, i32, i32) -DEF_HELPER_1(sxtb16, i32, i32) -DEF_HELPER_1(uxtb16, i32, i32) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) DEF_HELPER_3(add_setq, i32, env, i32, i32) DEF_HELPER_3(add_saturate, i32, env, i32, i32) @@ -10,10 +10,10 @@ DEF_HELPER_3(sub_saturate, i32, env, i32, i32) DEF_HELPER_3(add_usaturate, i32, env, i32, i32) DEF_HELPER_3(sub_usaturate, i32, env, i32, i32) DEF_HELPER_2(double_saturate, i32, env, s32) -DEF_HELPER_2(sdiv, s32, s32, s32) -DEF_HELPER_2(udiv, i32, i32, i32) -DEF_HELPER_1(rbit, i32, i32) -DEF_HELPER_1(abs, i32, i32) +DEF_HELPER_FLAGS_2(sdiv, TCG_CALL_CONST | TCG_CALL_PURE, s32, s32, s32) +DEF_HELPER_FLAGS_2(udiv, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_1(rbit, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(abs, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) #define PAS_OP(pfx) \ DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ @@ -45,11 +45,12 @@ DEF_HELPER_3(usat, i32, env, i32, i32) DEF_HELPER_3(ssat16, i32, env, i32, i32) DEF_HELPER_3(usat16, i32, env, i32, i32) -DEF_HELPER_2(usad8, i32, i32, i32) +DEF_HELPER_FLAGS_2(usad8, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) DEF_HELPER_1(logicq_cc, i32, i64) -DEF_HELPER_3(sel_flags, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_CONST | TCG_CALL_PURE, + i32, i32, i32, i32) DEF_HELPER_2(exception, void, env, i32) DEF_HELPER_1(wfi, void, env) @@ -142,14 +143,9 @@ DEF_HELPER_2(recpe_u32, i32, i32, env) DEF_HELPER_2(rsqrte_u32, i32, i32, env) DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32) -DEF_HELPER_3(add_cc, i32, env, i32, i32) DEF_HELPER_3(adc_cc, i32, env, i32, i32) -DEF_HELPER_3(sub_cc, i32, env, i32, i32) DEF_HELPER_3(sbc_cc, i32, env, i32, i32) -DEF_HELPER_3(shl, i32, env, i32, i32) -DEF_HELPER_3(shr, i32, env, i32, i32) -DEF_HELPER_3(sar, i32, env, i32, i32) DEF_HELPER_3(shl_cc, i32, env, i32, i32) DEF_HELPER_3(shr_cc, i32, env, i32, i32) DEF_HELPER_3(sar_cc, i32, env, i32, i32) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index f13fc3ae5..aef592ab8 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -323,16 +323,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) The only way to do that in TCG is a conditional branch, which clobbers all our temporaries. For now implement these as helper functions. */ -uint32_t HELPER (add_cc)(CPUARMState *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a + b; - env->NF = env->ZF = result; - env->CF = result < a; - env->VF = (a ^ b ^ -1) & (a ^ result); - return result; -} - uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b) { uint32_t result; @@ -348,16 +338,6 @@ uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b) return result; } -uint32_t HELPER(sub_cc)(CPUARMState *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a - b; - env->NF = env->ZF = result; - env->CF = a >= b; - env->VF = (a ^ b) & (a ^ result); - return result; -} - uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) { uint32_t result; @@ -375,30 +355,6 @@ uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) /* Similarly for variable shift instructions. */ -uint32_t HELPER(shl)(CPUARMState *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) - return 0; - return x << shift; -} - -uint32_t HELPER(shr)(CPUARMState *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) - return 0; - return (uint32_t)x >> shift; -} - -uint32_t HELPER(sar)(CPUARMState *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) - shift = 31; - return (int32_t)x >> shift; -} - uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i) { int shift = i & 0xff; diff --git a/target-arm/translate.c b/target-arm/translate.c index 5fded491e..c6840b783 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -85,6 +85,7 @@ static TCGv_ptr cpu_env; /* We reuse the same 64-bit temporaries for efficiency. */ static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; static TCGv_i32 cpu_R[16]; +static TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF; static TCGv_i32 cpu_exclusive_addr; static TCGv_i32 cpu_exclusive_val; static TCGv_i32 cpu_exclusive_high; @@ -115,6 +116,11 @@ void arm_translate_init(void) offsetof(CPUARMState, regs[i]), regnames[i]); } + cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF"); + cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF"); + cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF"); + cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF"); + cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, exclusive_addr), "exclusive_addr"); cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0, @@ -271,15 +277,6 @@ static void gen_sbfx(TCGv var, int shift, int width) } } -/* Bitfield insertion. Insert val into base. Clobbers base and val. */ -static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask) -{ - tcg_gen_andi_i32(val, val, mask); - tcg_gen_shli_i32(val, val, shift); - tcg_gen_andi_i32(base, base, ~(mask << shift)); - tcg_gen_or_i32(dest, base, val); -} - /* Return (b << 32) + a. Mark inputs as dead */ static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b) { @@ -369,53 +366,100 @@ static void gen_add16(TCGv t0, TCGv t1) tcg_temp_free_i32(t1); } -#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, CF)) - /* Set CF to the top bit of var. */ static void gen_set_CF_bit31(TCGv var) { - TCGv tmp = tcg_temp_new_i32(); - tcg_gen_shri_i32(tmp, var, 31); - gen_set_CF(tmp); - tcg_temp_free_i32(tmp); + tcg_gen_shri_i32(cpu_CF, var, 31); } /* Set N and Z flags from var. */ static inline void gen_logic_CC(TCGv var) { - tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, NF)); - tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, ZF)); + tcg_gen_mov_i32(cpu_NF, var); + tcg_gen_mov_i32(cpu_ZF, var); } /* T0 += T1 + CF. */ static void gen_adc(TCGv t0, TCGv t1) { - TCGv tmp; tcg_gen_add_i32(t0, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(t0, t0, tmp); - tcg_temp_free_i32(tmp); + tcg_gen_add_i32(t0, t0, cpu_CF); } /* dest = T0 + T1 + CF. */ static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1) { - TCGv tmp; tcg_gen_add_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); - tcg_temp_free_i32(tmp); + tcg_gen_add_i32(dest, dest, cpu_CF); } /* dest = T0 - T1 + CF - 1. */ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) { - TCGv tmp; tcg_gen_sub_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); + tcg_gen_add_i32(dest, dest, cpu_CF); tcg_gen_subi_i32(dest, dest, 1); +} + +/* dest = T0 + T1. Compute C, N, V and Z flags */ +static void gen_add_CC(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_add_i32(cpu_NF, t0, t1); + tcg_gen_mov_i32(cpu_ZF, cpu_NF); + tcg_gen_setcond_i32(TCG_COND_LTU, cpu_CF, cpu_NF, t0); + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp); tcg_temp_free_i32(tmp); + tcg_gen_mov_i32(dest, cpu_NF); +} + +/* dest = T0 - T1. Compute C, N, V and Z flags */ +static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_sub_i32(cpu_NF, t0, t1); + tcg_gen_mov_i32(cpu_ZF, cpu_NF); + tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0, t1); + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_and_i32(cpu_VF, cpu_VF, tmp); + tcg_temp_free_i32(tmp); + tcg_gen_mov_i32(dest, cpu_NF); +} + +#define GEN_SHIFT(name) \ +static void gen_##name(TCGv dest, TCGv t0, TCGv t1) \ +{ \ + TCGv tmp1, tmp2, tmp3; \ + tmp1 = tcg_temp_new_i32(); \ + tcg_gen_andi_i32(tmp1, t1, 0xff); \ + tmp2 = tcg_const_i32(0); \ + tmp3 = tcg_const_i32(0x1f); \ + tcg_gen_movcond_i32(TCG_COND_GTU, tmp2, tmp1, tmp3, tmp2, t0); \ + tcg_temp_free_i32(tmp3); \ + tcg_gen_andi_i32(tmp1, tmp1, 0x1f); \ + tcg_gen_##name##_i32(dest, tmp2, tmp1); \ + tcg_temp_free_i32(tmp2); \ + tcg_temp_free_i32(tmp1); \ +} +GEN_SHIFT(shl) +GEN_SHIFT(shr) +#undef GEN_SHIFT + +static void gen_sar(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp1, tmp2; + tmp1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp1, t1, 0xff); + tmp2 = tcg_const_i32(0x1f); + tcg_gen_movcond_i32(TCG_COND_GTU, tmp1, tmp1, tmp2, tmp2, tmp1); + tcg_temp_free_i32(tmp2); + tcg_gen_sar_i32(dest, t0, tmp1); + tcg_temp_free_i32(tmp1); } /* FIXME: Implement this natively. */ @@ -423,16 +467,14 @@ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) static void shifter_out_im(TCGv var, int shift) { - TCGv tmp = tcg_temp_new_i32(); if (shift == 0) { - tcg_gen_andi_i32(tmp, var, 1); + tcg_gen_andi_i32(cpu_CF, var, 1); } else { - tcg_gen_shri_i32(tmp, var, shift); - if (shift != 31) - tcg_gen_andi_i32(tmp, tmp, 1); + tcg_gen_shri_i32(cpu_CF, var, shift); + if (shift != 31) { + tcg_gen_andi_i32(cpu_CF, cpu_CF, 1); + } } - gen_set_CF(tmp); - tcg_temp_free_i32(tmp); } /* Shift by immediate. Includes special handling for shift == 0. */ @@ -449,8 +491,7 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) case 1: /* LSR */ if (shift == 0) { if (flags) { - tcg_gen_shri_i32(var, var, 31); - gen_set_CF(var); + tcg_gen_shri_i32(cpu_CF, var, 31); } tcg_gen_movi_i32(var, 0); } else { @@ -474,11 +515,11 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) shifter_out_im(var, shift - 1); tcg_gen_rotri_i32(var, var, shift); break; } else { - TCGv tmp = load_cpu_field(CF); + TCGv tmp = tcg_temp_new_i32(); if (flags) shifter_out_im(var, 0); tcg_gen_shri_i32(var, var, 1); - tcg_gen_shli_i32(tmp, tmp, 31); + tcg_gen_shli_i32(tmp, cpu_CF, 31); tcg_gen_or_i32(var, var, tmp); tcg_temp_free_i32(tmp); } @@ -497,9 +538,15 @@ static inline void gen_arm_shift_reg(TCGv var, int shiftop, } } else { switch (shiftop) { - case 0: gen_helper_shl(var, cpu_env, var, shift); break; - case 1: gen_helper_shr(var, cpu_env, var, shift); break; - case 2: gen_helper_sar(var, cpu_env, var, shift); break; + case 0: + gen_shl(var, var, shift); + break; + case 1: + gen_shr(var, var, shift); + break; + case 2: + gen_sar(var, var, shift); + break; case 3: tcg_gen_andi_i32(shift, shift, 0x1f); tcg_gen_rotr_i32(var, var, shift); break; } @@ -603,99 +650,75 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b) static void gen_test_cc(int cc, int label) { TCGv tmp; - TCGv tmp2; int inv; switch (cc) { case 0: /* eq: Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); break; case 1: /* ne: !Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); break; case 2: /* cs: C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_CF, 0, label); break; case 3: /* cc: !C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); break; case 4: /* mi: N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_LT, cpu_NF, 0, label); break; case 5: /* pl: !N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_GE, cpu_NF, 0, label); break; case 6: /* vs: V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_LT, cpu_VF, 0, label); break; case 7: /* vc: !V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_GE, cpu_VF, 0, label); break; case 8: /* hi: C && !Z */ inv = gen_new_label(); - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, inv); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); gen_set_label(inv); break; case 9: /* ls: !C || Z */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); break; case 10: /* ge: N == V -> N ^ V == 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_temp_free_i32(tmp); break; case 11: /* lt: N != V -> N ^ V != 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_temp_free_i32(tmp); break; case 12: /* gt: !Z && N == V */ inv = gen_new_label(); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, inv); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_temp_free_i32(tmp); gen_set_label(inv); break; case 13: /* le: Z || N != V */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_temp_free_i32(tmp); break; default: fprintf(stderr, "Bad condition code 0x%x\n", cc); abort(); } - tcg_temp_free_i32(tmp); } static const uint8_t table_logic_cc[16] = { @@ -2628,12 +2651,12 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn) switch (size) { case 0: tmp2 = neon_load_reg(rn, pass); - gen_bfi(tmp, tmp2, tmp, offset, 0xff); + tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 8); tcg_temp_free_i32(tmp2); break; case 1: tmp2 = neon_load_reg(rn, pass); - gen_bfi(tmp, tmp2, tmp, offset, 0xffff); + tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 16); tcg_temp_free_i32(tmp2); break; case 2: @@ -3989,7 +4012,8 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn) } if (size != 2) { tmp2 = neon_load_reg(rd, pass); - gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff); + tcg_gen_deposit_i32(tmp, tmp2, tmp, + shift, size ? 16 : 8); tcg_temp_free_i32(tmp2); } neon_store_reg(rd, pass, tmp); @@ -7005,11 +7029,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) if (IS_USER(s)) { goto illegal_op; } - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); gen_exception_return(s, tmp); } else { if (set_cc) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); } else { tcg_gen_sub_i32(tmp, tmp, tmp2); } @@ -7018,7 +7042,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x03: if (set_cc) { - gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp); + gen_sub_CC(tmp, tmp2, tmp); } else { tcg_gen_sub_i32(tmp, tmp2, tmp); } @@ -7026,7 +7050,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x04: if (set_cc) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); } else { tcg_gen_add_i32(tmp, tmp, tmp2); } @@ -7072,13 +7096,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x0a: if (set_cc) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); } tcg_temp_free_i32(tmp); break; case 0x0b: if (set_cc) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); } tcg_temp_free_i32(tmp); break; @@ -7593,7 +7617,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) } if (i != 32) { tmp2 = load_reg(s, rd); - gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1); + tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i); tcg_temp_free_i32(tmp2); } store_reg(s, rd, tmp); @@ -7865,7 +7889,7 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG break; case 8: /* add */ if (conds) - gen_helper_add_cc(t0, cpu_env, t0, t1); + gen_add_CC(t0, t0, t1); else tcg_gen_add_i32(t0, t0, t1); break; @@ -7883,13 +7907,13 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG break; case 13: /* sub */ if (conds) - gen_helper_sub_cc(t0, cpu_env, t0, t1); + gen_sub_CC(t0, t0, t1); else tcg_gen_sub_i32(t0, t0, t1); break; case 14: /* rsb */ if (conds) - gen_helper_sub_cc(t0, cpu_env, t1, t0); + gen_sub_CC(t0, t1, t0); else tcg_gen_sub_i32(t0, t1, t0); break; @@ -8704,7 +8728,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw imm = imm + 1 - shift; if (imm != 32) { tmp2 = load_reg(s, rd); - gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1); + tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm); tcg_temp_free_i32(tmp2); } break; @@ -9017,12 +9041,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_sub_i32(tmp, tmp, tmp2); else - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); } else { if (s->condexec_mask) tcg_gen_add_i32(tmp, tmp, tmp2); else - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); } tcg_temp_free_i32(tmp2); store_reg(s, rd, tmp); @@ -9053,7 +9077,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) tcg_gen_movi_i32(tmp2, insn & 0xff); switch (op) { case 1: /* cmp */ - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp2); break; @@ -9061,7 +9085,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_add_i32(tmp, tmp, tmp2); else - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp2); store_reg(s, rd, tmp); break; @@ -9069,7 +9093,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_sub_i32(tmp, tmp, tmp2); else - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp2); store_reg(s, rd, tmp); break; @@ -9105,7 +9129,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) case 1: /* cmp */ tmp = load_reg(s, rd); tmp2 = load_reg(s, rm); - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp2); tcg_temp_free_i32(tmp); break; @@ -9166,7 +9190,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) break; case 0x2: /* lsl */ if (s->condexec_mask) { - gen_helper_shl(tmp2, cpu_env, tmp2, tmp); + gen_shl(tmp2, tmp2, tmp); } else { gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp); gen_logic_CC(tmp2); @@ -9174,7 +9198,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) break; case 0x3: /* lsr */ if (s->condexec_mask) { - gen_helper_shr(tmp2, cpu_env, tmp2, tmp); + gen_shr(tmp2, tmp2, tmp); } else { gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp); gen_logic_CC(tmp2); @@ -9182,7 +9206,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) break; case 0x4: /* asr */ if (s->condexec_mask) { - gen_helper_sar(tmp2, cpu_env, tmp2, tmp); + gen_sar(tmp2, tmp2, tmp); } else { gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp); gen_logic_CC(tmp2); @@ -9218,14 +9242,14 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_neg_i32(tmp, tmp2); else - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); break; case 0xa: /* cmp */ - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); rd = 16; break; case 0xb: /* cmn */ - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); rd = 16; break; case 0xc: /* orr */ @@ -9970,19 +9994,6 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; -#if 0 - union { - uint32_t i; - float s; - } s0, s1; - CPU_DoubleU d; - /* ??? This assumes float64 and double have the same layout. - Oh well, it's only debug dumps. */ - union { - float64 f64; - double d; - } d0; -#endif uint32_t psr; for(i=0;i<16;i++) { @@ -10002,20 +10013,23 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf, psr & CPSR_T ? 'T' : 'A', cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); -#if 0 - for (i = 0; i < 16; i++) { - d.d = env->vfp.regs[i]; - s0.i = d.l.lower; - s1.i = d.l.upper; - d0.f64 = d.d; - cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n", - i * 2, (int)s0.i, s0.s, - i * 2 + 1, (int)s1.i, s1.s, - i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, - d0.d); + if (flags & CPU_DUMP_FPU) { + int numvfpregs = 0; + if (arm_feature(env, ARM_FEATURE_VFP)) { + numvfpregs += 16; + } + if (arm_feature(env, ARM_FEATURE_VFP3)) { + numvfpregs += 16; + } + for (i = 0; i < numvfpregs; i++) { + uint64_t v = float64_val(env->vfp.regs[i]); + cpu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", + i * 2, (uint32_t)v, + i * 2 + 1, (uint32_t)(v >> 32), + i, v); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); } - cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); -#endif } void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index bb1e44eb0..f3708e63b 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1759,7 +1759,7 @@ static void x86_cpu_reset(CPUState *s) if (qemu_loglevel_mask(CPU_LOG_RESET)) { qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); - log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP); + log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP); } xcc->parent_reset(s); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index d28d155a0..bc60cdb06 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -996,10 +996,6 @@ void cpu_smm_update(CPUX86State *env); uint64_t cpu_get_tsc(CPUX86State *env); X86CPU *pc_new_cpu(const char *cpu_model); -/* used to debug */ -#define X86_DUMP_FPU 0x0001 /* dump FPU state too */ -#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ - #define TARGET_PAGE_BITS 12 #ifdef TARGET_X86_64 diff --git a/target-i386/helper.c b/target-i386/helper.c index c635667d6..2ee7c6d1b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -284,7 +284,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n", env->dr[6], env->dr[7]); } - if (flags & X86_DUMP_CCOP) { + if (flags & CPU_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]); else @@ -303,7 +303,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, } } cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer); - if (flags & X86_DUMP_FPU) { + if (flags & CPU_DUMP_FPU) { int fptag; fptag = 0; for(i = 0; i < 8; i++) { diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 5fff8d59c..ff9337441 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -31,7 +31,7 @@ #ifdef DEBUG_PCALL # define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) # define LOG_PCALL_STATE(env) \ - log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP) + log_cpu_state_mask(CPU_LOG_PCALL, (env), CPU_DUMP_CCOP) #else # define LOG_PCALL(...) do { } while (0) # define LOG_PCALL_STATE(env) do { } while (0) @@ -1177,7 +1177,7 @@ static void do_interrupt_all(CPUX86State *env, int intno, int is_int, qemu_log(" EAX=" TARGET_FMT_lx, EAX); } qemu_log("\n"); - log_cpu_state(env, X86_DUMP_CCOP); + log_cpu_state(env, CPU_DUMP_CCOP); #if 0 { int i; diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c index 8b04eb2e0..eea2fe978 100644 --- a/target-i386/smm_helper.c +++ b/target-i386/smm_helper.c @@ -47,7 +47,7 @@ void do_smm_enter(CPUX86State *env) int i, offset; qemu_log_mask(CPU_LOG_INT, "SMM: enter\n"); - log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); + log_cpu_state_mask(CPU_LOG_INT, env, CPU_DUMP_CCOP); env->hflags |= HF_SMM_MASK; cpu_smm_update(env); @@ -295,7 +295,7 @@ void helper_rsm(CPUX86State *env) cpu_smm_update(env); qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); - log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); + log_cpu_state_mask(CPU_LOG_INT, env, CPU_DUMP_CCOP); } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index ca2fc2198..faf440407 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1079,7 +1079,6 @@ struct CPUPPCState { int mmu_idx; /* precomputed MMU index to speed up mem accesses */ /* Power management */ - int power_mode; int (*check_pow)(CPUPPCState *env); #if !defined(CONFIG_USER_ONLY) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index f638b2a07..f39b4f682 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -287,23 +287,6 @@ target_ulong helper_602_mfrom(target_ulong arg) for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--) #endif -/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise, - * execute the following block. */ -#define DO_HANDLE_NAN(result, x) \ - if (float32_is_any_nan(x)) { \ - CPU_FloatU __f; \ - __f.f = x; \ - __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ - result = __f.f; \ - } else - -#define HANDLE_NAN1(result, x) \ - DO_HANDLE_NAN(result, x) -#define HANDLE_NAN2(result, x, y) \ - DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) -#define HANDLE_NAN3(result, x, y, z) \ - DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z) - /* Saturating arithmetic helpers. */ #define SATCVT(from, to, from_type, to_type, min, max) \ static inline to_type cvt##from##to(from_type x, int *sat) \ @@ -409,15 +392,29 @@ VARITH(uwm, u32) int i; \ \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ - r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ - } \ + r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ } \ } VARITHFP(addfp, float32_add) VARITHFP(subfp, float32_sub) +VARITHFP(minfp, float32_min) +VARITHFP(maxfp, float32_max) #undef VARITHFP +#define VARITHFPFMA(suffix, type) \ + void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \ + ppc_avr_t *b, ppc_avr_t *c) \ + { \ + int i; \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + r->f[i] = float32_muladd(a->f[i], c->f[i], b->f[i], \ + type, &env->vec_status); \ + } \ + } +VARITHFPFMA(maddfp, 0); +VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c); +#undef VARITHFPFMA + #define VARITHSAT_CASE(type, op, cvt, element) \ { \ type result = (type)a->element[i] op (type)b->element[i]; \ @@ -649,27 +646,6 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT -void helper_vmaddfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, - ppc_avr_t *c) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { - /* Need to do the computation in higher precision and round - * once at the end. */ - float64 af, bf, cf, t; - - af = float32_to_float64(a->f[i], &env->vec_status); - bf = float32_to_float64(b->f[i], &env->vec_status); - cf = float32_to_float64(c->f[i], &env->vec_status); - t = float64_mul(af, cf, &env->vec_status); - t = float64_add(t, bf, &env->vec_status); - r->f[i] = float64_to_float32(t, &env->vec_status); - } - } -} - void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { @@ -730,27 +706,6 @@ VMINMAX(uw, u32) #undef VMINMAX_DO #undef VMINMAX -#define VMINMAXFP(suffix, rT, rF) \ - void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \ - ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ - if (float32_lt_quiet(a->f[i], b->f[i], \ - &env->vec_status)) { \ - r->f[i] = rT->f[i]; \ - } else { \ - r->f[i] = rF->f[i]; \ - } \ - } \ - } \ - } -VMINMAXFP(minfp, a, b) -VMINMAXFP(maxfp, b, a) -#undef VMINMAXFP - void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int i; @@ -930,28 +885,6 @@ VMUL(uh, u16, u32) #undef VMUL_DO #undef VMUL -void helper_vnmsubfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { - /* Need to do the computation is higher precision and round - * once at the end. */ - float64 af, bf, cf, t; - - af = float32_to_float64(a->f[i], &env->vec_status); - bf = float32_to_float64(b->f[i], &env->vec_status); - cf = float32_to_float64(c->f[i], &env->vec_status); - t = float64_mul(af, cf, &env->vec_status); - t = float64_sub(t, bf, &env->vec_status); - t = float64_chs(t); - r->f[i] = float64_to_float32(t, &env->vec_status); - } - } -} - void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { @@ -1039,9 +972,7 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); - } + r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); } } @@ -1054,9 +985,7 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) \ set_float_rounding_mode(rounding, &s); \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN1(r->f[i], b->f[i]) { \ - r->f[i] = float32_round_to_int (b->f[i], &s); \ - } \ + r->f[i] = float32_round_to_int (b->f[i], &s); \ } \ } VRFI(n, float_round_nearest_even) @@ -1089,11 +1018,9 @@ void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - float32 t = float32_sqrt(b->f[i], &env->vec_status); + float32 t = float32_sqrt(b->f[i], &env->vec_status); - r->f[i] = float32_div(float32_one, t, &env->vec_status); - } + r->f[i] = float32_div(float32_one, t, &env->vec_status); } } @@ -1109,9 +1036,7 @@ void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_exp2(b->f[i], &env->vec_status); - } + r->f[i] = float32_exp2(b->f[i], &env->vec_status); } } @@ -1120,9 +1045,7 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_log2(b->f[i], &env->vec_status); - } + r->f[i] = float32_log2(b->f[i], &env->vec_status); } } @@ -1473,10 +1396,6 @@ VUPK(lsh, s32, s16, UPKLO) #undef UPKHI #undef UPKLO -#undef DO_HANDLE_NAN -#undef HANDLE_NAN1 -#undef HANDLE_NAN2 -#undef HANDLE_NAN3 #undef VECTOR_FOR_INORDER_I #undef HI_IDX #undef LO_IDX diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 7f6e4e0b8..5cbe98a16 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -60,6 +60,7 @@ static int cap_booke_sregs; static int cap_ppc_smt; static int cap_ppc_rma; static int cap_spapr_tce; +static int cap_hior; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -86,6 +87,7 @@ int kvm_arch_init(KVMState *s) cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); + cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -469,6 +471,54 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) env->tlb_dirty = false; } + if (cap_segstate && (level >= KVM_PUT_RESET_STATE)) { + struct kvm_sregs sregs; + + sregs.pvr = env->spr[SPR_PVR]; + + sregs.u.s.sdr1 = env->spr[SPR_SDR1]; + + /* Sync SLB */ +#ifdef TARGET_PPC64 + for (i = 0; i < 64; i++) { + sregs.u.s.ppc64.slb[i].slbe = env->slb[i].esid; + sregs.u.s.ppc64.slb[i].slbv = env->slb[i].vsid; + } +#endif + + /* Sync SRs */ + for (i = 0; i < 16; i++) { + sregs.u.s.ppc32.sr[i] = env->sr[i]; + } + + /* Sync BATs */ + for (i = 0; i < 8; i++) { + /* Beware. We have to swap upper and lower bits here */ + sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[0][i] << 32) + | env->DBAT[1][i]; + sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[0][i] << 32) + | env->IBAT[1][i]; + } + + ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + if (ret) { + return ret; + } + } + + if (cap_hior && (level >= KVM_PUT_RESET_STATE)) { + uint64_t hior = env->spr[SPR_HIOR]; + struct kvm_one_reg reg = { + .id = KVM_REG_PPC_HIOR, + .addr = (uintptr_t) &hior, + }; + + ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + } + return ret; } @@ -946,52 +996,14 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) void kvmppc_set_papr(CPUPPCState *env) { struct kvm_enable_cap cap = {}; - struct kvm_one_reg reg = {}; - struct kvm_sregs sregs = {}; int ret; - uint64_t hior = env->spr[SPR_HIOR]; cap.cap = KVM_CAP_PPC_PAPR; ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap); if (ret) { - goto fail; - } - - /* - * XXX We set HIOR here. It really should be a qdev property of - * the CPU node, but we don't have CPUs converted to qdev yet. - * - * Once we have qdev CPUs, move HIOR to a qdev property and - * remove this chunk. - */ - reg.id = KVM_REG_PPC_HIOR; - reg.addr = (uintptr_t)&hior; - ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®); - if (ret) { - fprintf(stderr, "Couldn't set HIOR. Maybe you're running an old \n" - "kernel with support for HV KVM but no PAPR PR \n" - "KVM in which case things will work. If they don't \n" - "please update your host kernel!\n"); - } - - /* Set SDR1 so kernel space finds the HTAB */ - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); - if (ret) { - goto fail; + cpu_abort(env, "This KVM version does not support PAPR\n"); } - - sregs.u.s.sdr1 = env->spr[SPR_SDR1]; - - ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); - if (ret) { - goto fail; - } - - return; - -fail: - cpu_abort(env, "This KVM version does not support PAPR\n"); } int kvmppc_smt_threads(void) @@ -999,6 +1011,7 @@ int kvmppc_smt_threads(void) return cap_ppc_smt ? cap_ppc_smt : 1; } +#ifdef TARGET_PPC64 off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) { void *rma; @@ -1042,6 +1055,16 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) return size; } +uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift) +{ + if (cap_ppc_rma >= 2) { + return current_size; + } + return MIN(current_size, + getrampagesize() << (hash_shift - 7)); +} +#endif + void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) { struct kvm_create_spapr_tce args = { @@ -1101,6 +1124,44 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return 0; } +int kvmppc_reset_htab(int shift_hint) +{ + uint32_t shift = shift_hint; + + if (!kvm_enabled()) { + /* Full emulation, tell caller to allocate htab itself */ + return 0; + } + if (kvm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) { + int ret; + ret = kvm_vm_ioctl(kvm_state, KVM_PPC_ALLOCATE_HTAB, &shift); + if (ret == -ENOTTY) { + /* At least some versions of PR KVM advertise the + * capability, but don't implement the ioctl(). Oops. + * Return 0 so that we allocate the htab in qemu, as is + * correct for PR. */ + return 0; + } else if (ret < 0) { + return ret; + } + return shift; + } + + /* We have a kernel that predates the htab reset calls. For PR + * KVM, we need to allocate the htab ourselves, for an HV KVM of + * this era, it has allocated a 16MB fixed size hash table + * already. Kernels of this era have the GET_PVINFO capability + * only on PR, so we use this hack to determine the right + * answer */ + if (kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + /* PR - tell caller to allocate htab */ + return 0; + } else { + /* HV - assume 16MB kernel allocated htab */ + return 24; + } +} + static inline uint32_t mfpvr(void) { uint32_t pvr; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index e2f870385..baad6eb75 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -27,6 +27,8 @@ int kvmppc_smt_threads(void); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +int kvmppc_reset_htab(int shift_hint); +uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ const ppc_def_t *kvmppc_host_cpu_def(void); int kvmppc_fixup_cpu(CPUPPCState *env); @@ -94,6 +96,23 @@ static inline int kvmppc_remove_spapr_tce(void *table, int pfd, { return -1; } + +static inline int kvmppc_reset_htab(int shift_hint) +{ + return -1; +} + +static inline uint64_t kvmppc_rma_size(uint64_t current_size, + unsigned int hash_shift) +{ + return ram_size; +} + +static inline int kvmppc_update_sdr1(CPUPPCState *env) +{ + return 0; +} + #endif /* !CONFIG_USER_ONLY */ static inline const ppc_def_t *kvmppc_host_cpu_def(void) diff --git a/target-ppc/machine.c b/target-ppc/machine.c index d6c2ee41b..21ce7575e 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -82,7 +82,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_betls(f, &env->hflags); qemu_put_betls(f, &env->hflags_nmsr); qemu_put_sbe32s(f, &env->mmu_idx); - qemu_put_sbe32s(f, &env->power_mode); + qemu_put_sbe32(f, 0); } int cpu_load(QEMUFile *f, void *opaque, int version_id) @@ -167,7 +167,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_betls(f, &env->hflags); qemu_get_betls(f, &env->hflags_nmsr); qemu_get_sbe32s(f, &env->mmu_idx); - qemu_get_sbe32s(f, &env->power_mode); + qemu_get_sbe32(f); /* Discard unused power_mode */ return 0; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index fba2b4242..a97228703 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10423,6 +10423,14 @@ static void ppc_cpu_reset(CPUState *s) env->pending_interrupts = 0; env->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; + +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) + env->vpa = 0; + env->slb_shadow = 0; + env->dispatch_trace_log = 0; + env->dtl_size = 0; +#endif /* TARGET_PPC64 */ + /* Flush all TLBs */ tlb_flush(env, 1); } diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index eb9f0e725..882d30642 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -792,7 +792,6 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc); - cpu_fprintf(f, "General Registers:\n"); for (i = 0; i < 8; i++) { if (i % REGS_PER_LINE == 0) { @@ -803,7 +802,6 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n"); } } - cpu_fprintf(f, "\nCurrent Register Window:\n"); for (x = 0; x < 3; x++) { for (i = 0; i < 8; i++) { if (i % REGS_PER_LINE == 0) { @@ -817,10 +815,10 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, } } } - cpu_fprintf(f, "\nFloating Point Registers:\n"); + for (i = 0; i < TARGET_DPREGS; i++) { if ((i & 3) == 0) { - cpu_fprintf(f, "%%f%02d:", i * 2); + cpu_fprintf(f, "%%f%02d: ", i * 2); } cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll); if ((i & 3) == 3) { @@ -850,6 +848,7 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n", env->fsr, env->y); #endif + cpu_fprintf(f, "\n"); } static void sparc_cpu_initfn(Object *obj) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e16b7b351..214d01dd7 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -714,6 +714,7 @@ trap_state* cpu_tsptr(CPUSPARCState* env); void QEMU_NORETURN do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, int is_user, uintptr_t retaddr); +void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr); #define TB_FLAG_FPU_ENABLED (1 << 4) #define TB_FLAG_AM_ENABLED (1 << 5) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 65e1740e1..556ac286e 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -75,6 +75,7 @@ static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a, x1 = (b & 0xffffffff); if (x1 == 0) { + cpu_restore_state2(env, GETPC()); helper_raise_exception(env, TT_DIV_ZERO); } @@ -113,6 +114,7 @@ static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a, x1 = (b & 0xffffffff); if (x1 == 0) { + cpu_restore_state2(env, GETPC()); helper_raise_exception(env, TT_DIV_ZERO); } @@ -139,3 +141,87 @@ target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b) { return helper_sdiv_common(env, a, b, 1); } + +#ifdef TARGET_SPARC64 +int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b) +{ + if (b == 0) { + /* Raise divide by zero trap. */ + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_DIV_ZERO); + } else if (b == -1) { + /* Avoid overflow trap with i386 divide insn. */ + return -a; + } else { + return a / b; + } +} + +uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b) +{ + if (b == 0) { + /* Raise divide by zero trap. */ + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_DIV_ZERO); + } + return a / b; +} +#endif + +target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1, + target_ulong src2) +{ + target_ulong dst; + + /* Tag overflow occurs if either input has bits 0 or 1 set. */ + if ((src1 | src2) & 3) { + goto tag_overflow; + } + + dst = src1 + src2; + + /* Tag overflow occurs if the addition overflows. */ + if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) { + goto tag_overflow; + } + + /* Only modify the CC after any exceptions have been generated. */ + env->cc_op = CC_OP_TADDTV; + env->cc_src = src1; + env->cc_src2 = src2; + env->cc_dst = dst; + return dst; + + tag_overflow: + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_TOVF); +} + +target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1, + target_ulong src2) +{ + target_ulong dst; + + /* Tag overflow occurs if either input has bits 0 or 1 set. */ + if ((src1 | src2) & 3) { + goto tag_overflow; + } + + dst = src1 - src2; + + /* Tag overflow occurs if the subtraction overflows. */ + if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) { + goto tag_overflow; + } + + /* Only modify the CC after any exceptions have been generated. */ + env->cc_op = CC_OP_TSUBTV; + env->cc_src = src1; + env->cc_src2 = src2; + env->cc_dst = dst; + return dst; + + tag_overflow: + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_TOVF); +} diff --git a/target-sparc/helper.h b/target-sparc/helper.h index e3c7fddbe..e1ae3c708 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -38,6 +38,12 @@ DEF_HELPER_3(udiv, tl, env, tl, tl) DEF_HELPER_3(udiv_cc, tl, env, tl, tl) DEF_HELPER_3(sdiv, tl, env, tl, tl) DEF_HELPER_3(sdiv_cc, tl, env, tl, tl) +DEF_HELPER_3(taddcctv, tl, env, tl, tl) +DEF_HELPER_3(tsubcctv, tl, env, tl, tl) +#ifdef TARGET_SPARC64 +DEF_HELPER_3(sdivx, s64, env, s64, s64) +DEF_HELPER_3(udivx, i64, env, i64, i64) +#endif DEF_HELPER_3(ldqf, void, env, tl, int) DEF_HELPER_3(stqf, void, env, tl, int) #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c index 5e33d50e2..9ac5aac33 100644 --- a/target-sparc/int32_helper.c +++ b/target-sparc/int32_helper.c @@ -21,7 +21,7 @@ #include "trace.h" #include "sysemu.h" -//#define DEBUG_PCALL +#define DEBUG_PCALL #ifdef DEBUG_PCALL static const char * const excp_names[0x80] = { @@ -78,10 +78,7 @@ void do_interrupt(CPUSPARCState *env) } } - qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); + qemu_log("%6d: %s (v=%02x)\n", count, name, intno); log_cpu_state(env, 0); #if 0 { diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c index 5e3eff76d..5d0bc6c6d 100644 --- a/target-sparc/int64_helper.c +++ b/target-sparc/int64_helper.c @@ -21,7 +21,7 @@ #include "helper.h" #include "trace.h" -//#define DEBUG_PCALL +#define DEBUG_PCALL #ifdef DEBUG_PCALL static const char * const excp_names[0x80] = { @@ -84,11 +84,7 @@ void do_interrupt(CPUSPARCState *env) } } - qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 - " SP=%016" PRIx64 "\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); + qemu_log("%6d: %s (v=%04x)\n", count, name, intno); log_cpu_state(env, 0); #if 0 { diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 9bec7a92f..2ca9a5c4a 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -2390,9 +2390,8 @@ void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr, #endif #endif -#if !defined(CONFIG_USER_ONLY) /* XXX: make it generic ? */ -static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) +void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) { TranslationBlock *tb; @@ -2407,6 +2406,7 @@ static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) } } +#if !defined(CONFIG_USER_ONLY) void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, int is_user, uintptr_t retaddr) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e5ebedfa2..472eb518c 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -86,6 +86,13 @@ typedef struct DisasContext { int n_t32; } DisasContext; +typedef struct { + TCGCond cond; + bool is_bool; + bool g1, g2; + TCGv c1, c2; +} DisasCompare; + // This function uses non-native bit order #define GET_FIELD(X, FROM, TO) \ ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) @@ -329,43 +336,6 @@ static inline void gen_mov_reg_C(TCGv reg, TCGv_i32 src) tcg_gen_andi_tl(reg, reg, 0x1); } -static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2) -{ - TCGv r_temp; - TCGv_i32 r_const; - int l1; - - l1 = gen_new_label(); - - r_temp = tcg_temp_new(); - tcg_gen_xor_tl(r_temp, src1, src2); - tcg_gen_not_tl(r_temp, r_temp); - tcg_gen_xor_tl(cpu_tmp0, src1, dst); - tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); - tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); - r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); - tcg_temp_free(r_temp); -} - -static inline void gen_tag_tv(TCGv src1, TCGv src2) -{ - int l1; - TCGv_i32 r_const; - - l1 = gen_new_label(); - tcg_gen_or_tl(cpu_tmp0, src1, src2); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3); - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); - r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); -} - static inline void gen_op_addi_cc(TCGv dst, TCGv src1, target_long src2) { tcg_gen_mov_tl(cpu_cc_src, src1); @@ -510,45 +480,6 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, } } -static inline void gen_op_tadd_cc(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static inline void gen_op_tadd_ccTV(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - gen_tag_tv(cpu_cc_src, cpu_cc_src2); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - gen_add_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2) -{ - TCGv r_temp; - TCGv_i32 r_const; - int l1; - - l1 = gen_new_label(); - - r_temp = tcg_temp_new(); - tcg_gen_xor_tl(r_temp, src1, src2); - tcg_gen_xor_tl(cpu_tmp0, src1, dst); - tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); - tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); - r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); - tcg_temp_free(r_temp); -} - static inline void gen_op_subi_cc(TCGv dst, TCGv src1, target_long src2, DisasContext *dc) { tcg_gen_mov_tl(cpu_cc_src, src1); @@ -649,42 +580,23 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, } } -static inline void gen_op_tsub_cc(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static inline void gen_op_tsub_ccTV(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - gen_tag_tv(cpu_cc_src, cpu_cc_src2); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - gen_sub_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) { - TCGv r_temp; - int l1; + TCGv r_temp, zero; - l1 = gen_new_label(); r_temp = tcg_temp_new(); /* old op: if (!(env->y & 1)) T1 = 0; */ + zero = tcg_const_tl(0); tcg_gen_andi_tl(cpu_cc_src, src1, 0xffffffff); tcg_gen_andi_tl(r_temp, cpu_y, 0x1); tcg_gen_andi_tl(cpu_cc_src2, src2, 0xffffffff); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp, 0, l1); - tcg_gen_movi_tl(cpu_cc_src2, 0); - gen_set_label(l1); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_cc_src2, r_temp, zero, + zero, cpu_cc_src2); + tcg_temp_free(zero); // b2 = T0 & 1; // env->y = (b2 << 31) | (env->y >> 1); @@ -761,44 +673,6 @@ static inline void gen_op_smul(TCGv dst, TCGv src1, TCGv src2) gen_op_multiply(dst, src1, src2, 1); } -#ifdef TARGET_SPARC64 -static inline void gen_trap_ifdivzero_tl(TCGv divisor) -{ - TCGv_i32 r_const; - int l1; - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1); - r_const = tcg_const_i32(TT_DIV_ZERO); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); -} - -static inline void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2) -{ - int l1, l2; - TCGv r_temp1, r_temp2; - - l1 = gen_new_label(); - l2 = gen_new_label(); - r_temp1 = tcg_temp_local_new(); - r_temp2 = tcg_temp_local_new(); - tcg_gen_mov_tl(r_temp1, src1); - tcg_gen_mov_tl(r_temp2, src2); - gen_trap_ifdivzero_tl(r_temp2); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp1, INT64_MIN, l1); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp2, -1, l1); - tcg_gen_movi_i64(dst, INT64_MIN); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_div_i64(dst, r_temp1, r_temp2); - gen_set_label(l2); - tcg_temp_free(r_temp1); - tcg_temp_free(r_temp2); -} -#endif - // 1 static inline void gen_op_eval_ba(TCGv dst) { @@ -1098,45 +972,40 @@ static inline void gen_branch_a(DisasContext *dc, target_ulong pc1, gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8); } -static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2, - TCGv r_cond) +static inline void gen_generic_branch(DisasContext *dc) { - int l1, l2; + TCGv npc0 = tcg_const_tl(dc->jump_pc[0]); + TCGv npc1 = tcg_const_tl(dc->jump_pc[1]); + TCGv zero = tcg_const_tl(0); - l1 = gen_new_label(); - l2 = gen_new_label(); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, zero, npc0, npc1); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); - - tcg_gen_movi_tl(cpu_npc, npc1); - tcg_gen_br(l2); - - gen_set_label(l1); - tcg_gen_movi_tl(cpu_npc, npc2); - gen_set_label(l2); + tcg_temp_free(npc0); + tcg_temp_free(npc1); + tcg_temp_free(zero); } /* call this function before using the condition register as it may have been set for a jump */ -static inline void flush_cond(DisasContext *dc, TCGv cond) +static inline void flush_cond(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + gen_generic_branch(dc); dc->npc = DYNAMIC_PC; } } -static inline void save_npc(DisasContext *dc, TCGv cond) +static inline void save_npc(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + gen_generic_branch(dc); dc->npc = DYNAMIC_PC; } else if (dc->npc != DYNAMIC_PC) { tcg_gen_movi_tl(cpu_npc, dc->npc); } } -static inline void save_state(DisasContext *dc, TCGv cond) +static inline void save_state(DisasContext *dc) { tcg_gen_movi_tl(cpu_pc, dc->pc); /* flush pending conditional evaluations before exposing cpu state */ @@ -1144,13 +1013,13 @@ static inline void save_state(DisasContext *dc, TCGv cond) dc->cc_op = CC_OP_FLAGS; gen_helper_compute_psr(cpu_env); } - save_npc(dc, cond); + save_npc(dc); } -static inline void gen_mov_pc_npc(DisasContext *dc, TCGv cond) +static inline void gen_mov_pc_npc(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + gen_generic_branch(dc); tcg_gen_mov_tl(cpu_pc, cpu_npc); dc->pc = DYNAMIC_PC; } else if (dc->npc == DYNAMIC_PC) { @@ -1167,82 +1036,178 @@ static inline void gen_op_next_insn(void) tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); } -static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond, - DisasContext *dc) +static void free_compare(DisasCompare *cmp) { + if (!cmp->g1) { + tcg_temp_free(cmp->c1); + } + if (!cmp->g2) { + tcg_temp_free(cmp->c2); + } +} + +static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, + DisasContext *dc) +{ + static int subcc_cond[16] = { + -1, /* never */ + TCG_COND_EQ, + TCG_COND_LE, + TCG_COND_LT, + TCG_COND_LEU, + TCG_COND_LTU, + -1, /* neg */ + -1, /* overflow */ + -1, /* always */ + TCG_COND_NE, + TCG_COND_GT, + TCG_COND_GE, + TCG_COND_GTU, + TCG_COND_GEU, + -1, /* pos */ + -1, /* no overflow */ + }; + TCGv_i32 r_src; + TCGv r_dst; #ifdef TARGET_SPARC64 - if (cc) + if (xcc) { r_src = cpu_xcc; - else + } else { r_src = cpu_psr; + } #else r_src = cpu_psr; #endif + switch (dc->cc_op) { - case CC_OP_FLAGS: + case CC_OP_SUB: + switch (cond) { + case 6: /* neg */ + case 14: /* pos */ + cmp->cond = (cond == 6 ? TCG_COND_LT : TCG_COND_GE); + cmp->is_bool = false; + cmp->g2 = false; + cmp->c2 = tcg_const_tl(0); +#ifdef TARGET_SPARC64 + if (!xcc) { + cmp->g1 = false; + cmp->c1 = tcg_temp_new(); + tcg_gen_ext32s_tl(cmp->c1, cpu_cc_dst); + break; + } +#endif + cmp->g1 = true; + cmp->c1 = cpu_cc_dst; + break; + + case 0: /* never */ + case 8: /* always */ + case 7: /* overflow */ + case 15: /* !overflow */ + goto do_dynamic; + + default: + cmp->cond = subcc_cond[cond]; + cmp->is_bool = false; +#ifdef TARGET_SPARC64 + if (!xcc) { + /* Note that sign-extension works for unsigned compares as + long as both operands are sign-extended. */ + cmp->g1 = cmp->g2 = false; + cmp->c1 = tcg_temp_new(); + cmp->c2 = tcg_temp_new(); + tcg_gen_ext32s_tl(cmp->c1, cpu_cc_src); + tcg_gen_ext32s_tl(cmp->c2, cpu_cc_src2); + } +#endif + cmp->g1 = cmp->g2 = true; + cmp->c1 = cpu_cc_src; + cmp->c2 = cpu_cc_src2; + break; + } break; + default: + do_dynamic: gen_helper_compute_psr(cpu_env); dc->cc_op = CC_OP_FLAGS; - break; - } - switch (cond) { - case 0x0: - gen_op_eval_bn(r_dst); - break; - case 0x1: - gen_op_eval_be(r_dst, r_src); - break; - case 0x2: - gen_op_eval_ble(r_dst, r_src); - break; - case 0x3: - gen_op_eval_bl(r_dst, r_src); - break; - case 0x4: - gen_op_eval_bleu(r_dst, r_src); - break; - case 0x5: - gen_op_eval_bcs(r_dst, r_src); - break; - case 0x6: - gen_op_eval_bneg(r_dst, r_src); - break; - case 0x7: - gen_op_eval_bvs(r_dst, r_src); - break; - case 0x8: - gen_op_eval_ba(r_dst); - break; - case 0x9: - gen_op_eval_bne(r_dst, r_src); - break; - case 0xa: - gen_op_eval_bg(r_dst, r_src); - break; - case 0xb: - gen_op_eval_bge(r_dst, r_src); - break; - case 0xc: - gen_op_eval_bgu(r_dst, r_src); - break; - case 0xd: - gen_op_eval_bcc(r_dst, r_src); - break; - case 0xe: - gen_op_eval_bpos(r_dst, r_src); - break; - case 0xf: - gen_op_eval_bvc(r_dst, r_src); + /* FALLTHRU */ + + case CC_OP_FLAGS: + /* We're going to generate a boolean result. */ + cmp->cond = TCG_COND_NE; + cmp->is_bool = true; + cmp->g1 = cmp->g2 = false; + cmp->c1 = r_dst = tcg_temp_new(); + cmp->c2 = tcg_const_tl(0); + + switch (cond) { + case 0x0: + gen_op_eval_bn(r_dst); + break; + case 0x1: + gen_op_eval_be(r_dst, r_src); + break; + case 0x2: + gen_op_eval_ble(r_dst, r_src); + break; + case 0x3: + gen_op_eval_bl(r_dst, r_src); + break; + case 0x4: + gen_op_eval_bleu(r_dst, r_src); + break; + case 0x5: + gen_op_eval_bcs(r_dst, r_src); + break; + case 0x6: + gen_op_eval_bneg(r_dst, r_src); + break; + case 0x7: + gen_op_eval_bvs(r_dst, r_src); + break; + case 0x8: + gen_op_eval_ba(r_dst); + break; + case 0x9: + gen_op_eval_bne(r_dst, r_src); + break; + case 0xa: + gen_op_eval_bg(r_dst, r_src); + break; + case 0xb: + gen_op_eval_bge(r_dst, r_src); + break; + case 0xc: + gen_op_eval_bgu(r_dst, r_src); + break; + case 0xd: + gen_op_eval_bcc(r_dst, r_src); + break; + case 0xe: + gen_op_eval_bpos(r_dst, r_src); + break; + case 0xf: + gen_op_eval_bvc(r_dst, r_src); + break; + } break; } } -static inline void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) +static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond) { unsigned int offset; + TCGv r_dst; + + /* For now we still generate a straight boolean result. */ + cmp->cond = TCG_COND_NE; + cmp->is_bool = true; + cmp->g1 = cmp->g2 = false; + cmp->c1 = r_dst = tcg_temp_new(); + cmp->c2 = tcg_const_tl(0); switch (cc) { default: @@ -1312,6 +1277,37 @@ static inline void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) } } +static void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond, + DisasContext *dc) +{ + DisasCompare cmp; + gen_compare(&cmp, cc, cond, dc); + + /* The interface is to return a boolean in r_dst. */ + if (cmp.is_bool) { + tcg_gen_mov_tl(r_dst, cmp.c1); + } else { + tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); + } + + free_compare(&cmp); +} + +static void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) +{ + DisasCompare cmp; + gen_fcompare(&cmp, cc, cond); + + /* The interface is to return a boolean in r_dst. */ + if (cmp.is_bool) { + tcg_gen_mov_tl(r_dst, cmp.c1); + } else { + tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); + } + + free_compare(&cmp); +} + #ifdef TARGET_SPARC64 // Inverted logic static const int gen_tcg_cond_reg[8] = { @@ -1325,20 +1321,29 @@ static const int gen_tcg_cond_reg[8] = { TCG_COND_LT, }; +static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src) +{ + cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]); + cmp->is_bool = false; + cmp->g1 = true; + cmp->g2 = false; + cmp->c1 = r_src; + cmp->c2 = tcg_const_tl(0); +} + static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src) { - int l1; + DisasCompare cmp; + gen_compare_reg(&cmp, cond, r_src); - l1 = gen_new_label(); - tcg_gen_movi_tl(r_dst, 0); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], r_src, 0, l1); - tcg_gen_movi_tl(r_dst, 1); - gen_set_label(l1); + /* The interface is to return a boolean in r_dst. */ + tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); + + free_compare(&cmp); } #endif -static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, - TCGv r_cond) +static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -1368,10 +1373,10 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, tcg_gen_mov_tl(cpu_pc, cpu_npc); } } else { - flush_cond(dc, r_cond); - gen_cond(r_cond, cc, cond, dc); + flush_cond(dc); + gen_cond(cpu_cond, cc, cond, dc); if (a) { - gen_branch_a(dc, target, dc->npc, r_cond); + gen_branch_a(dc, target, dc->npc, cpu_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -1387,8 +1392,7 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, } } -static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, - TCGv r_cond) +static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -1418,10 +1422,10 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, tcg_gen_mov_tl(cpu_pc, cpu_npc); } } else { - flush_cond(dc, r_cond); - gen_fcond(r_cond, cc, cond); + flush_cond(dc); + gen_fcond(cpu_cond, cc, cond); if (a) { - gen_branch_a(dc, target, dc->npc, r_cond); + gen_branch_a(dc, target, dc->npc, cpu_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -1439,7 +1443,7 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, #ifdef TARGET_SPARC64 static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, - TCGv r_cond, TCGv r_reg) + TCGv r_reg) { unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -1447,10 +1451,10 @@ static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, if (unlikely(AM_CHECK(dc))) { target &= 0xffffffffULL; } - flush_cond(dc, r_cond); - gen_cond_reg(r_cond, cond, r_reg); + flush_cond(dc); + gen_cond_reg(cpu_cond, cond, r_reg); if (a) { - gen_branch_a(dc, target, dc->npc, r_cond); + gen_branch_a(dc, target, dc->npc, cpu_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -1617,13 +1621,13 @@ static inline void gen_op_fpexception_im(int fsr_flags) tcg_temp_free_i32(r_const); } -static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond) +static int gen_trap_ifnofpu(DisasContext *dc) { #if !defined(CONFIG_USER_ONLY) if (!dc->fpu_enabled) { TCGv_i32 r_const; - save_state(dc, r_cond); + save_state(dc); r_const = tcg_const_i32(TT_NFPU_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -2210,6 +2214,57 @@ static inline TCGv get_src2(unsigned int insn, TCGv def) } #ifdef TARGET_SPARC64 +static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs) +{ + TCGv_i32 c32, zero, dst, s1, s2; + + /* We have two choices here: extend the 32 bit data and use movcond_i64, + or fold the comparison down to 32 bits and use movcond_i32. Choose + the later. */ + c32 = tcg_temp_new_i32(); + if (cmp->is_bool) { + tcg_gen_trunc_i64_i32(c32, cmp->c1); + } else { + TCGv_i64 c64 = tcg_temp_new_i64(); + tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2); + tcg_gen_trunc_i64_i32(c32, c64); + tcg_temp_free_i64(c64); + } + + s1 = gen_load_fpr_F(dc, rs); + s2 = gen_load_fpr_F(dc, rd); + dst = gen_dest_fpr_F(); + zero = tcg_const_i32(0); + + tcg_gen_movcond_i32(TCG_COND_NE, dst, c32, zero, s1, s2); + + tcg_temp_free_i32(c32); + tcg_temp_free_i32(zero); + gen_store_fpr_F(dc, rd, dst); +} + +static void gen_fmovd(DisasContext *dc, DisasCompare *cmp, int rd, int rs) +{ + TCGv_i64 dst = gen_dest_fpr_D(); + tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, cmp->c2, + gen_load_fpr_D(dc, rs), + gen_load_fpr_D(dc, rd)); + gen_store_fpr_D(dc, rd, dst); +} + +static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs) +{ + int qd = QFPREG(rd); + int qs = QFPREG(rs); + + tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2], cmp->c1, cmp->c2, + cpu_fpr[qs / 2], cpu_fpr[qd / 2]); + tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, cmp->c2, + cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]); + + gen_update_fprs_dirty(qd); +} + static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env) { TCGv_i32 r_tl = tcg_temp_new_i32(); @@ -2421,9 +2476,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target <<= 2; cc = GET_FIELD_SP(insn, 20, 21); if (cc == 0) - do_branch(dc, target, insn, 0, cpu_cond); + do_branch(dc, target, insn, 0); else if (cc == 2) - do_branch(dc, target, insn, 1, cpu_cond); + do_branch(dc, target, insn, 1); else goto illegal_insn; goto jmp_insn; @@ -2435,18 +2490,19 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target = sign_extend(target, 16); target <<= 2; cpu_src1 = get_src1(insn, cpu_src1); - do_branch_reg(dc, target, insn, cpu_cond, cpu_src1); + do_branch_reg(dc, target, insn, cpu_src1); goto jmp_insn; } case 0x5: /* V9 FBPcc */ { int cc = GET_FIELD_SP(insn, 20, 21); - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } target = GET_FIELD_SP(insn, 0, 18); target = sign_extend(target, 19); target <<= 2; - do_fbranch(dc, target, insn, cc, cpu_cond); + do_fbranch(dc, target, insn, cc); goto jmp_insn; } #else @@ -2460,17 +2516,18 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; - do_branch(dc, target, insn, 0, cpu_cond); + do_branch(dc, target, insn, 0); goto jmp_insn; } case 0x6: /* FBN+x */ { - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; - do_fbranch(dc, target, insn, 0, cpu_cond); + do_fbranch(dc, target, insn, 0); goto jmp_insn; } case 0x4: /* SETHI */ @@ -2499,7 +2556,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_movl_TN_reg(15, r_const); tcg_temp_free(r_const); target += dc->pc; - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); #ifdef TARGET_SPARC64 if (unlikely(AM_CHECK(dc))) { target &= 0xffffffffULL; @@ -2512,70 +2569,89 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { unsigned int xop = GET_FIELD(insn, 7, 12); if (xop == 0x3a) { /* generate trap */ - int cond; + int cond = GET_FIELD(insn, 3, 6); + TCGv_i32 trap; + int l1 = -1, mask; - cpu_src1 = get_src1(insn, cpu_src1); - if (IS_IMM) { - rs2 = GET_FIELD(insn, 25, 31); - tcg_gen_addi_tl(cpu_dst, cpu_src1, rs2); - } else { - rs2 = GET_FIELD(insn, 27, 31); - if (rs2 != 0) { - gen_movl_reg_TN(rs2, cpu_src2); - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); - } else - tcg_gen_mov_tl(cpu_dst, cpu_src1); + if (cond == 0) { + /* Trap never. */ + break; } - cond = GET_FIELD(insn, 3, 6); - if (cond == 0x8) { /* Trap Always */ - save_state(dc, cpu_cond); - if ((dc->def->features & CPU_FEATURE_HYPV) && - supervisor(dc)) - tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK); - else - tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK); - tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst); - gen_helper_raise_exception(cpu_env, cpu_tmp32); - - } else if (cond != 0) { - TCGv r_cond = tcg_temp_new(); - int l1; + save_state(dc); + + if (cond != 8) { + /* Conditional trap. */ + DisasCompare cmp; #ifdef TARGET_SPARC64 /* V9 icc/xcc */ int cc = GET_FIELD_SP(insn, 11, 12); - - save_state(dc, cpu_cond); - if (cc == 0) - gen_cond(r_cond, 0, cond, dc); - else if (cc == 2) - gen_cond(r_cond, 1, cond, dc); - else + if (cc == 0) { + gen_compare(&cmp, 0, cond, dc); + } else if (cc == 2) { + gen_compare(&cmp, 1, cond, dc); + } else { goto illegal_insn; + } #else - save_state(dc, cpu_cond); - gen_cond(r_cond, 0, cond, dc); + gen_compare(&cmp, 0, cond, dc); #endif l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + tcg_gen_brcond_tl(tcg_invert_cond(cmp.cond), + cmp.c1, cmp.c2, l1); + free_compare(&cmp); + } - if ((dc->def->features & CPU_FEATURE_HYPV) && - supervisor(dc)) - tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK); - else - tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK); - tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst); - gen_helper_raise_exception(cpu_env, cpu_tmp32); + mask = ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc) + ? UA2005_HTRAP_MASK : V8_TRAP_MASK); + + /* Don't use the normal temporaries, as they may well have + gone out of scope with the branch above. While we're + doing that we might as well pre-truncate to 32-bit. */ + trap = tcg_temp_new_i32(); + rs1 = GET_FIELD_SP(insn, 14, 18); + if (IS_IMM) { + rs2 = GET_FIELD_SP(insn, 0, 6); + if (rs1 == 0) { + tcg_gen_movi_i32(trap, (rs2 & mask) + TT_TRAP); + /* Signal that the trap value is fully constant. */ + mask = 0; + } else { + TCGv t1 = tcg_temp_new(); + gen_movl_reg_TN(rs1, t1); + tcg_gen_trunc_tl_i32(trap, t1); + tcg_temp_free(t1); + tcg_gen_addi_i32(trap, trap, rs2); + } + } else { + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_TN(rs1, t1); + gen_movl_reg_TN(rs2, t2); + tcg_gen_add_tl(t1, t1, t2); + tcg_gen_trunc_tl_i32(trap, t1); + tcg_temp_free(t1); + tcg_temp_free(t2); + } + if (mask != 0) { + tcg_gen_andi_i32(trap, trap, mask); + tcg_gen_addi_i32(trap, trap, TT_TRAP); + } + + gen_helper_raise_exception(cpu_env, trap); + tcg_temp_free_i32(trap); + + if (cond == 8) { + /* An unconditional trap ends the TB. */ + dc->is_br = 1; + goto jmp_insn; + } else { + /* A conditional trap falls through to the next insn. */ gen_set_label(l1); - tcg_temp_free(r_cond); + break; } - gen_op_next_insn(); - tcg_gen_exit_tb(0); - dc->is_br = 1; - goto jmp_insn; } else if (xop == 0x28) { rs1 = GET_FIELD(insn, 13, 17); switch(rs1) { @@ -2645,8 +2721,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0xf: /* V9 membar */ break; /* no effect */ case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } gen_movl_TN_reg(rd, cpu_gsr); break; case 0x16: /* Softint */ @@ -2853,7 +2930,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 - save_state(dc, cpu_cond); + save_state(dc); gen_helper_flushw(cpu_env); #else if (!supervisor(dc)) @@ -2863,13 +2940,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #endif } else if (xop == 0x34) { /* FPU Operations */ - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); - save_state(dc, cpu_cond); + save_state(dc); switch (xop) { case 0x1: /* fmovs */ cpu_src1_32 = gen_load_fpr_F(dc, rs2); @@ -3037,216 +3115,121 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #ifdef TARGET_SPARC64 int cond; #endif - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); - save_state(dc, cpu_cond); -#ifdef TARGET_SPARC64 - if ((xop & 0x11f) == 0x005) { // V9 fmovsr - int l1; + save_state(dc); - l1 = gen_new_label(); - cond = GET_FIELD_SP(insn, 14, 17); - cpu_src1 = get_src1(insn, cpu_src1); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, - 0, l1); - cpu_src1_32 = gen_load_fpr_F(dc, rs2); - gen_store_fpr_F(dc, rd, cpu_src1_32); - gen_set_label(l1); +#ifdef TARGET_SPARC64 +#define FMOVR(sz) \ + do { \ + DisasCompare cmp; \ + cond = GET_FIELD_SP(insn, 14, 17); \ + cpu_src1 = get_src1(insn, cpu_src1); \ + gen_compare_reg(&cmp, cond, cpu_src1); \ + gen_fmov##sz(dc, &cmp, rd, rs2); \ + free_compare(&cmp); \ + } while (0) + + if ((xop & 0x11f) == 0x005) { /* V9 fmovsr */ + FMOVR(s); break; } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr - int l1; - - l1 = gen_new_label(); - cond = GET_FIELD_SP(insn, 14, 17); - cpu_src1 = get_src1(insn, cpu_src1); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, - 0, l1); - cpu_src1_64 = gen_load_fpr_D(dc, rs2); - gen_store_fpr_D(dc, rd, cpu_src1_64); - gen_set_label(l1); + FMOVR(d); break; } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr - int l1; - CHECK_FPU_FEATURE(dc, FLOAT128); - l1 = gen_new_label(); - cond = GET_FIELD_SP(insn, 14, 17); - cpu_src1 = get_src1(insn, cpu_src1); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, - 0, l1); - gen_move_Q(rd, rs2); - gen_set_label(l1); + FMOVR(q); break; } +#undef FMOVR #endif switch (xop) { #ifdef TARGET_SPARC64 -#define FMOVSCC(fcc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_fcond(r_cond, fcc, cond); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_32 = gen_load_fpr_F(dc, rs2); \ - gen_store_fpr_F(dc, rd, cpu_src1_32); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVDCC(fcc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_fcond(r_cond, fcc, cond); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_64 = gen_load_fpr_D(dc, rs2); \ - gen_store_fpr_D(dc, rd, cpu_src1_64); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVQCC(fcc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ +#define FMOVCC(fcc, sz) \ + do { \ + DisasCompare cmp; \ cond = GET_FIELD_SP(insn, 14, 17); \ - gen_fcond(r_cond, fcc, cond); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - gen_move_Q(rd, rs2); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } + gen_fcompare(&cmp, fcc, cond); \ + gen_fmov##sz(dc, &cmp, rd, rs2); \ + free_compare(&cmp); \ + } while (0) + case 0x001: /* V9 fmovscc %fcc0 */ - FMOVSCC(0); + FMOVCC(0, s); break; case 0x002: /* V9 fmovdcc %fcc0 */ - FMOVDCC(0); + FMOVCC(0, d); break; case 0x003: /* V9 fmovqcc %fcc0 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(0); + FMOVCC(0, q); break; case 0x041: /* V9 fmovscc %fcc1 */ - FMOVSCC(1); + FMOVCC(1, s); break; case 0x042: /* V9 fmovdcc %fcc1 */ - FMOVDCC(1); + FMOVCC(1, d); break; case 0x043: /* V9 fmovqcc %fcc1 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(1); + FMOVCC(1, q); break; case 0x081: /* V9 fmovscc %fcc2 */ - FMOVSCC(2); + FMOVCC(2, s); break; case 0x082: /* V9 fmovdcc %fcc2 */ - FMOVDCC(2); + FMOVCC(2, d); break; case 0x083: /* V9 fmovqcc %fcc2 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(2); + FMOVCC(2, q); break; case 0x0c1: /* V9 fmovscc %fcc3 */ - FMOVSCC(3); + FMOVCC(3, s); break; case 0x0c2: /* V9 fmovdcc %fcc3 */ - FMOVDCC(3); + FMOVCC(3, d); break; case 0x0c3: /* V9 fmovqcc %fcc3 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(3); + FMOVCC(3, q); break; -#undef FMOVSCC -#undef FMOVDCC -#undef FMOVQCC -#define FMOVSCC(icc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ +#undef FMOVCC +#define FMOVCC(xcc, sz) \ + do { \ + DisasCompare cmp; \ cond = GET_FIELD_SP(insn, 14, 17); \ - gen_cond(r_cond, icc, cond, dc); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_32 = gen_load_fpr_F(dc, rs2); \ - gen_store_fpr_F(dc, rd, cpu_src1_32); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVDCC(icc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_cond(r_cond, icc, cond, dc); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_64 = gen_load_fpr_D(dc, rs2); \ - gen_store_fpr_D(dc, rd, cpu_src1_64); \ - gen_update_fprs_dirty(DFPREG(rd)); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVQCC(icc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_cond(r_cond, icc, cond, dc); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - gen_move_Q(rd, rs2); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } + gen_compare(&cmp, xcc, cond, dc); \ + gen_fmov##sz(dc, &cmp, rd, rs2); \ + free_compare(&cmp); \ + } while (0) case 0x101: /* V9 fmovscc %icc */ - FMOVSCC(0); + FMOVCC(0, s); break; case 0x102: /* V9 fmovdcc %icc */ - FMOVDCC(0); + FMOVCC(0, d); break; case 0x103: /* V9 fmovqcc %icc */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(0); + FMOVCC(0, q); break; case 0x181: /* V9 fmovscc %xcc */ - FMOVSCC(1); + FMOVCC(1, s); break; case 0x182: /* V9 fmovdcc %xcc */ - FMOVDCC(1); + FMOVCC(1, d); break; case 0x183: /* V9 fmovqcc %xcc */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(1); + FMOVCC(1, q); break; -#undef FMOVSCC -#undef FMOVDCC -#undef FMOVQCC +#undef FMOVCC #endif case 0x51: /* fcmps, V9 %fcc */ cpu_src1_32 = gen_load_fpr_F(dc, rs1); @@ -3548,17 +3531,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #ifdef TARGET_SPARC64 case 0xd: /* V9 udivx */ - { - TCGv r_temp1, r_temp2; - r_temp1 = tcg_temp_local_new(); - r_temp2 = tcg_temp_local_new(); - tcg_gen_mov_tl(r_temp1, cpu_src1); - tcg_gen_mov_tl(r_temp2, cpu_src2); - gen_trap_ifdivzero_tl(r_temp2); - tcg_gen_divu_i64(cpu_dst, r_temp1, r_temp2); - tcg_temp_free(r_temp1); - tcg_temp_free(r_temp2); - } + gen_helper_udivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); break; #endif case 0xe: /* udiv */ @@ -3592,29 +3565,27 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cpu_src2 = get_src2(insn, cpu_src2); switch (xop) { case 0x20: /* taddcc */ - gen_op_tadd_cc(cpu_dst, cpu_src1, cpu_src2); + gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADD); dc->cc_op = CC_OP_TADD; break; case 0x21: /* tsubcc */ - gen_op_tsub_cc(cpu_dst, cpu_src1, cpu_src2); + gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUB); dc->cc_op = CC_OP_TSUB; break; case 0x22: /* taddcctv */ - save_state(dc, cpu_cond); - gen_op_tadd_ccTV(cpu_dst, cpu_src1, cpu_src2); + gen_helper_taddcctv(cpu_dst, cpu_env, + cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADDTV); dc->cc_op = CC_OP_TADDTV; break; case 0x23: /* tsubcctv */ - save_state(dc, cpu_cond); - gen_op_tsub_ccTV(cpu_dst, cpu_src1, cpu_src2); + gen_helper_tsubcctv(cpu_dst, cpu_env, + cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUBTV); dc->cc_op = CC_OP_TSUBTV; break; case 0x24: /* mulscc */ @@ -3688,7 +3659,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x6: /* V9 wrfprs */ tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); tcg_gen_trunc_tl_i32(cpu_fprs, cpu_dst); - save_state(dc, cpu_cond); + save_state(dc); gen_op_next_insn(); tcg_gen_exit_tb(0); dc->is_br = 1; @@ -3701,8 +3672,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif break; case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2); break; case 0x14: /* Softint set */ @@ -3814,7 +3786,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_wrpsr(cpu_env, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; - save_state(dc, cpu_cond); + save_state(dc); gen_op_next_insn(); tcg_gen_exit_tb(0); dc->is_br = 1; @@ -3894,7 +3866,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv r_tmp = tcg_temp_local_new(); tcg_gen_mov_tl(r_tmp, cpu_tmp0); - save_state(dc, cpu_cond); + save_state(dc); gen_helper_wrpstate(cpu_env, r_tmp); tcg_temp_free(r_tmp); dc->npc = DYNAMIC_PC; @@ -3905,7 +3877,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv r_tmp = tcg_temp_local_new(); tcg_gen_mov_tl(r_tmp, cpu_tmp0); - save_state(dc, cpu_cond); + save_state(dc); tcg_gen_trunc_tl_i32(cpu_tmp32, r_tmp); tcg_temp_free(r_tmp); tcg_gen_st_i32(cpu_tmp32, cpu_env, @@ -3987,7 +3959,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) switch (rd) { case 0: // hpstate // XXX gen_op_wrhpstate(); - save_state(dc, cpu_cond); + save_state(dc); gen_op_next_insn(); tcg_gen_exit_tb(0); dc->is_br = 1; @@ -4027,42 +3999,38 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { int cc = GET_FIELD_SP(insn, 11, 12); int cond = GET_FIELD_SP(insn, 14, 17); - TCGv r_cond; - int l1; + DisasCompare cmp; - r_cond = tcg_temp_new(); if (insn & (1 << 18)) { - if (cc == 0) - gen_cond(r_cond, 0, cond, dc); - else if (cc == 2) - gen_cond(r_cond, 1, cond, dc); - else + if (cc == 0) { + gen_compare(&cmp, 0, cond, dc); + } else if (cc == 2) { + gen_compare(&cmp, 1, cond, dc); + } else { goto illegal_insn; + } } else { - gen_fcond(r_cond, cc, cond); + gen_fcompare(&cmp, cc, cond); } - l1 = gen_new_label(); - - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); - if (IS_IMM) { /* immediate */ - TCGv r_const; - + /* The get_src2 above loaded the normal 13-bit + immediate field, not the 11-bit field we have + in movcc. But it did handle the reg case. */ + if (IS_IMM) { simm = GET_FIELD_SPs(insn, 0, 10); - r_const = tcg_const_tl(simm); - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); - } else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_TN(rs2, cpu_tmp0); - gen_movl_TN_reg(rd, cpu_tmp0); + tcg_gen_movi_tl(cpu_src2, simm); } - gen_set_label(l1); - tcg_temp_free(r_cond); + + gen_movl_reg_TN(rd, cpu_dst); + tcg_gen_movcond_tl(cmp.cond, cpu_dst, + cmp.c1, cmp.c2, + cpu_src2, cpu_dst); + free_compare(&cmp); + gen_movl_TN_reg(rd, cpu_dst); break; } case 0x2d: /* V9 sdivx */ - gen_op_sdivx(cpu_dst, cpu_src1, cpu_src2); + gen_helper_sdivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); break; case 0x2e: /* V9 popc */ @@ -4074,27 +4042,24 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x2f: /* V9 movr */ { int cond = GET_FIELD_SP(insn, 10, 12); - int l1; - - cpu_src1 = get_src1(insn, cpu_src1); + DisasCompare cmp; - l1 = gen_new_label(); - - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], - cpu_src1, 0, l1); - if (IS_IMM) { /* immediate */ - TCGv r_const; + gen_compare_reg(&cmp, cond, cpu_src1); + /* The get_src2 above loaded the normal 13-bit + immediate field, not the 10-bit field we have + in movr. But it did handle the reg case. */ + if (IS_IMM) { simm = GET_FIELD_SPs(insn, 0, 9); - r_const = tcg_const_tl(simm); - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); - } else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_TN(rs2, cpu_tmp0); - gen_movl_TN_reg(rd, cpu_tmp0); + tcg_gen_movi_tl(cpu_src2, simm); } - gen_set_label(l1); + + gen_movl_reg_TN(rd, cpu_dst); + tcg_gen_movcond_tl(cmp.cond, cpu_dst, + cmp.c1, cmp.c2, + cpu_src2, cpu_dst); + free_compare(&cmp); + gen_movl_TN_reg(rd, cpu_dst); break; } #endif @@ -4107,8 +4072,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) int opf = GET_FIELD_SP(insn, 5, 13); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } switch (opf) { case 0x000: /* VIS I edge8cc */ @@ -4554,7 +4520,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else if (xop == 0x39) { /* V9 return */ TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); @@ -4568,7 +4534,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_mov_tl(cpu_dst, cpu_src1); } gen_helper_restore(cpu_env); - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); @@ -4598,7 +4564,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) r_pc = tcg_const_tl(dc->pc); gen_movl_TN_reg(rd, r_pc); tcg_temp_free(r_pc); - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); @@ -4614,7 +4580,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); @@ -4630,12 +4596,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) /* nop */ break; case 0x3c: /* save */ - save_state(dc, cpu_cond); + save_state(dc); gen_helper_save(cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x3d: /* restore */ - save_state(dc, cpu_cond); + save_state(dc); gen_helper_restore(cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; @@ -4718,7 +4684,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) else { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(7); /* XXX remove alignment check */ gen_helper_check_align(cpu_env, cpu_addr, r_const); @@ -4769,7 +4735,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 4, 0); break; case 0x11: /* lduba, load unsigned byte alternate */ @@ -4779,7 +4745,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 1, 0); break; case 0x12: /* lduha, load unsigned halfword alternate */ @@ -4789,7 +4755,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 2, 0); break; case 0x13: /* ldda, load double word alternate */ @@ -4801,7 +4767,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif if (rd & 1) goto illegal_insn; - save_state(dc, cpu_cond); + save_state(dc); gen_ldda_asi(cpu_val, cpu_addr, insn, rd); goto skip_move; case 0x19: /* ldsba, load signed byte alternate */ @@ -4811,7 +4777,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 1, 1); break; case 0x1a: /* ldsha, load signed halfword alternate */ @@ -4821,7 +4787,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 2, 1); break; case 0x1d: /* ldstuba -- XXX: should be atomically */ @@ -4831,7 +4797,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ldstub_asi(cpu_val, cpu_addr, insn); break; case 0x1f: /* swapa, swap reg with alt. memory. Also @@ -4843,7 +4809,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_movl_reg_TN(rd, cpu_val); gen_swap_asi(cpu_val, cpu_addr, insn); break; @@ -4865,28 +4831,28 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx); break; case 0x18: /* V9 ldswa */ - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 4, 1); break; case 0x1b: /* V9 ldxa */ - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 8, 0); break; case 0x2d: /* V9 prefetch, no effect */ goto skip_move; case 0x30: /* V9 ldfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); gen_ldf_asi(cpu_addr, insn, 4, rd); gen_update_fprs_dirty(rd); goto skip_move; case 0x33: /* V9 lddfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); goto skip_move; @@ -4894,10 +4860,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto skip_move; case 0x32: /* V9 ldqfa */ CHECK_FPU_FEATURE(dc, FLOAT128); - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); goto skip_move; @@ -4910,9 +4876,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) skip_move: ; #endif } else if (xop >= 0x20 && xop < 0x24) { - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; - save_state(dc, cpu_cond); + } + save_state(dc); switch (xop) { case 0x20: /* ldf, load fpreg */ gen_address_mask(dc, cpu_addr); @@ -4983,7 +4950,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) else { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); gen_address_mask(dc, cpu_addr); r_const = tcg_const_i32(7); /* XXX remove alignment check */ @@ -5002,7 +4969,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 4); dc->npc = DYNAMIC_PC; break; @@ -5013,7 +4980,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 1); dc->npc = DYNAMIC_PC; break; @@ -5024,7 +4991,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 2); dc->npc = DYNAMIC_PC; break; @@ -5038,7 +5005,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (rd & 1) goto illegal_insn; else { - save_state(dc, cpu_cond); + save_state(dc); gen_stda_asi(cpu_val, cpu_addr, insn, rd); } break; @@ -5049,7 +5016,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx); break; case 0x1e: /* V9 stxa */ - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 8); dc->npc = DYNAMIC_PC; break; @@ -5058,9 +5025,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; - save_state(dc, cpu_cond); + } + save_state(dc); switch (xop) { case 0x24: /* stf, store fpreg */ gen_address_mask(dc, cpu_addr); @@ -5102,8 +5070,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #else if (!supervisor(dc)) goto priv_insn; - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } goto nfq_insn; #endif #endif @@ -5116,11 +5085,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } } else if (xop > 0x33 && xop < 0x3f) { - save_state(dc, cpu_cond); + save_state(dc); switch (xop) { #ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } gen_stf_asi(cpu_addr, insn, 4, rd); @@ -5130,7 +5099,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_i32 r_const; CHECK_FPU_FEATURE(dc, FLOAT128); - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } r_const = tcg_const_i32(7); @@ -5140,7 +5109,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } break; case 0x37: /* V9 stdfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); @@ -5186,7 +5155,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_ILL_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -5197,7 +5166,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_UNIMP_FLUSH); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -5209,7 +5178,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_PRIV_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -5218,13 +5187,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto egress; #endif nfpu_insn: - save_state(dc, cpu_cond); + save_state(dc); gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); dc->is_br = 1; goto egress; #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) nfq_insn: - save_state(dc, cpu_cond); + save_state(dc); gen_op_fpexception_im(FSR_FTT_SEQ_ERROR); dc->is_br = 1; goto egress; @@ -5234,7 +5203,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_NCP_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free(r_const); @@ -5280,16 +5249,6 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, dc->singlestep = (env->singlestep_enabled || singlestep); gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - cpu_tmp0 = tcg_temp_new(); - cpu_tmp32 = tcg_temp_new_i32(); - cpu_tmp64 = tcg_temp_new_i64(); - - cpu_dst = tcg_temp_local_new(); - - // loads and stores - cpu_val = tcg_temp_local_new(); - cpu_addr = tcg_temp_local_new(); - num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) @@ -5300,7 +5259,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (bp->pc == dc->pc) { if (dc->pc != pc_start) - save_state(dc, cpu_cond); + save_state(dc); gen_helper_debug(cpu_env); tcg_gen_exit_tb(0); dc->is_br = 1; @@ -5325,9 +5284,24 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, gen_io_start(); last_pc = dc->pc; insn = cpu_ldl_code(env, dc->pc); + + cpu_tmp0 = tcg_temp_new(); + cpu_tmp32 = tcg_temp_new_i32(); + cpu_tmp64 = tcg_temp_new_i64(); + cpu_dst = tcg_temp_new(); + cpu_val = tcg_temp_new(); + cpu_addr = tcg_temp_new(); + disas_sparc_insn(dc, insn); num_insns++; + tcg_temp_free(cpu_addr); + tcg_temp_free(cpu_val); + tcg_temp_free(cpu_dst); + tcg_temp_free_i64(cpu_tmp64); + tcg_temp_free_i32(cpu_tmp32); + tcg_temp_free(cpu_tmp0); + if (dc->is_br) break; /* if the next PC is different, we abort now */ @@ -5347,24 +5321,19 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, num_insns < max_insns); exit_gen_loop: - tcg_temp_free(cpu_addr); - tcg_temp_free(cpu_val); - tcg_temp_free(cpu_dst); - tcg_temp_free_i64(cpu_tmp64); - tcg_temp_free_i32(cpu_tmp32); - tcg_temp_free(cpu_tmp0); - - if (tb->cflags & CF_LAST_IO) + if (tb->cflags & CF_LAST_IO) { gen_io_end(); + } if (!dc->is_br) { if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { /* static PC and NPC: we can use direct chaining */ gen_goto_tb(dc, 0, dc->pc, dc->npc); } else { - if (dc->pc != DYNAMIC_PC) + if (dc->pc != DYNAMIC_PC) { tcg_gen_movi_tl(cpu_pc, dc->pc); - save_npc(dc, cpu_cond); + } + save_npc(dc); tcg_gen_exit_tb(0); } } diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index 36f4f2f96..c3cdafa18 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -1932,8 +1932,6 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s) } ILLEGAL; } - - return; } /* generate intermediate code in gen_opc_buf and gen_opparam_buf for diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index b9acd706c..82e8cccad 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -1829,26 +1829,8 @@ static void disas_xtensa_insn(DisasContext *dc) int maskimm = (1 << (OP2 + 1)) - 1; TCGv_i32 tmp = tcg_temp_new_i32(); - - if (shiftimm) { - tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); - } else { - tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); - } - - switch (maskimm) { - case 0xff: - tcg_gen_ext8u_i32(cpu_R[RRR_R], tmp); - break; - - case 0xffff: - tcg_gen_ext16u_i32(cpu_R[RRR_R], tmp); - break; - - default: - tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); - break; - } + tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); + tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); tcg_temp_free(tmp); } break; diff --git a/tcg/README b/tcg/README index 27846f1ea..aa86992bc 100644 --- a/tcg/README +++ b/tcg/README @@ -88,8 +88,7 @@ supported. * Branches: -Use the instruction 'br' to jump to a label. Use 'jmp' to jump to an -explicit address. Conditional branches can only jump to labels. +Use the instruction 'br' to jump to a label. 3.3) Code Optimizations @@ -129,10 +128,6 @@ call function 'ptr' (pointer type) ********* Jumps/Labels -* jmp t0 - -Absolute jump to address t0 (pointer type). - * set_label $label Define label 'label' at the current program point. diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 2bad0a2b1..737200e5e 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -335,7 +335,7 @@ enum arm_cond_code_e { COND_AL = 0xe, }; -static const uint8_t tcg_cond_to_arm_cond[10] = { +static const uint8_t tcg_cond_to_arm_cond[] = { [TCG_COND_EQ] = COND_EQ, [TCG_COND_NE] = COND_NE, [TCG_COND_LT] = COND_LT, @@ -1197,20 +1197,11 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) case 1: case 2: default: - if (data_reg != TCG_REG_R0) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, - data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0)); - } + tcg_out_mov_reg(s, COND_AL, data_reg, TCG_REG_R0); break; case 3: - if (data_reg != TCG_REG_R0) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, - data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0)); - } - if (data_reg2 != TCG_REG_R1) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, - data_reg2, 0, TCG_REG_R1, SHIFT_IMM_LSL(0)); - } + tcg_out_mov_reg(s, COND_AL, data_reg, TCG_REG_R0); + tcg_out_mov_reg(s, COND_AL, data_reg2, TCG_REG_R1); break; } @@ -1530,12 +1521,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, else tcg_out_callr(s, COND_AL, args[0]); break; - case INDEX_op_jmp: - if (const_args[0]) - tcg_out_goto(s, COND_AL, args[0]); - else - tcg_out_bx(s, COND_AL, args[0]); - break; case INDEX_op_br: tcg_out_goto_label(s, COND_AL, args[0]); break; @@ -1769,7 +1754,6 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 2c79c1081..de500ae18 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -732,7 +732,7 @@ static void tcg_out_branch(TCGContext *s, int label_index, int nul) } } -static const uint8_t tcg_cond_to_cmp_cond[10] = +static const uint8_t tcg_cond_to_cmp_cond[] = { [TCG_COND_EQ] = COND_EQ, [TCG_COND_NE] = COND_EQ | COND_FALSE, @@ -814,19 +814,6 @@ static void tcg_out_comclr(TCGContext *s, int cond, TCGArg ret, tcg_out32(s, op); } -static TCGCond const tcg_high_cond[] = { - [TCG_COND_EQ] = TCG_COND_EQ, - [TCG_COND_NE] = TCG_COND_NE, - [TCG_COND_LT] = TCG_COND_LT, - [TCG_COND_LE] = TCG_COND_LT, - [TCG_COND_GT] = TCG_COND_GT, - [TCG_COND_GE] = TCG_COND_GT, - [TCG_COND_LTU] = TCG_COND_LTU, - [TCG_COND_LEU] = TCG_COND_LTU, - [TCG_COND_GTU] = TCG_COND_GTU, - [TCG_COND_GEU] = TCG_COND_GTU -}; - static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, TCGArg bl, int blconst, TCGArg bh, int bhconst, int label_index) @@ -841,7 +828,7 @@ static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, tcg_out_brcond(s, TCG_COND_NE, ah, bh, bhconst, label_index); break; default: - tcg_out_brcond(s, tcg_high_cond[cond], ah, bh, bhconst, label_index); + tcg_out_brcond(s, tcg_high_cond(cond), ah, bh, bhconst, label_index); tcg_out_comclr(s, TCG_COND_NE, TCG_REG_R0, ah, bh, bhconst); tcg_out_brcond(s, tcg_unsigned_cond(cond), al, bl, blconst, label_index); @@ -894,7 +881,7 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret, tcg_out_setcond(s, tcg_unsigned_cond(cond), scratch, al, bl, blconst); tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst); tcg_out_movi(s, TCG_TYPE_I32, scratch, 0); - tcg_out_comclr(s, tcg_invert_cond(tcg_high_cond[cond]), + tcg_out_comclr(s, tcg_invert_cond(tcg_high_cond(cond)), TCG_REG_R0, ah, bh, bhconst); tcg_out_movi(s, TCG_TYPE_I32, scratch, 1); break; @@ -1353,11 +1340,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, } break; - case INDEX_op_jmp: - fprintf(stderr, "unimplemented jmp\n"); - tcg_abort(); - break; - case INDEX_op_br: tcg_out_branch(s, args[0], 1); break; @@ -1592,7 +1574,6 @@ static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "r" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 0e218c861..4952c057b 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -338,7 +338,7 @@ static inline int tcg_target_const_match(tcg_target_long val, #define JCC_JLE 0xe #define JCC_JG 0xf -static const uint8_t tcg_cond_to_jcc[10] = { +static const uint8_t tcg_cond_to_jcc[] = { [TCG_COND_EQ] = JCC_JE, [TCG_COND_NE] = JCC_JNE, [TCG_COND_LT] = JCC_JL, @@ -1513,14 +1513,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_modrm(s, OPC_GRP5, EXT5_CALLN_Ev, args[0]); } break; - case INDEX_op_jmp: - if (const_args[0]) { - tcg_out_jmp(s, args[0]); - } else { - /* jmp *reg */ - tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, args[0]); - } - break; case INDEX_op_br: tcg_out_jxx(s, JCC_JMP, args[0], 0); break; @@ -1848,7 +1840,6 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, { INDEX_op_movi_i32, { "r" } }, diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index dc9c12cf1..705712f77 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -1916,9 +1916,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_goto_tb: tcg_out_goto_tb(s, args[0]); break; - case INDEX_op_jmp: - tcg_out_jmp(s, args[0]); - break; case INDEX_op_movi_i32: tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); @@ -2156,7 +2153,6 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_call, { "r" } }, { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_jmp, { "r" } }, { INDEX_op_mov_i32, { "r", "r" } }, { INDEX_op_movi_i32, { "r" } }, diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 34e3e7f82..7e4013e1e 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1322,10 +1322,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0); tcg_out_nop(s); break; - case INDEX_op_jmp: - tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0); - tcg_out_nop(s); - break; case INDEX_op_br: tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]); break; @@ -1577,7 +1573,6 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "C" } }, - { INDEX_op_jmp, { "r" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/optimize.c b/tcg/optimize.c index 35532a1e0..edb2b0ea9 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -321,6 +321,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, return (uint32_t)temps[x].val <= (uint32_t)temps[y].val; case TCG_COND_GTU: return (uint32_t)temps[x].val > (uint32_t)temps[y].val; + default: + break; } break; case 64: @@ -345,6 +347,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, return (uint64_t)temps[x].val <= (uint64_t)temps[y].val; case TCG_COND_GTU: return (uint64_t)temps[x].val > (uint64_t)temps[y].val; + default: + break; } break; } @@ -362,6 +366,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, case TCG_COND_LEU: case TCG_COND_EQ: return 1; + default: + break; } } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { switch (c) { diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 90c275d69..60b7b9262 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -437,7 +437,7 @@ enum { CR_SO }; -static const uint32_t tcg_to_bc[10] = { +static const uint32_t tcg_to_bc[] = { [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, @@ -1417,15 +1417,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_call: tcg_out_call (s, args[0], const_args[0]); break; - case INDEX_op_jmp: - if (const_args[0]) { - tcg_out_b (s, 0, args[0]); - } - else { - tcg_out32 (s, MTSPR | RS (args[0]) | CTR); - tcg_out32 (s, BCCTR | BO_ALWAYS); - } - break; case INDEX_op_movi_i32: tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); break; @@ -1904,7 +1895,6 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 19944bc42..5403fc1f9 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -418,7 +418,7 @@ enum { CR_SO }; -static const uint32_t tcg_to_bc[10] = { +static const uint32_t tcg_to_bc[] = { [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, @@ -1245,15 +1245,6 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_call: tcg_out_call (s, args[0], const_args[0]); break; - case INDEX_op_jmp: - if (const_args[0]) { - tcg_out_b (s, 0, args[0]); - } - else { - tcg_out32 (s, MTSPR | RS (args[0]) | CTR); - tcg_out32 (s, BCCTR | BO_ALWAYS); - } - break; case INDEX_op_movi_i32: tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]); break; @@ -1588,7 +1579,6 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 3b90605fb..fd9286f52 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -268,7 +268,7 @@ static const int tcg_target_call_oarg_regs[] = { #define S390_CC_ALWAYS 15 /* Condition codes that result from a COMPARE and COMPARE LOGICAL. */ -static const uint8_t tcg_cond_to_s390_cond[10] = { +static const uint8_t tcg_cond_to_s390_cond[] = { [TCG_COND_EQ] = S390_CC_EQ, [TCG_COND_NE] = S390_CC_NE, [TCG_COND_LT] = S390_CC_LT, @@ -284,7 +284,7 @@ static const uint8_t tcg_cond_to_s390_cond[10] = { /* Condition codes that result from a LOAD AND TEST. Here, we have no unsigned instruction variation, however since the test is vs zero we can re-map the outcomes appropriately. */ -static const uint8_t tcg_cond_to_ltr_cond[10] = { +static const uint8_t tcg_cond_to_ltr_cond[] = { [TCG_COND_EQ] = S390_CC_EQ, [TCG_COND_NE] = S390_CC_NE, [TCG_COND_LT] = S390_CC_LT, @@ -1113,7 +1113,7 @@ static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val) static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, TCGArg c2, int c2const) { - bool is_unsigned = (c > TCG_COND_GT); + bool is_unsigned = is_unsigned_cond(c); if (c2const) { if (c2 == 0) { if (type == TCG_TYPE_I32) { @@ -2037,11 +2037,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; #endif /* TCG_TARGET_REG_BITS == 64 */ - case INDEX_op_jmp: - /* This one is obsolete and never emitted. */ - tcg_abort(); - break; - default: fprintf(stderr,"unimplemented opc 0x%x\n",opc); tcg_abort(); @@ -2052,7 +2047,6 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 8fd7f86de..0c32baa50 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -512,7 +512,7 @@ static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index) } #endif -static const uint8_t tcg_cond_to_bcond[10] = { +static const uint8_t tcg_cond_to_bcond[] = { [TCG_COND_EQ] = COND_E, [TCG_COND_NE] = COND_NE, [TCG_COND_LT] = COND_L, @@ -1097,7 +1097,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, /* delay slot */ tcg_out_nop(s); break; - case INDEX_op_jmp: case INDEX_op_br: tcg_out_branch_i32(s, COND_A, args[0]); tcg_out_nop(s); @@ -1367,7 +1366,6 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index bd93fe4f0..551845801 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -646,29 +646,49 @@ static inline void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) static inline void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, int label_index) { - tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index); + } } static inline void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1, int32_t arg2, int label_index) { - TCGv_i32 t0 = tcg_const_i32(arg2); - tcg_gen_brcond_i32(cond, arg1, t0, label_index); - tcg_temp_free_i32(t0); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_brcond_i32(cond, arg1, t0, label_index); + tcg_temp_free_i32(t0); + } } static inline void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i32(ret, 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i32(ret, 0); + } else { + tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); + } } static inline void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) { - TCGv_i32 t0 = tcg_const_i32(arg2); - tcg_gen_setcond_i32(cond, ret, arg1, t0); - tcg_temp_free_i32(t0); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i32(ret, 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i32(ret, 0); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_setcond_i32(cond, ret, arg1, t0); + tcg_temp_free_i32(t0); + } } static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) @@ -964,17 +984,27 @@ static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, int label_index) { - tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, - TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), - TCGV_HIGH(arg2), cond, label_index); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2), cond, label_index); + } } static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), - TCGV_LOW(arg1), TCGV_HIGH(arg1), - TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i32(TCGV_LOW(ret), 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i32(TCGV_LOW(ret), 0); + } else { + tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), + TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); + } tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } @@ -1273,13 +1303,23 @@ static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, int label_index) { - tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); + } } static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i64(ret, 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i64(ret, 0); + } else { + tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); + } } static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) @@ -1397,9 +1437,13 @@ static inline void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) static inline void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, int label_index) { - TCGv_i64 t0 = tcg_const_i64(arg2); - tcg_gen_brcond_i64(cond, arg1, t0, label_index); - tcg_temp_free_i64(t0); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_brcond_i64(cond, arg1, t0, label_index); + tcg_temp_free_i64(t0); + } } static inline void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index dbb0e3916..04cb7ca03 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -38,7 +38,6 @@ DEF(discard, 1, 0, 0, 0) DEF(set_label, 0, 0, 1, TCG_OPF_BB_END) DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ -DEF(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) #define IMPL(X) (X ? 0 : TCG_OPF_NOT_PRESENT) @@ -242,7 +242,6 @@ void tcg_context_init(TCGContext *s) int *sorted_args; memset(s, 0, sizeof(*s)); - s->temps = s->static_temps; s->nb_globals = 0; /* Count total number of arguments and allocate the corresponding @@ -864,6 +863,8 @@ static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) static const char * const cond_name[] = { + [TCG_COND_NEVER] = "never", + [TCG_COND_ALWAYS] = "always", [TCG_COND_EQ] = "eq", [TCG_COND_NE] = "ne", [TCG_COND_LT] = "lt", @@ -266,18 +266,28 @@ typedef int TCGv_i64; #define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1) #define TCG_CALL_DUMMY_ARG ((TCGArg)(-1)) +/* Conditions. Note that these are layed out for easy manipulation by + the the functions below: + bit 0 is used for inverting; + bit 1 is signed, + bit 2 is unsigned, + bit 3 is used with bit 0 for swapping signed/unsigned. */ typedef enum { - TCG_COND_EQ, - TCG_COND_NE, - TCG_COND_LT, - TCG_COND_GE, - TCG_COND_LE, - TCG_COND_GT, + /* non-signed */ + TCG_COND_NEVER = 0 | 0 | 0 | 0, + TCG_COND_ALWAYS = 0 | 0 | 0 | 1, + TCG_COND_EQ = 8 | 0 | 0 | 0, + TCG_COND_NE = 8 | 0 | 0 | 1, + /* signed */ + TCG_COND_LT = 0 | 0 | 2 | 0, + TCG_COND_GE = 0 | 0 | 2 | 1, + TCG_COND_LE = 8 | 0 | 2 | 0, + TCG_COND_GT = 8 | 0 | 2 | 1, /* unsigned */ - TCG_COND_LTU, - TCG_COND_GEU, - TCG_COND_LEU, - TCG_COND_GTU, + TCG_COND_LTU = 0 | 4 | 0 | 0, + TCG_COND_GEU = 0 | 4 | 0 | 1, + TCG_COND_LEU = 8 | 4 | 0 | 0, + TCG_COND_GTU = 8 | 4 | 0 | 1, } TCGCond; /* Invert the sense of the comparison. */ @@ -289,13 +299,34 @@ static inline TCGCond tcg_invert_cond(TCGCond c) /* Swap the operands in a comparison. */ static inline TCGCond tcg_swap_cond(TCGCond c) { - int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15); - return (TCGCond)(c ^ mask); + return c & 6 ? (TCGCond)(c ^ 9) : c; } +/* Create an "unsigned" version of a "signed" comparison. */ static inline TCGCond tcg_unsigned_cond(TCGCond c) { - return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c); + return c & 2 ? (TCGCond)(c ^ 6) : c; +} + +/* Must a comparison be considered unsigned? */ +static inline bool is_unsigned_cond(TCGCond c) +{ + return (c & 4) != 0; +} + +/* Create a "high" version of a double-word comparison. + This removes equality from a LTE or GTE comparison. */ +static inline TCGCond tcg_high_cond(TCGCond c) +{ + switch (c) { + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GEU: + case TCG_COND_LEU: + return (TCGCond)(c ^ 8); + default: + return c; + } } #define TEMP_VAL_DEAD 0 @@ -336,7 +367,6 @@ struct TCGContext { TCGPool *pool_first, *pool_current, *pool_first_large; TCGLabel *labels; int nb_labels; - TCGTemp *temps; /* globals first, temps after */ int nb_globals; int nb_temps; /* index of free temps, -1 if none */ @@ -362,7 +392,7 @@ struct TCGContext { int frame_reg; uint8_t *code_ptr; - TCGTemp static_temps[TCG_MAX_TEMPS]; + TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ TCGHelperInfo *helpers; int nb_helpers; diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index d272a906e..e93074083 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -69,7 +69,6 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { { INDEX_op_exit_tb, { NULL } }, { INDEX_op_goto_tb, { NULL } }, { INDEX_op_call, { RI } }, - { INDEX_op_jmp, { RI } }, { INDEX_op_br, { NULL } }, { INDEX_op_mov_i32, { R, R } }, @@ -583,9 +582,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_call: tcg_out_ri(s, const_args[0], args[0]); break; - case INDEX_op_jmp: - TODO(); - break; case INDEX_op_setcond_i32: tcg_out_r(s, args[0]); tcg_out_r(s, args[1]); @@ -505,7 +505,6 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) tci_write_reg(TCG_REG_R0, tmp64); #endif break; - case INDEX_op_jmp: case INDEX_op_br: label = tci_read_label(&tb_ptr); assert(tb_ptr == old_code_ptr + op_size); diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c index bfdcb46ef..f3ad75d52 100644 --- a/ui/vnc-auth-sasl.c +++ b/ui/vnc-auth-sasl.c @@ -617,7 +617,6 @@ void start_auth_sasl(VncState *vs) authabort: vnc_client_error(vs); - return; } diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c index 3aaa93928..a7f7d07ac 100644 --- a/ui/vnc-tls.c +++ b/ui/vnc-tls.c @@ -49,7 +49,7 @@ static int vnc_tls_initialize(void) if (gnutls_global_init () < 0) return 0; - /* XXX ought to re-generate diffie-hellmen params periodically */ + /* XXX ought to re-generate diffie-hellman params periodically */ if (gnutls_dh_params_init (&dh_params) < 0) return 0; if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) @@ -1023,7 +1023,6 @@ static void numa_add(const char *optarg) } nb_numa_nodes++; } - return; } static void smp_parse(const char *optarg) @@ -1700,17 +1699,23 @@ static const QEMUOption qemu_options[] = { static bool vga_available(void) { - return qdev_exists("VGA") || qdev_exists("isa-vga"); + return object_class_by_name("VGA") || object_class_by_name("isa-vga"); } static bool cirrus_vga_available(void) { - return qdev_exists("cirrus-vga") || qdev_exists("isa-cirrus-vga"); + return object_class_by_name("cirrus-vga") + || object_class_by_name("isa-cirrus-vga"); } static bool vmware_vga_available(void) { - return qdev_exists("vmware-svga"); + return object_class_by_name("vmware-svga"); +} + +static bool qxl_vga_available(void) +{ + return object_class_by_name("qxl-vga"); } static void select_vgahw (const char *p) @@ -1742,7 +1747,12 @@ static void select_vgahw (const char *p) } else if (strstart(p, "xenfb", &opts)) { vga_interface_type = VGA_XENFB; } else if (strstart(p, "qxl", &opts)) { - vga_interface_type = VGA_QXL; + if (qxl_vga_available()) { + vga_interface_type = VGA_QXL; + } else { + fprintf(stderr, "Error: QXL VGA not available\n"); + exit(0); + } } else if (!strstart(p, "none", &opts)) { invalid_vga: fprintf(stderr, "Unknown vga type: %s\n", p); @@ -3641,8 +3651,12 @@ int main(int argc, char **argv, char **envp) exit(1); /* If no default VGA is requested, the default is "none". */ - if (default_vga && cirrus_vga_available()) { - vga_model = "cirrus"; + if (default_vga) { + if (cirrus_vga_available()) { + vga_model = "cirrus"; + } else if (vga_available()) { + vga_model = "std"; + } } select_vgahw(vga_model); @@ -1092,7 +1092,6 @@ static void xen_read_physmap(XenIOState *state) QLIST_INSERT_HEAD(&state->physmap, physmap, list); } free(entries); - return; } int xen_hvm_init(void) |