diff options
216 files changed, 9762 insertions, 2882 deletions
@@ -44,6 +44,9 @@ QMP/qmp-commands.txt *.ky *.log *.pdf +*.cps +*.fns +*.kys *.pg *.pyc *.toc @@ -163,7 +163,10 @@ distclean: clean rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi rm -f config-all-devices.mak rm -f roms/seabios/config.mak roms/vgabios/config.mak - rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr + rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi + rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys + rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp + rm -f qemu-doc.vr rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr for d in $(TARGET_DIRS) $(QEMULIBS); do \ rm -rf $$d || exit 1 ; \ diff --git a/Makefile.target b/Makefile.target index d5761b7..0e0ef36 100644 --- a/Makefile.target +++ b/Makefile.target @@ -352,6 +352,8 @@ obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o obj-arm-y += syborg_virtio.o obj-arm-y += vexpress.o +obj-arm-y += strongarm.o +obj-arm-y += collie.o obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o @@ -24,7 +24,6 @@ #include "qemu-common.h" -#include "sysemu.h" #include "acl.h" #ifdef CONFIG_FNMATCH diff --git a/arch_init.h b/arch_init.h index c83360c..86ebc14 100644 --- a/arch_init.h +++ b/arch_init.h @@ -22,8 +22,6 @@ enum { extern const uint32_t arch_type; void select_soundhw(const char *optarg); -int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque); -int ram_load(QEMUFile *f, void *opaque, int version_id); void do_acpitable_option(const char *optarg); void do_smbios_option(const char *optarg); void cpudef_init(void); @@ -33,7 +33,6 @@ #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) #else #include "qemu-common.h" -#include "sysemu.h" #include "gdbstub.h" #endif @@ -22,7 +22,6 @@ * THE SOFTWARE. */ -#include "sysemu.h" #include "monitor.h" #include "qjson.h" #include "qint.h" diff --git a/block/qed-check.c b/block/qed-check.c index 4600932..ea4ebc8 100644 --- a/block/qed-check.c +++ b/block/qed-check.c @@ -72,7 +72,8 @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table) for (i = 0; i < s->table_nelems; i++) { uint64_t offset = table->offsets[i]; - if (!offset) { + if (qed_offset_is_unalloc_cluster(offset) || + qed_offset_is_zero_cluster(offset)) { continue; } @@ -111,7 +112,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table) unsigned int num_invalid_l2; uint64_t offset = table->offsets[i]; - if (!offset) { + if (qed_offset_is_unalloc_cluster(offset)) { continue; } diff --git a/block/qed-cluster.c b/block/qed-cluster.c index 0ec864b..3e19ad1 100644 --- a/block/qed-cluster.c +++ b/block/qed-cluster.c @@ -23,7 +23,8 @@ * @n: Maximum number of clusters * @offset: Set to first cluster offset * - * This function scans tables for contiguous allocated or free clusters. + * This function scans tables for contiguous clusters. A contiguous run of + * clusters may be allocated, unallocated, or zero. */ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s, QEDTable *table, @@ -38,9 +39,14 @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s, *offset = last; for (i = index + 1; i < end; i++) { - if (last == 0) { - /* Counting free clusters */ - if (table->offsets[i] != 0) { + if (qed_offset_is_unalloc_cluster(last)) { + /* Counting unallocated clusters */ + if (!qed_offset_is_unalloc_cluster(table->offsets[i])) { + break; + } + } else if (qed_offset_is_zero_cluster(last)) { + /* Counting zero clusters */ + if (!qed_offset_is_zero_cluster(table->offsets[i])) { break; } } else { @@ -87,14 +93,19 @@ static void qed_find_cluster_cb(void *opaque, int ret) n = qed_count_contiguous_clusters(s, request->l2_table->table, index, n, &offset); - ret = offset ? QED_CLUSTER_FOUND : QED_CLUSTER_L2; - len = MIN(find_cluster_cb->len, n * s->header.cluster_size - - qed_offset_into_cluster(s, find_cluster_cb->pos)); - - if (offset && !qed_check_cluster_offset(s, offset)) { + if (qed_offset_is_unalloc_cluster(offset)) { + ret = QED_CLUSTER_L2; + } else if (qed_offset_is_zero_cluster(offset)) { + ret = QED_CLUSTER_ZERO; + } else if (qed_check_cluster_offset(s, offset)) { + ret = QED_CLUSTER_FOUND; + } else { ret = -EINVAL; } + len = MIN(find_cluster_cb->len, n * s->header.cluster_size - + qed_offset_into_cluster(s, find_cluster_cb->pos)); + out: find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len); qemu_free(find_cluster_cb); @@ -132,7 +143,7 @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos, len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos); l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)]; - if (!l2_offset) { + if (qed_offset_is_unalloc_cluster(l2_offset)) { cb(opaque, QED_CLUSTER_L1, 0, len); return; } diff --git a/block/qed.c b/block/qed.c index 75ae244..c8c5930 100644 --- a/block/qed.c +++ b/block/qed.c @@ -573,7 +573,7 @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l { QEDIsAllocatedCB *cb = opaque; *cb->pnum = len / BDRV_SECTOR_SIZE; - cb->is_allocated = ret == QED_CLUSTER_FOUND; + cb->is_allocated = (ret == QED_CLUSTER_FOUND || ret == QED_CLUSTER_ZERO); } static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num, @@ -745,7 +745,10 @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos, * @table: L2 table * @index: First cluster index * @n: Number of contiguous clusters - * @cluster: First cluster byte offset in image file + * @cluster: First cluster offset + * + * The cluster offset may be an allocated byte offset in the image file, the + * zero cluster marker, or the unallocated cluster marker. */ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index, unsigned int n, uint64_t cluster) @@ -753,7 +756,10 @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index, int i; for (i = index; i < index + n; i++) { table->offsets[i] = cluster; - cluster += s->header.cluster_size; + if (!qed_offset_is_unalloc_cluster(cluster) && + !qed_offset_is_zero_cluster(cluster)) { + cluster += s->header.cluster_size; + } } } @@ -1075,6 +1081,7 @@ static void qed_aio_write_data(void *opaque, int ret, case QED_CLUSTER_L2: case QED_CLUSTER_L1: + case QED_CLUSTER_ZERO: qed_aio_write_alloc(acb, len); break; @@ -1114,8 +1121,12 @@ static void qed_aio_read_data(void *opaque, int ret, qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len); - /* Handle backing file and unallocated sparse hole reads */ - if (ret != QED_CLUSTER_FOUND) { + /* Handle zero cluster and backing file reads */ + if (ret == QED_CLUSTER_ZERO) { + qemu_iovec_memset(&acb->cur_qiov, 0, acb->cur_qiov.size); + qed_aio_next_io(acb, 0); + return; + } else if (ret != QED_CLUSTER_FOUND) { qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov, qed_aio_next_io, acb); return; diff --git a/block/qed.h b/block/qed.h index 2925e37..3e1ab84 100644 --- a/block/qed.h +++ b/block/qed.h @@ -161,6 +161,7 @@ typedef struct { enum { QED_CLUSTER_FOUND, /* cluster found */ + QED_CLUSTER_ZERO, /* zero cluster found */ QED_CLUSTER_L2, /* cluster missing in L2 */ QED_CLUSTER_L1, /* cluster missing in L1 */ }; @@ -298,4 +299,29 @@ static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset) qed_check_cluster_offset(s, end_offset); } +static inline bool qed_offset_is_cluster_aligned(BDRVQEDState *s, + uint64_t offset) +{ + if (qed_offset_into_cluster(s, offset)) { + return false; + } + return true; +} + +static inline bool qed_offset_is_unalloc_cluster(uint64_t offset) +{ + if (offset == 0) { + return true; + } + return false; +} + +static inline bool qed_offset_is_zero_cluster(uint64_t offset) +{ + if (offset == 1) { + return true; + } + return false; +} + #endif /* BLOCK_QED_H */ diff --git a/block/vpc.c b/block/vpc.c index 7b025be..56865da 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -505,12 +505,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) int ret = -EIO; // Read out options - while (options && options->name) { - if (!strcmp(options->name, "size")) { - total_sectors = options->value.n / 512; - } - options++; - } + total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n / + BDRV_SECTOR_SIZE; // Create the file fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); @@ -19,7 +19,6 @@ #include "qemu-common.h" #include "qemu-char.h" -#include "sysemu.h" #include "net.h" #include "bt-host.h" @@ -19,7 +19,6 @@ #include "qemu-common.h" #include "qemu-char.h" -#include "sysemu.h" #include "net.h" #include "hw/bt.h" diff --git a/buffered_file.c b/buffered_file.c index b5e2baf..41b42c3 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -14,7 +14,6 @@ #include "qemu-common.h" #include "hw/hw.h" #include "qemu-timer.h" -#include "sysemu.h" #include "qemu-char.h" #include "buffered_file.h" @@ -177,6 +177,7 @@ spice="" rbd="" smartcard="" smartcard_nss="" +opengl="no" # parse CC options first for opt do @@ -283,7 +284,7 @@ else fi case "$cpu" in - alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64) + alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64|unicore32) cpu="$cpu" ;; i386|i486|i586|i686|i86pc|BePC) @@ -814,6 +815,9 @@ case "$cpu" in hppa*) host_guest_base="yes" ;; + unicore32*) + host_guest_base="yes" + ;; esac [ -z "$guest_base" ] && guest_base="$host_guest_base" @@ -1048,6 +1052,7 @@ sh4eb-linux-user \ sparc-linux-user \ sparc64-linux-user \ sparc32plus-linux-user \ +unicore32-linux-user \ " fi # the following are Darwin specific @@ -1233,7 +1238,7 @@ else fi sdl=no fi -if test -n "$cross_prefix" && test "`basename $sdlconfig`" = sdl-config; then +if test -n "$cross_prefix" && test "$(basename "$sdlconfig")" = sdl-config; then echo warning: using "\"$sdlconfig\"" to detect cross-compiled sdl >&2 fi @@ -2633,7 +2638,7 @@ echo "docdir=$docdir" >> $config_host_mak echo "confdir=$confdir" >> $config_host_mak case "$cpu" in - i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64) + i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64|unicore32) ARCH=$cpu ;; armv4b|armv4l) @@ -3184,6 +3189,10 @@ case "$target_arch2" in s390x) target_nptl="yes" target_phys_bits=64 + target_long_alignment=8 + ;; + unicore32) + target_phys_bits=32 ;; *) echo "Unsupported target CPU" @@ -3266,14 +3275,7 @@ if test ! -z "$gdb_xml_files" ; then echo "TARGET_XML_FILES=$list" >> $config_target_mak fi -case "$target_arch2" in - i386|x86_64) - echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak - ;; - *) - echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak - ;; -esac +echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then echo "TARGET_HAS_BFLT=y" >> $config_target_mak @@ -138,6 +138,16 @@ typedef union { uint64_t ll; } CPU_DoubleU; +#if defined(FLOATX80) +typedef union { + floatx80 d; + struct { + uint64_t lower; + uint16_t upper; + } l; +} CPU_LDoubleU; +#endif + #if defined(CONFIG_SOFTFLOAT) typedef union { float128 q; diff --git a/cpu-common.h b/cpu-common.h index ef4e8da..96c02ae 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -68,14 +68,14 @@ void cpu_unregister_io_memory(int table_address); void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write); static inline void cpu_physical_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len) + void *buf, int len) { cpu_physical_memory_rw(addr, buf, len, 0); } static inline void cpu_physical_memory_write(target_phys_addr_t addr, - const uint8_t *buf, int len) + const void *buf, int len) { - cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); + cpu_physical_memory_rw(addr, (void *)buf, len, 1); } void *cpu_physical_memory_map(target_phys_addr_t addr, target_phys_addr_t *plen, @@ -267,6 +267,7 @@ int cpu_exec(CPUState *env1) env->cc_x = (env->sr >> 4) & 1; #elif defined(TARGET_ALPHA) #elif defined(TARGET_ARM) +#elif defined(TARGET_UNICORE32) #elif defined(TARGET_PPC) #elif defined(TARGET_LM32) #elif defined(TARGET_MICROBLAZE) @@ -335,6 +336,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_ARM) do_interrupt(env); +#elif defined(TARGET_UNICORE32) + do_interrupt(env); #elif defined(TARGET_SH4) do_interrupt(env); #elif defined(TARGET_ALPHA) @@ -343,6 +346,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_M68K) do_interrupt(0); +#elif defined(TARGET_S390X) + do_interrupt(env); #endif env->exception_index = -1; #endif @@ -367,7 +372,7 @@ int cpu_exec(CPUState *env1) } #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ - defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) + defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32) if (interrupt_request & CPU_INTERRUPT_HALT) { env->interrupt_request &= ~CPU_INTERRUPT_HALT; env->halted = 1; @@ -514,6 +519,12 @@ int cpu_exec(CPUState *env1) do_interrupt(env); next_tb = 0; } +#elif defined(TARGET_UNICORE32) + if (interrupt_request & CPU_INTERRUPT_HARD + && !(env->uncached_asr & ASR_I)) { + do_interrupt(env); + next_tb = 0; + } #elif defined(TARGET_SH4) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); @@ -551,6 +562,12 @@ int cpu_exec(CPUState *env1) do_interrupt(1); next_tb = 0; } +#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY) + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->psw.mask & PSW_MASK_EXT)) { + do_interrupt(env); + next_tb = 0; + } #endif /* Don't use the cached interupt_request value, do_interrupt may have updated the EXITTB flag. */ @@ -664,6 +681,7 @@ int cpu_exec(CPUState *env1) env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); #elif defined(TARGET_ARM) /* XXX: Save/restore host fpu exception state?. */ +#elif defined(TARGET_UNICORE32) #elif defined(TARGET_SPARC) #elif defined(TARGET_PPC) #elif defined(TARGET_LM32) @@ -790,7 +808,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, puc); + cpu_restore_state(tb, env, pc); } /* we restore the process signal mask as the sigreturn should @@ -155,7 +155,7 @@ static bool cpu_thread_is_idle(CPUState *env) return true; } -static bool all_cpu_threads_idle(void) +bool all_cpu_threads_idle(void) { CPUState *env; @@ -739,6 +739,9 @@ static void qemu_tcg_wait_io_event(void) CPUState *env; while (all_cpu_threads_idle()) { + /* Start accounting real time to the virtual clock if the CPUs + are idle. */ + qemu_clock_warp(vm_clock); qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex); } @@ -830,6 +833,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) while (1) { cpu_exec_all(); + if (use_icount && qemu_next_icount_deadline() <= 0) { + qemu_notify_event(); + } qemu_tcg_wait_io_event(); } @@ -1044,7 +1050,7 @@ static int tcg_cpu_exec(CPUState *env) qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); env->icount_decr.u16.low = 0; env->icount_extra = 0; - count = qemu_icount_round (qemu_next_deadline()); + count = qemu_icount_round(qemu_next_icount_deadline()); qemu_icount += count; decr = (count > 0xffff) ? 0xffff : count; count -= decr; @@ -1070,6 +1076,9 @@ bool cpu_exec_all(void) { int r; + /* Account partial waits to the vm_clock. */ + qemu_clock_warp(vm_clock); + if (next_cpu == NULL) { next_cpu = first_cpu; } @@ -8,6 +8,10 @@ void resume_all_vcpus(void); void pause_all_vcpus(void); void cpu_stop_current(void); +void cpu_synchronize_all_states(void); +void cpu_synchronize_all_post_reset(void); +void cpu_synchronize_all_post_init(void); + /* vl.c */ extern int smp_cores; extern int smp_threads; diff --git a/default-configs/unicore32-linux-user.mak b/default-configs/unicore32-linux-user.mak new file mode 100644 index 0000000..6aafd21 --- /dev/null +++ b/default-configs/unicore32-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for unicore32-linux-user diff --git a/device_tree.c b/device_tree.c index 21be070..f5d5eb1 100644 --- a/device_tree.c +++ b/device_tree.c @@ -20,7 +20,6 @@ #include "config.h" #include "qemu-common.h" -#include "sysemu.h" #include "device_tree.h" #include "hw/loader.h" @@ -345,7 +345,7 @@ monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, struct disassemble_info *info) { if (monitor_disas_is_physical) { - cpu_physical_memory_rw(memaddr, myaddr, length, 0); + cpu_physical_memory_read(memaddr, myaddr, length); } else { cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); } diff --git a/docs/specs/qed_spec.txt b/docs/specs/qed_spec.txt index 1d5fa87..7982e05 100644 --- a/docs/specs/qed_spec.txt +++ b/docs/specs/qed_spec.txt @@ -89,6 +89,7 @@ L1, L2, and data cluster offsets must be aligned to header.cluster_size. The fo ===Data cluster offsets=== * 0 - unallocated. The data cluster is not yet allocated. +* 1 - zero. The data cluster contents are all zeroes and no cluster is allocated. Future format extensions may wish to store per-offset information. The least significant 12 bits of an offset are reserved for this purpose and must be set to zero. Image files with cluster_size > 2^12 will have more unused bits which should also be zeroed. @@ -97,6 +98,13 @@ Reads to an unallocated area of the image file access the backing file. If ther Writes to an unallocated area cause a new data clusters to be allocated, and a new L2 table if that is also unallocated. The new data cluster is populated with data from the backing file (or zeroes if no backing file) and the data being written. +===Zero data clusters=== +Zero data clusters are a space-efficient way of storing zeroed regions of the image. + +Reads to a zero data cluster produce zeroes. Note that the difference between an unallocated and a zero data cluster is that zero data clusters stop the reading of contents from the backing file. + +Writes to a zero data cluster cause a new data cluster to be allocated. The new data cluster is populated with zeroes and the data being written. + ===Logical offset translation=== Logical offsets are translated into cluster offsets as follows: @@ -106,6 +106,8 @@ typedef int64_t Elf64_Sxword; #define EM_H8S 48 /* Hitachi H8S */ #define EM_LATTICEMICO32 138 /* LatticeMico32 */ +#define EM_UNICORE32 110 /* UniCore32 */ + /* * This is an interim value that we will use until the committee comes * up with a final number. @@ -77,15 +77,14 @@ extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc); +void restore_state_to_opc(CPUState *env, struct TranslationBlock *tb, + int pc_pos); void cpu_gen_init(void); int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int *gen_code_size_ptr); int cpu_restore_state(struct TranslationBlock *tb, - CPUState *env, unsigned long searched_pc, - void *puc); + CPUState *env, unsigned long searched_pc); void cpu_resume_from_signal(CPUState *env1, void *puc); void cpu_io_recompile(CPUState *env, void *retaddr); TranslationBlock *tb_gen_code(CPUState *env, @@ -1070,8 +1070,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, restore the CPU state */ current_tb_modified = 1; - cpu_restore_state(current_tb, env, - env->mem_io_pc, NULL); + cpu_restore_state(current_tb, env, env->mem_io_pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } @@ -1179,7 +1178,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, restore the CPU state */ current_tb_modified = 1; - cpu_restore_state(current_tb, env, pc, puc); + cpu_restore_state(current_tb, env, pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } @@ -3266,7 +3265,7 @@ static void check_watchpoint(int offset, int len_mask, int flags) cpu_abort(env, "check_watchpoint: could not find TB for " "pc=%p", (void *)env->mem_io_pc); } - cpu_restore_state(tb, env, env->mem_io_pc, NULL); + cpu_restore_state(tb, env, env->mem_io_pc); tb_phys_invalidate(tb, -1); if (wp->flags & BP_STOP_BEFORE_ACCESS) { env->exception_index = EXCP_DEBUG; @@ -3932,7 +3931,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, bounce.addr = addr; bounce.len = l; if (!is_write) { - cpu_physical_memory_rw(addr, bounce.buffer, l, 0); + cpu_physical_memory_read(addr, bounce.buffer, l); } ptr = bounce.buffer; } else { @@ -4253,7 +4252,7 @@ void stw_phys(target_phys_addr_t addr, uint32_t val) void stq_phys(target_phys_addr_t addr, uint64_t val) { val = tswap64(val); - cpu_physical_memory_write(addr, (const uint8_t *)&val, 8); + cpu_physical_memory_write(addr, &val, 8); } /* virtual memory access for debug (includes writing to ROM) */ @@ -4301,7 +4300,7 @@ void cpu_io_recompile(CPUState *env, void *retaddr) retaddr); } n = env->icount_decr.u16.low + tb->icount; - cpu_restore_state(tb, env, (unsigned long)retaddr, NULL); + cpu_restore_state(tb, env, (unsigned long)retaddr); /* Calculate how many instructions had been executed before the fault occurred. */ n = n - env->icount_decr.u16.low; diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h index 3128e60..e82ce233 100644 --- a/fpu/softfloat-macros.h +++ b/fpu/softfloat-macros.h @@ -36,6 +36,17 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ /*---------------------------------------------------------------------------- +| This macro tests for minimum version of the GNU C compiler. +*----------------------------------------------------------------------------*/ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define SOFTFLOAT_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define SOFTFLOAT_GNUC_PREREQ(maj, min) 0 +#endif + + +/*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero | bits are shifted off, they are ``jammed'' into the least significant bit of | the result by setting the least significant bit to 1. The value of `count' @@ -616,6 +627,13 @@ static uint32_t estimateSqrt32( int16 aExp, uint32_t a ) static int8 countLeadingZeros32( uint32_t a ) { +#if SOFTFLOAT_GNUC_PREREQ(3, 4) + if (a) { + return __builtin_clz(a); + } else { + return 32; + } +#else static const int8 countLeadingZerosHigh[] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -647,7 +665,7 @@ static int8 countLeadingZeros32( uint32_t a ) } shiftCount += countLeadingZerosHigh[ a>>24 ]; return shiftCount; - +#endif } /*---------------------------------------------------------------------------- @@ -657,6 +675,13 @@ static int8 countLeadingZeros32( uint32_t a ) static int8 countLeadingZeros64( uint64_t a ) { +#if SOFTFLOAT_GNUC_PREREQ(3, 4) + if (a) { + return __builtin_clzll(a); + } else { + return 64; + } +#else int8 shiftCount; shiftCount = 0; @@ -668,7 +693,7 @@ static int8 countLeadingZeros64( uint64_t a ) } shiftCount += countLeadingZeros32( a ); return shiftCount; - +#endif } /*---------------------------------------------------------------------------- diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 50355a4..8848651 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -263,6 +263,15 @@ int float32_is_quiet_nan( float32 a1 ) return ( 0xFF800000 < ( a<<1 ) ); } +int float32_is_any_nan( float32 a1 ) +{ + float32u u; + uint32_t a; + u.f = a1; + a = u.i; + return (a & ~(1 << 31)) > 0x7f800000U; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -422,6 +431,16 @@ int float64_is_quiet_nan( float64 a1 ) } +int float64_is_any_nan( float64 a1 ) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + + return (a & ~(1ULL << 63)) > LIT64 (0x7FF0000000000000 ); +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -511,4 +530,11 @@ int floatx80_is_quiet_nan( floatx80 a1 ) return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( u.i.low<<1 ); } +int floatx80_is_any_nan( floatx80 a1 ) +{ + floatx80u u; + u.f = a1; + return ((u.i.high & 0x7FFF) == 0x7FFF) && ( u.i.low<<1 ); +} + #endif diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 80b5f28..6afb74a 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -172,6 +172,15 @@ float128 int64_to_float128( int64_t STATUS_PARAM); #endif /*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define float32_zero (0.0) +#define float32_one (1.0) +#define float32_ln2 (0.6931471) +#define float32_pi (3.1415926) +#define float32_half (0.5) + +/*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ int float32_to_int32( float32 STATUS_PARAM); @@ -210,7 +219,7 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) } float32 float32_rem( float32, float32 STATUS_PARAM); float32 float32_sqrt( float32 STATUS_PARAM); -INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq_quiet( float32 a, float32 b STATUS_PARAM) { return a == b; } @@ -222,7 +231,7 @@ INLINE int float32_lt( float32 a, float32 b STATUS_PARAM) { return a < b; } -INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) { return a <= b && a >= b; } @@ -237,12 +246,16 @@ INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM) INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM) +{ + return isunordered(a, b); } int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); int float32_is_signaling_nan( float32 ); int float32_is_quiet_nan( float32 ); +int float32_is_any_nan( float32 ); INLINE float32 float32_abs(float32 a) { @@ -271,12 +284,21 @@ INLINE float32 float32_is_zero(float32 a) return fpclassify(a) == FP_ZERO; } -INLINE float32 float32_scalbn(float32 a, int n) +INLINE float32 float32_scalbn(float32 a, int n STATUS_PARAM) { return scalbnf(a, n); } /*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define float64_zero (0.0) +#define float64_one (1.0) +#define float64_ln2 (0.693147180559945) +#define float64_pi (3.141592653589793) +#define float64_half (0.5) + +/*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ int float64_to_int32( float64 STATUS_PARAM ); @@ -318,7 +340,7 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) } float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); -INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq_quiet( float64 a, float64 b STATUS_PARAM) { return a == b; } @@ -330,7 +352,7 @@ INLINE int float64_lt( float64 a, float64 b STATUS_PARAM) { return a < b; } -INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) { return a <= b && a >= b; } @@ -346,11 +368,15 @@ INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM) INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM) +{ + return isunordered(a, b); } int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); int float64_is_signaling_nan( float64 ); +int float64_is_any_nan( float64 ); int float64_is_quiet_nan( float64 ); INLINE float64 float64_abs(float64 a) @@ -380,7 +406,7 @@ INLINE float64 float64_is_zero(float64 a) return fpclassify(a) == FP_ZERO; } -INLINE float64 float64_scalbn(float64 a, int n) +INLINE float64 float64_scalbn(float64 a, int n STATUS_PARAM) { return scalbn(a, n); } @@ -388,6 +414,15 @@ INLINE float64 float64_scalbn(float64 a, int n) #ifdef FLOATX80 /*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define floatx80_zero (0.0L) +#define floatx80_one (1.0L) +#define floatx80_ln2 (0.69314718055994530943L) +#define floatx80_pi (3.14159265358979323851L) +#define floatx80_half (0.5L) + +/*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision conversion routines. *----------------------------------------------------------------------------*/ int floatx80_to_int32( floatx80 STATUS_PARAM ); @@ -422,7 +457,7 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) } floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); -INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM) { return a == b; } @@ -434,7 +469,7 @@ INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) { return a < b; } -INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) { return a <= b && a >= b; } @@ -450,12 +485,16 @@ INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isunordered(a, b); } int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_signaling_nan( floatx80 ); int floatx80_is_quiet_nan( floatx80 ); +int floatx80_is_any_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { @@ -484,7 +523,7 @@ INLINE floatx80 floatx80_is_zero(floatx80 a) return fpclassify(a) == FP_ZERO; } -INLINE floatx80 floatx80_scalbn(floatx80 a, int n) +INLINE floatx80 floatx80_scalbn(floatx80 a, int n STATUS_PARAM) { return scalbnl(a, n); } diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 4b65de6..9d68aae 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -93,7 +93,7 @@ float16 float16_maybe_silence_nan(float16 a_) { if (float16_is_signaling_nan(a_)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) return float16_default_nan; # else # error Rules for silencing a signaling NaN are target-specific @@ -184,7 +184,7 @@ float32 float32_maybe_silence_nan( float32 a_ ) { if (float32_is_signaling_nan(a_)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) return float32_default_nan; # else # error Rules for silencing a signaling NaN are target-specific @@ -430,7 +430,7 @@ float64 float64_maybe_silence_nan( float64 a_ ) { if (float64_is_signaling_nan(a_)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) return float64_default_nan; # else # error Rules for silencing a signaling NaN are target-specific @@ -578,7 +578,7 @@ floatx80 floatx80_maybe_silence_nan( floatx80 a ) { if (floatx80_is_signaling_nan(a)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) a.low = floatx80_default_nan_low; a.high = floatx80_default_nan_high; # else @@ -603,9 +603,15 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) commonNaNT z; if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); - z.sign = a.high>>15; - z.low = 0; - z.high = a.low; + if ( a.low >> 63 ) { + z.sign = a.high >> 15; + z.low = 0; + z.high = a.low << 1; + } else { + z.sign = floatx80_default_nan_high >> 15; + z.low = 0; + z.high = floatx80_default_nan_low << 1; + } return z; } @@ -624,11 +630,14 @@ static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM) return z; } - if (a.high) - z.low = a.high; - else + if (a.high >> 1) { + z.low = LIT64( 0x8000000000000000 ) | a.high >> 1; + z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF; + } else { z.low = floatx80_default_nan_low; - z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF; + z.high = floatx80_default_nan_high; + } + return z; } @@ -721,7 +730,7 @@ float128 float128_maybe_silence_nan( float128 a ) { if (float128_is_signaling_nan(a)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) a.low = float128_default_nan_low; a.high = float128_default_nan_high; # else diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 03fb948..baba1dc 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2314,33 +2314,33 @@ float32 float32_log2( float32 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_eq( float32 a, float32 b STATUS_PARAM ) { + uint32_t av, bv; a = float32_squash_input_denormal(a STATUS_VAR); b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { - if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( float32_val(a) == float32_val(b) ) || - ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); - + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| or equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_le( float32 a, float32 b STATUS_PARAM ) @@ -2367,8 +2367,9 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_lt( float32 a, float32 b STATUS_PARAM ) @@ -2394,15 +2395,14 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| Returns 1 if the single-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +int float32_unordered( float32 a, float32 b STATUS_PARAM ) { - uint32_t av, bv; a = float32_squash_input_denormal(a STATUS_VAR); b = float32_squash_input_denormal(b STATUS_VAR); @@ -2410,12 +2410,33 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { float_raise( float_flag_invalid STATUS_VAR); - return 0; + return 1; } - av = float32_val(a); - bv = float32_val(b); - return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); + return 0; +} +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_eq_quiet( float32 a, float32 b STATUS_PARAM ) +{ + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return ( float32_val(a) == float32_val(b) ) || + ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- @@ -2481,6 +2502,29 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM ) +{ + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the 32-bit two's complement integer format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point @@ -3536,7 +3580,8 @@ float64 float64_log2( float64 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The comparison is performed +| corresponding value `b', and 0 otherwise. The invalid exception is raised +| if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ @@ -3549,9 +3594,7 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { - if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } av = float64_val(a); @@ -3562,9 +3605,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than or -| equal to the corresponding value `b', and 0 otherwise. The comparison is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_le( float64 a, float64 b STATUS_PARAM ) @@ -3591,8 +3634,9 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_lt( float64 a, float64 b STATUS_PARAM ) @@ -3618,13 +3662,34 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_unordered( float64 a, float64 b STATUS_PARAM ) +{ + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The invalid exception is raised -| if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception.The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +int float64_eq_quiet( float64 a, float64 b STATUS_PARAM ) { uint64_t av, bv; a = float64_squash_input_denormal(a STATUS_VAR); @@ -3633,7 +3698,9 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } av = float64_val(a); @@ -3704,6 +3771,29 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM ) +{ + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -4501,10 +4591,10 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) } /*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is -| equal to the corresponding value `b', and 0 otherwise. The comparison is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| Returns 1 if the extended double-precision floating-point value `a' is equal +| to the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) @@ -4515,10 +4605,7 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { - if ( floatx80_is_signaling_nan( a ) - || floatx80_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } return @@ -4533,8 +4620,9 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is | less than or equal to the corresponding value `b', and 0 otherwise. The -| comparison is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. +| invalid exception is raised if either operand is a NaN. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) @@ -4565,9 +4653,9 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is -| less than the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| less than the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) @@ -4597,13 +4685,32 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is equal -| to the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| Returns 1 if the extended double-precision floating-point values `a' and `b' +| cannot be compared, and 0 otherwise. The invalid exception is raised if +| either operand is a NaN. The comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -4611,7 +4718,10 @@ int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } return @@ -4695,6 +4805,28 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point values `a' and `b' +| cannot be compared, and 0 otherwise. Quiet NaNs do not cause an exception. +| The comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #endif #ifdef FLOAT128 @@ -5625,7 +5757,8 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ @@ -5637,10 +5770,7 @@ int float128_eq( float128 a, float128 b STATUS_PARAM ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } return @@ -5654,9 +5784,9 @@ int float128_eq( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| or equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_le( float128 a, float128 b STATUS_PARAM ) @@ -5687,8 +5817,9 @@ int float128_le( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_lt( float128 a, float128 b STATUS_PARAM ) @@ -5718,13 +5849,33 @@ int float128_lt( float128 a, float128 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_unordered( float128 a, float128 b STATUS_PARAM ) +{ + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +int float128_eq_quiet( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5732,7 +5883,10 @@ int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } return @@ -5816,6 +5970,29 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM ) +{ + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #endif /* misc functions */ @@ -6013,6 +6190,52 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ COMPARE(32, 0xff) COMPARE(64, 0x7ff) +INLINE int floatx80_compare_internal( floatx80 a, floatx80 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloatx80Exp( a ) == 0x7fff ) && + ( extractFloatx80Frac( a )<<1 ) ) || + ( ( extractFloatx80Exp( b ) == 0x7fff ) && + ( extractFloatx80Frac( b )<<1 ) )) { + if (!is_quiet || + floatx80_is_signaling_nan( a ) || + floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + + if ( ( ( (uint16_t) ( ( a.high | b.high ) << 1 ) ) == 0) && + ( ( a.low | b.low ) == 0 ) ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +{ + return floatx80_compare_internal(a, b, 0 STATUS_VAR); +} + +int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + return floatx80_compare_internal(a, b, 1 STATUS_VAR); +} + INLINE int float128_compare_internal( float128 a, float128 b, int is_quiet STATUS_PARAM ) { @@ -6110,7 +6333,7 @@ MINMAX(64, 0x7ff) float32 float32_scalbn( float32 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; + int16_t aExp; uint32_t aSig; a = float32_squash_input_denormal(a STATUS_VAR); @@ -6119,6 +6342,9 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { + if ( aSig ) { + return propagateFloat32NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -6126,6 +6352,12 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) else if ( aSig == 0 ) return a; + if (n > 0x200) { + n = 0x200; + } else if (n < -0x200) { + n = -0x200; + } + aExp += n - 1; aSig <<= 7; return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); @@ -6134,7 +6366,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) float64 float64_scalbn( float64 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; + int16_t aExp; uint64_t aSig; a = float64_squash_input_denormal(a STATUS_VAR); @@ -6143,6 +6375,9 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { + if ( aSig ) { + return propagateFloat64NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -6150,6 +6385,12 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) else if ( aSig == 0 ) return a; + if (n > 0x1000) { + n = 0x1000; + } else if (n < -0x1000) { + n = -0x1000; + } + aExp += n - 1; aSig <<= 10; return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); @@ -6159,19 +6400,29 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; + int32_t aExp; uint64_t aSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); - if ( aExp == 0x7FF ) { + if ( aExp == 0x7FFF ) { + if ( aSig<<1 ) { + return propagateFloatx80NaN( a, a STATUS_VAR ); + } return a; } + if (aExp == 0 && aSig == 0) return a; + if (n > 0x10000) { + n = 0x10000; + } else if (n < -0x10000) { + n = -0x10000; + } + aExp += n; return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision), aSign, aExp, aSig, 0 STATUS_VAR ); @@ -6182,7 +6433,7 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) float128 float128_scalbn( float128 a, int n STATUS_PARAM ) { flag aSign; - int32 aExp; + int32_t aExp; uint64_t aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); @@ -6190,6 +6441,9 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM ) aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return propagateFloat128NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -6197,6 +6451,12 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM ) else if ( aSig0 == 0 && aSig1 == 0 ) return a; + if (n > 0x10000) { + n = 0x10000; + } else if (n < -0x10000) { + n = -0x10000; + } + aExp += n - 1; return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1 STATUS_VAR ); diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 90f4250..5eff085 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -68,7 +68,7 @@ typedef int64_t int64; #define LIT64( a ) a##LL #define INLINE static inline -#if defined(TARGET_MIPS) || defined(TARGET_SH4) +#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) #define SNAN_BIT_IS_ONE 1 #else #define SNAN_BIT_IS_ONE 0 @@ -154,6 +154,7 @@ typedef struct { uint64_t low; uint16_t high; } floatx80; +#define make_floatx80(exp, mant) ((floatx80) { mant, exp }) #endif #ifdef FLOAT128 typedef struct { @@ -211,6 +212,10 @@ typedef struct float_status { void set_float_rounding_mode(int val STATUS_PARAM); void set_float_exception_flags(int val STATUS_PARAM); +INLINE void set_float_detect_tininess(int val STATUS_PARAM) +{ + STATUS(float_detect_tininess) = val; +} INLINE void set_flush_to_zero(flag val STATUS_PARAM) { STATUS(flush_to_zero) = val; @@ -319,9 +324,11 @@ float32 float32_log2( float32 STATUS_PARAM ); int float32_eq( float32, float32 STATUS_PARAM ); int float32_le( float32, float32 STATUS_PARAM ); int float32_lt( float32, float32 STATUS_PARAM ); -int float32_eq_signaling( float32, float32 STATUS_PARAM ); +int float32_unordered( float32, float32 STATUS_PARAM ); +int float32_eq_quiet( float32, float32 STATUS_PARAM ); int float32_le_quiet( float32, float32 STATUS_PARAM ); int float32_lt_quiet( float32, float32 STATUS_PARAM ); +int float32_unordered_quiet( float32, float32 STATUS_PARAM ); int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); float32 float32_min(float32, float32 STATUS_PARAM); @@ -380,6 +387,7 @@ INLINE float32 float32_set_sign(float32 a, int sign) #define float32_zero make_float32(0) #define float32_one make_float32(0x3f800000) #define float32_ln2 make_float32(0x3f317218) +#define float32_pi make_float32(0x40490fdb) #define float32_half make_float32(0x3f000000) #define float32_infinity make_float32(0x7f800000) @@ -433,9 +441,11 @@ float64 float64_log2( float64 STATUS_PARAM ); int float64_eq( float64, float64 STATUS_PARAM ); int float64_le( float64, float64 STATUS_PARAM ); int float64_lt( float64, float64 STATUS_PARAM ); -int float64_eq_signaling( float64, float64 STATUS_PARAM ); +int float64_unordered( float64, float64 STATUS_PARAM ); +int float64_eq_quiet( float64, float64 STATUS_PARAM ); int float64_le_quiet( float64, float64 STATUS_PARAM ); int float64_lt_quiet( float64, float64 STATUS_PARAM ); +int float64_unordered_quiet( float64, float64 STATUS_PARAM ); int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); float64 float64_min(float64, float64 STATUS_PARAM); @@ -490,6 +500,7 @@ INLINE float64 float64_set_sign(float64 a, int sign) #define float64_zero make_float64(0) #define float64_one make_float64(0x3ff0000000000000LL) #define float64_ln2 make_float64(0x3fe62e42fefa39efLL) +#define float64_pi make_float64(0x400921fb54442d18LL) #define float64_half make_float64(0x3fe0000000000000LL) #define float64_infinity make_float64(0x7ff0000000000000LL) @@ -534,9 +545,13 @@ floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); int floatx80_le( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); -int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +int floatx80_unordered( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_quiet_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); floatx80 floatx80_maybe_silence_nan( floatx80 ); @@ -556,7 +571,7 @@ INLINE floatx80 floatx80_chs(floatx80 a) INLINE int floatx80_is_infinity(floatx80 a) { - return (a.high & 0x7fff) == 0x7fff && a.low == 0; + return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL; } INLINE int floatx80_is_neg(floatx80 a) @@ -574,6 +589,13 @@ INLINE int floatx80_is_any_nan(floatx80 a) return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); } +#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) +#define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL) +#define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL) +#define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL) +#define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL) +#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL) + /*---------------------------------------------------------------------------- | The pattern for a default generated extended double-precision NaN. The | `high' and `low' values hold the most- and least-significant bits, @@ -617,9 +639,11 @@ float128 float128_sqrt( float128 STATUS_PARAM ); int float128_eq( float128, float128 STATUS_PARAM ); int float128_le( float128, float128 STATUS_PARAM ); int float128_lt( float128, float128 STATUS_PARAM ); -int float128_eq_signaling( float128, float128 STATUS_PARAM ); +int float128_unordered( float128, float128 STATUS_PARAM ); +int float128_eq_quiet( float128, float128 STATUS_PARAM ); int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_unordered_quiet( float128, float128 STATUS_PARAM ); int float128_compare( float128, float128 STATUS_PARAM ); int float128_compare_quiet( float128, float128 STATUS_PARAM ); int float128_is_quiet_nan( float128 ); diff --git a/gen-icount.h b/gen-icount.h index 8879da6..5fb3829 100644 --- a/gen-icount.h +++ b/gen-icount.h @@ -29,7 +29,7 @@ static void gen_icount_end(TranslationBlock *tb, int num_insns) if (use_icount) { *icount_arg = num_insns; gen_set_label(icount_label); - tcg_gen_exit_tb((long)tb + 2); + tcg_gen_exit_tb((tcg_target_long)tb + 2); } } @@ -15,6 +15,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/> */ +#include "sysemu.h" #include "hw.h" #include "pc.h" #include "acpi.h" @@ -197,3 +198,199 @@ out: } return -1; } + +/* ACPI PM1a EVT */ +uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time) +{ + int64_t d = acpi_pm_tmr_get_clock(); + if (d >= overflow_time) { + pm1->sts |= ACPI_BITMASK_TIMER_STATUS; + } + return pm1->sts; +} + +void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val) +{ + uint16_t pm1_sts = acpi_pm1_evt_get_sts(pm1, tmr->overflow_time); + if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { + /* if TMRSTS is reset, then compute the new overflow time */ + acpi_pm_tmr_calc_overflow_time(tmr); + } + pm1->sts &= ~val; +} + +void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr) +{ + if (!pm1) { + qemu_system_shutdown_request(); + } else if (pm1->en & ACPI_BITMASK_POWER_BUTTON_ENABLE) { + pm1->sts |= ACPI_BITMASK_POWER_BUTTON_STATUS; + tmr->update_sci(tmr); + } +} + +void acpi_pm1_evt_reset(ACPIPM1EVT *pm1) +{ + pm1->sts = 0; + pm1->en = 0; +} + +/* ACPI PM_TMR */ +void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable) +{ + int64_t expire_time; + + /* schedule a timer interruption if needed */ + if (enable) { + expire_time = muldiv64(tmr->overflow_time, get_ticks_per_sec(), + PM_TIMER_FREQUENCY); + qemu_mod_timer(tmr->timer, expire_time); + } else { + qemu_del_timer(tmr->timer); + } +} + +void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr) +{ + int64_t d = acpi_pm_tmr_get_clock(); + tmr->overflow_time = (d + 0x800000LL) & ~0x7fffffLL; +} + +uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr) +{ + uint32_t d = acpi_pm_tmr_get_clock();; + return d & 0xffffff; +} + +static void acpi_pm_tmr_timer(void *opaque) +{ + ACPIPMTimer *tmr = opaque; + tmr->update_sci(tmr); +} + +void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci) +{ + tmr->update_sci = update_sci; + tmr->timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, tmr); +} + +void acpi_pm_tmr_reset(ACPIPMTimer *tmr) +{ + tmr->overflow_time = 0; + qemu_del_timer(tmr->timer); +} + +/* ACPI PM1aCNT */ +void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3) +{ + pm1_cnt->cmos_s3 = cmos_s3; +} + +void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val) +{ + pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); + + if (val & ACPI_BITMASK_SLEEP_ENABLE) { + /* change suspend type */ + uint16_t sus_typ = (val >> 10) & 7; + switch(sus_typ) { + case 0: /* soft power off */ + qemu_system_shutdown_request(); + break; + case 1: + /* ACPI_BITMASK_WAKE_STATUS should be set on resume. + Pretend that resume was caused by power button */ + pm1a->sts |= + (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); + qemu_system_reset_request(); + qemu_irq_raise(pm1_cnt->cmos_s3); + default: + break; + } + } +} + +void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt, + bool sci_enable, bool sci_disable) +{ + /* ACPI specs 3.0, 4.7.2.5 */ + if (sci_enable) { + pm1_cnt->cnt |= ACPI_BITMASK_SCI_ENABLE; + } else if (sci_disable) { + pm1_cnt->cnt &= ~ACPI_BITMASK_SCI_ENABLE; + } +} + +void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt) +{ + pm1_cnt->cnt = 0; + if (pm1_cnt->cmos_s3) { + qemu_irq_lower(pm1_cnt->cmos_s3); + } +} + +/* ACPI GPE */ +void acpi_gpe_init(ACPIGPE *gpe, uint8_t len) +{ + gpe->len = len; + gpe->sts = qemu_mallocz(len / 2); + gpe->en = qemu_mallocz(len / 2); +} + +void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk) +{ + gpe->blk = blk; +} + +void acpi_gpe_reset(ACPIGPE *gpe) +{ + memset(gpe->sts, 0, gpe->len / 2); + memset(gpe->en, 0, gpe->len / 2); +} + +static uint8_t *acpi_gpe_ioport_get_ptr(ACPIGPE *gpe, uint32_t addr) +{ + uint8_t *cur = NULL; + + if (addr < gpe->len / 2) { + cur = gpe->sts + addr; + } else if (addr < gpe->len) { + cur = gpe->en + addr - gpe->len / 2; + } else { + abort(); + } + + return cur; +} + +void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val) +{ + uint8_t *cur; + + addr -= gpe->blk; + cur = acpi_gpe_ioport_get_ptr(gpe, addr); + if (addr < gpe->len / 2) { + /* GPE_STS */ + *cur = (*cur) & ~val; + } else if (addr < gpe->len) { + /* GPE_EN */ + *cur = val; + } else { + abort(); + } +} + +uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr) +{ + uint8_t *cur; + uint32_t val; + + addr -= gpe->blk; + cur = acpi_gpe_ioport_get_ptr(gpe, addr); + val = 0; + if (cur != NULL) { + val = *cur; + } + + return val; +} @@ -74,5 +74,73 @@ #define ACPI_BITMASK_ARB_DISABLE 0x0001 /* PM_TMR */ +struct ACPIPMTimer; +typedef struct ACPIPMTimer ACPIPMTimer; + +typedef void (*acpi_update_sci_fn)(ACPIPMTimer *tmr); + +struct ACPIPMTimer { + QEMUTimer *timer; + int64_t overflow_time; + + acpi_update_sci_fn update_sci; +}; + +void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable); +void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr); +uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr); +void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci); +void acpi_pm_tmr_reset(ACPIPMTimer *tmr); + +#include "qemu-timer.h" +static inline int64_t acpi_pm_tmr_get_clock(void) +{ + return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, + get_ticks_per_sec()); +} + +/* PM1a_EVT: piix and ich9 don't implement PM1b. */ +struct ACPIPM1EVT +{ + uint16_t sts; + uint16_t en; +}; +typedef struct ACPIPM1EVT ACPIPM1EVT; + +uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time); +void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val); +void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr); +void acpi_pm1_evt_reset(ACPIPM1EVT *pm1); + +/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */ +struct ACPIPM1CNT { + uint16_t cnt; + + qemu_irq cmos_s3; +}; +typedef struct ACPIPM1CNT ACPIPM1CNT; + +void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3); +void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val); +void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt, + bool sci_enable, bool sci_disable); +void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt); + +/* GPE0 */ +struct ACPIGPE { + uint32_t blk; + uint8_t len; + + uint8_t *sts; + uint8_t *en; +}; +typedef struct ACPIGPE ACPIGPE; + +void acpi_gpe_init(ACPIGPE *gpe, uint8_t len); +void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk); +void acpi_gpe_reset(ACPIGPE *gpe); + +void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val); +uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr); #endif /* !QEMU_HW_ACPI_H */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 74044dd..96f5222 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -35,17 +35,13 @@ #define ACPI_DBG_IO_ADDR 0xb044 #define GPE_BASE 0xafe0 +#define GPE_LEN 4 #define PCI_BASE 0xae00 #define PCI_EJ_BASE 0xae08 #define PCI_RMV_BASE 0xae0c #define PIIX4_PCI_HOTPLUG_STATUS 2 -struct gpe_regs { - uint16_t sts; /* status */ - uint16_t en; /* enabled */ -}; - struct pci_status { uint32_t up; uint32_t down; @@ -54,25 +50,22 @@ struct pci_status { typedef struct PIIX4PMState { PCIDevice dev; IORange ioport; - uint16_t pmsts; - uint16_t pmen; - uint16_t pmcntrl; + ACPIPM1EVT pm1a; + ACPIPM1CNT pm1_cnt; APMState apm; - QEMUTimer *tmr_timer; - int64_t tmr_overflow_time; + ACPIPMTimer tmr; PMSMBus smb; uint32_t smb_io_base; qemu_irq irq; - qemu_irq cmos_s3; qemu_irq smi_irq; int kvm_enabled; /* for pci hotplug */ - struct gpe_regs gpe; + ACPIGPE gpe; struct pci_status pci0_status; uint32_t pci0_hotplug_enable; } PIIX4PMState; @@ -82,52 +75,27 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -static uint32_t get_pmtmr(PIIX4PMState *s) -{ - uint32_t d; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - return d & 0xffffff; -} - -static int get_pmsts(PIIX4PMState *s) -{ - int64_t d; - - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, - get_ticks_per_sec()); - if (d >= s->tmr_overflow_time) - s->pmsts |= ACPI_BITMASK_TIMER_STATUS; - return s->pmsts; -} - static void pm_update_sci(PIIX4PMState *s) { int sci_level, pmsts; - int64_t expire_time; - pmsts = get_pmsts(s); - sci_level = (((pmsts & s->pmen) & + pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); + sci_level = (((pmsts & s->pm1a.en) & (ACPI_BITMASK_RT_CLOCK_ENABLE | ACPI_BITMASK_POWER_BUTTON_ENABLE | ACPI_BITMASK_GLOBAL_LOCK_ENABLE | ACPI_BITMASK_TIMER_ENABLE)) != 0) || - (((s->gpe.sts & s->gpe.en) & PIIX4_PCI_HOTPLUG_STATUS) != 0); + (((s->gpe.sts[0] & s->gpe.en[0]) & PIIX4_PCI_HOTPLUG_STATUS) != 0); qemu_set_irq(s->irq, sci_level); /* schedule a timer interruption if needed */ - if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) && - !(pmsts & ACPI_BITMASK_TIMER_STATUS)) { - expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), - PM_TIMER_FREQUENCY); - qemu_mod_timer(s->tmr_timer, expire_time); - } else { - qemu_del_timer(s->tmr_timer); - } + acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } -static void pm_tmr_timer(void *opaque) +static void pm_tmr_timer(ACPIPMTimer *tmr) { - PIIX4PMState *s = opaque; + PIIX4PMState *s = container_of(tmr, PIIX4PMState, tmr); pm_update_sci(s); } @@ -143,49 +111,15 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, switch(addr) { case 0x00: - { - int64_t d; - int pmsts; - pmsts = get_pmsts(s); - if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) { - /* if TMRSTS is reset, then compute the new overflow time */ - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, - get_ticks_per_sec()); - s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; - } - s->pmsts &= ~val; - pm_update_sci(s); - } + acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val); + pm_update_sci(s); break; case 0x02: - s->pmen = val; + s->pm1a.en = val; pm_update_sci(s); break; case 0x04: - { - int sus_typ; - s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE); - if (val & ACPI_BITMASK_SLEEP_ENABLE) { - /* change suspend type */ - sus_typ = (val >> 10) & 7; - switch(sus_typ) { - case 0: /* soft power off */ - qemu_system_shutdown_request(); - break; - case 1: - /* ACPI_BITMASK_WAKE_STATUS should be set on resume. - Pretend that resume was caused by power button */ - s->pmsts |= (ACPI_BITMASK_WAKE_STATUS | - ACPI_BITMASK_POWER_BUTTON_STATUS); - qemu_system_reset_request(); - if (s->cmos_s3) { - qemu_irq_raise(s->cmos_s3); - } - default: - break; - } - } - } + acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val); break; default: break; @@ -202,16 +136,16 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, switch(addr) { case 0x00: - val = get_pmsts(s); + val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); break; case 0x02: - val = s->pmen; + val = s->pm1a.en; break; case 0x04: - val = s->pmcntrl; + val = s->pm1_cnt.cnt; break; case 0x08: - val = get_pmtmr(s); + val = acpi_pm_tmr_get(&s->tmr); break; default: val = 0; @@ -231,11 +165,7 @@ static void apm_ctrl_changed(uint32_t val, void *arg) PIIX4PMState *s = arg; /* ACPI specs 3.0, 4.7.2.5 */ - if (val == ACPI_ENABLE) { - s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE; - } else if (val == ACPI_DISABLE) { - s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE; - } + acpi_pm1_cnt_update(&s->pm1_cnt, val == ACPI_ENABLE, val == ACPI_DISABLE); if (s->dev.config[0x5b] & (1 << 1)) { if (s->smi_irq) { @@ -280,14 +210,25 @@ static int vmstate_acpi_post_load(void *opaque, int version_id) return 0; } +#define VMSTATE_GPE_ARRAY(_field, _state) \ + { \ + .name = (stringify(_field)), \ + .version_id = 0, \ + .num = GPE_LEN, \ + .info = &vmstate_info_uint16, \ + .size = sizeof(uint16_t), \ + .flags = VMS_ARRAY | VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ + } + static const VMStateDescription vmstate_gpe = { .name = "gpe", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT16(sts, struct gpe_regs), - VMSTATE_UINT16(en, struct gpe_regs), + VMSTATE_GPE_ARRAY(sts, ACPIGPE), + VMSTATE_GPE_ARRAY(en, ACPIGPE), VMSTATE_END_OF_LIST() } }; @@ -312,13 +253,13 @@ static const VMStateDescription vmstate_acpi = { .post_load = vmstate_acpi_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, PIIX4PMState), - VMSTATE_UINT16(pmsts, PIIX4PMState), - VMSTATE_UINT16(pmen, PIIX4PMState), - VMSTATE_UINT16(pmcntrl, PIIX4PMState), + VMSTATE_UINT16(pm1a.sts, PIIX4PMState), + VMSTATE_UINT16(pm1a.en, PIIX4PMState), + VMSTATE_UINT16(pm1_cnt.cnt, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(tmr_timer, PIIX4PMState), - VMSTATE_INT64(tmr_overflow_time, PIIX4PMState), - VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, struct gpe_regs), + VMSTATE_TIMER(tmr.timer, PIIX4PMState), + VMSTATE_INT64(tmr.overflow_time, PIIX4PMState), + VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, struct pci_status), VMSTATE_END_OF_LIST() @@ -364,13 +305,10 @@ static void piix4_reset(void *opaque) static void piix4_powerdown(void *opaque, int irq, int power_failing) { PIIX4PMState *s = opaque; + ACPIPM1EVT *pm1a = s? &s->pm1a: NULL; + ACPIPMTimer *tmr = s? &s->tmr: NULL; - if (!s) { - qemu_system_shutdown_request(); - } else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) { - s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS; - pm_update_sci(s); - } + acpi_pm1_evt_power_down(pm1a, tmr); } static int piix4_pm_initfn(PCIDevice *dev) @@ -414,7 +352,8 @@ static int piix4_pm_initfn(PCIDevice *dev) register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); - s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s); + acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); + acpi_gpe_init(&s->gpe, GPE_LEN); qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); @@ -437,7 +376,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, s = DO_UPCAST(PIIX4PMState, dev, dev); s->irq = sci_irq; - s->cmos_s3 = cmos_s3; + acpi_pm1_cnt_init(&s->pm1_cnt, cmos_s3); s->smi_irq = smi_irq; s->kvm_enabled = kvm_enabled; @@ -468,74 +407,20 @@ static void piix4_pm_register(void) device_init(piix4_pm_register); -static uint32_t gpe_read_val(uint16_t val, uint32_t addr) -{ - if (addr & 1) - return (val >> 8) & 0xff; - return val & 0xff; -} - static uint32_t gpe_readb(void *opaque, uint32_t addr) { - uint32_t val = 0; PIIX4PMState *s = opaque; - struct gpe_regs *g = &s->gpe; - - switch (addr) { - case GPE_BASE: - case GPE_BASE + 1: - val = gpe_read_val(g->sts, addr); - break; - case GPE_BASE + 2: - case GPE_BASE + 3: - val = gpe_read_val(g->en, addr); - break; - default: - break; - } + uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr); PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); return val; } -static void gpe_write_val(uint16_t *cur, int addr, uint32_t val) -{ - if (addr & 1) - *cur = (*cur & 0xff) | (val << 8); - else - *cur = (*cur & 0xff00) | (val & 0xff); -} - -static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val) -{ - uint16_t x1, x0 = val & 0xff; - int shift = (addr & 1) ? 8 : 0; - - x1 = (*cur >> shift) & 0xff; - - x1 = x1 & ~x0; - - *cur = (*cur & (0xff << (8 - shift))) | (x1 << shift); -} - static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) { PIIX4PMState *s = opaque; - struct gpe_regs *g = &s->gpe; - - switch (addr) { - case GPE_BASE: - case GPE_BASE + 1: - gpe_reset_val(&g->sts, addr, val); - break; - case GPE_BASE + 2: - case GPE_BASE + 3: - gpe_write_val(&g->en, addr, val); - break; - default: - break; - } + acpi_gpe_ioport_writeb(&s->gpe, addr, val); pm_update_sci(s); PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); @@ -618,8 +503,9 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) { struct pci_status *pci0_status = &s->pci0_status; - register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, s); - register_ioport_read(GPE_BASE, 4, 1, gpe_readb, s); + register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); + register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); + acpi_gpe_blk(&s->gpe, GPE_BASE); register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status); register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status); @@ -635,13 +521,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) static void enable_device(PIIX4PMState *s, int slot) { - s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS; + s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; s->pci0_status.up |= (1 << slot); } static void disable_device(PIIX4PMState *s, int slot) { - s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS; + s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; s->pci0_status.down |= (1 << slot); } @@ -261,30 +261,19 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, return olen; } -static void adb_kbd_save(QEMUFile *f, void *opaque) -{ - KBDState *s = (KBDState *)opaque; - - qemu_put_buffer(f, s->data, sizeof(s->data)); - qemu_put_sbe32s(f, &s->rptr); - qemu_put_sbe32s(f, &s->wptr); - qemu_put_sbe32s(f, &s->count); -} - -static int adb_kbd_load(QEMUFile *f, void *opaque, int version_id) -{ - KBDState *s = (KBDState *)opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_buffer(f, s->data, sizeof(s->data)); - qemu_get_sbe32s(f, &s->rptr); - qemu_get_sbe32s(f, &s->wptr); - qemu_get_sbe32s(f, &s->count); - - return 0; -} +static const VMStateDescription vmstate_adb_kbd = { + .name = "adb_kbd", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_BUFFER(data, KBDState), + VMSTATE_INT32(rptr, KBDState), + VMSTATE_INT32(wptr, KBDState), + VMSTATE_INT32(count, KBDState), + VMSTATE_END_OF_LIST() + } +}; static int adb_kbd_reset(ADBDevice *d) { @@ -305,8 +294,7 @@ void adb_kbd_init(ADBBusState *bus) d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, adb_kbd_reset, s); qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); - register_savevm(NULL, "adb_kbd", -1, 1, adb_kbd_save, - adb_kbd_load, s); + vmstate_register(NULL, -1, &vmstate_adb_kbd, s); } /***************************************************************/ @@ -439,32 +427,20 @@ static int adb_mouse_reset(ADBDevice *d) return 0; } -static void adb_mouse_save(QEMUFile *f, void *opaque) -{ - MouseState *s = (MouseState *)opaque; - - qemu_put_sbe32s(f, &s->buttons_state); - qemu_put_sbe32s(f, &s->last_buttons_state); - qemu_put_sbe32s(f, &s->dx); - qemu_put_sbe32s(f, &s->dy); - qemu_put_sbe32s(f, &s->dz); -} - -static int adb_mouse_load(QEMUFile *f, void *opaque, int version_id) -{ - MouseState *s = (MouseState *)opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_sbe32s(f, &s->buttons_state); - qemu_get_sbe32s(f, &s->last_buttons_state); - qemu_get_sbe32s(f, &s->dx); - qemu_get_sbe32s(f, &s->dy); - qemu_get_sbe32s(f, &s->dz); - - return 0; -} +static const VMStateDescription vmstate_adb_mouse = { + .name = "adb_mouse", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(buttons_state, MouseState), + VMSTATE_INT32(last_buttons_state, MouseState), + VMSTATE_INT32(dx, MouseState), + VMSTATE_INT32(dy, MouseState), + VMSTATE_INT32(dz, MouseState), + VMSTATE_END_OF_LIST() + } +}; void adb_mouse_init(ADBBusState *bus) { @@ -475,6 +451,5 @@ void adb_mouse_init(ADBBusState *bus) d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, adb_mouse_reset, s); qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse"); - register_savevm(NULL, "adb_mouse", -1, 1, adb_mouse_save, - adb_mouse_load, s); + vmstate_register(NULL, -1, &vmstate_adb_mouse, s); } diff --git a/hw/ads7846.c b/hw/ads7846.c index b3bbeaf..9c58a5f 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -105,35 +105,30 @@ static void ads7846_ts_event(void *opaque, } } -static void ads7846_save(QEMUFile *f, void *opaque) +static int ads7856_post_load(void *opaque, int version_id) { - ADS7846State *s = (ADS7846State *) opaque; - int i; - - for (i = 0; i < 8; i ++) - qemu_put_be32(f, s->input[i]); - qemu_put_be32(f, s->noise); - qemu_put_be32(f, s->cycle); - qemu_put_be32(f, s->output); -} - -static int ads7846_load(QEMUFile *f, void *opaque, int version_id) -{ - ADS7846State *s = (ADS7846State *) opaque; - int i; - - for (i = 0; i < 8; i ++) - s->input[i] = qemu_get_be32(f); - s->noise = qemu_get_be32(f); - s->cycle = qemu_get_be32(f); - s->output = qemu_get_be32(f); + ADS7846State *s = opaque; s->pressure = 0; ads7846_int_update(s); - return 0; } +static const VMStateDescription vmstate_ads7846 = { + .name = "ads7846", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = ads7856_post_load, + .fields = (VMStateField[]) { + VMSTATE_INT32_ARRAY(input, ADS7846State, 8), + VMSTATE_INT32(noise, ADS7846State), + VMSTATE_INT32(cycle, ADS7846State), + VMSTATE_INT32(output, ADS7846State), + VMSTATE_END_OF_LIST() + } +}; + static int ads7846_init(SSISlave *dev) { ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev); @@ -151,7 +146,7 @@ static int ads7846_init(SSISlave *dev) ads7846_int_update(s); - register_savevm(NULL, "ads7846", -1, 0, ads7846_save, ads7846_load, s); + vmstate_register(NULL, -1, &vmstate_ads7846, s); return 0; } diff --git a/hw/an5206.c b/hw/an5206.c index b9f19a9..42a0163 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -9,7 +9,6 @@ #include "hw.h" #include "pc.h" #include "mcf.h" -#include "sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 41e99d1..bfac982 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -15,7 +15,7 @@ #define KERNEL_ARGS_ADDR 0x100 #define KERNEL_LOAD_ADDR 0x00010000 -#define INITRD_LOAD_ADDR 0x00800000 +#define INITRD_LOAD_ADDR 0x00d00000 /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ static uint32_t bootloader[] = { diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 82f05de..dac9e70 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -140,28 +140,19 @@ static void arm_timer_tick(void *opaque) arm_timer_update(s); } -static void arm_timer_save(QEMUFile *f, void *opaque) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - qemu_put_be32(f, s->control); - qemu_put_be32(f, s->limit); - qemu_put_be32(f, s->int_level); - qemu_put_ptimer(f, s->timer); -} - -static int arm_timer_load(QEMUFile *f, void *opaque, int version_id) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->control = qemu_get_be32(f); - s->limit = qemu_get_be32(f); - s->int_level = qemu_get_be32(f); - qemu_get_ptimer(f, s->timer); - return 0; -} +static const VMStateDescription vmstate_arm_timer = { + .name = "arm_timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(control, arm_timer_state), + VMSTATE_UINT32(limit, arm_timer_state), + VMSTATE_INT32(int_level, arm_timer_state), + VMSTATE_PTIMER(timer, arm_timer_state), + VMSTATE_END_OF_LIST() + } +}; static arm_timer_state *arm_timer_init(uint32_t freq) { @@ -174,7 +165,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) bh = qemu_bh_new(arm_timer_tick, s); s->timer = ptimer_init(bh); - register_savevm(NULL, "arm_timer", -1, 1, arm_timer_save, arm_timer_load, s); + vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; } @@ -235,24 +226,17 @@ static CPUWriteMemoryFunc * const sp804_writefn[] = { sp804_write }; -static void sp804_save(QEMUFile *f, void *opaque) -{ - sp804_state *s = (sp804_state *)opaque; - qemu_put_be32(f, s->level[0]); - qemu_put_be32(f, s->level[1]); -} - -static int sp804_load(QEMUFile *f, void *opaque, int version_id) -{ - sp804_state *s = (sp804_state *)opaque; - if (version_id != 1) - return -EINVAL; - - s->level[0] = qemu_get_be32(f); - s->level[1] = qemu_get_be32(f); - return 0; -} +static const VMStateDescription vmstate_sp804 = { + .name = "sp804", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32_ARRAY(level, sp804_state, 2), + VMSTATE_END_OF_LIST() + } +}; static int sp804_init(SysBusDevice *dev) { @@ -271,7 +255,7 @@ static int sp804_init(SysBusDevice *dev) iomemtype = cpu_register_io_memory(sp804_readfn, sp804_writefn, s, DEVICE_NATIVE_ENDIAN); sysbus_init_mmio(dev, 0x1000, iomemtype); - register_savevm(&dev->qdev, "sp804", -1, 1, sp804_save, sp804_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_sp804, s); return 0; } diff --git a/hw/armv7m.c b/hw/armv7m.c index 304cd34..72d010a 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -9,7 +9,6 @@ #include "sysbus.h" #include "arm-misc.h" -#include "sysemu.h" #include "loader.h" #include "elf.h" diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index ffe16b8..d06eec9 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -365,30 +365,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) } } -static void nvic_save(QEMUFile *f, void *opaque) -{ - nvic_state *s = (nvic_state *)opaque; - - qemu_put_be32(f, s->systick.control); - qemu_put_be32(f, s->systick.reload); - qemu_put_be64(f, s->systick.tick); - qemu_put_timer(f, s->systick.timer); -} - -static int nvic_load(QEMUFile *f, void *opaque, int version_id) -{ - nvic_state *s = (nvic_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->systick.control = qemu_get_be32(f); - s->systick.reload = qemu_get_be32(f); - s->systick.tick = qemu_get_be64(f); - qemu_get_timer(f, s->systick.timer); - - return 0; -} +static const VMStateDescription vmstate_nvic = { + .name = "armv7m_nvic", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(systick.control, nvic_state), + VMSTATE_UINT32(systick.reload, nvic_state), + VMSTATE_INT64(systick.tick, nvic_state), + VMSTATE_TIMER(systick.timer, nvic_state), + VMSTATE_END_OF_LIST() + } +}; static int armv7m_nvic_init(SysBusDevice *dev) { @@ -397,7 +386,7 @@ static int armv7m_nvic_init(SysBusDevice *dev) gic_init(&s->gic); cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype); s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); - register_savevm(&dev->qdev, "armv7m_nvic", -1, 1, nvic_save, nvic_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_nvic, s); return 0; } diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index 57b5e2f..0e2135a 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -26,7 +26,6 @@ #include "net.h" #include "flash.h" #include "boards.h" -#include "sysemu.h" #include "etraxfs.h" #include "loader.h" #include "elf.h" diff --git a/hw/blizzard.c b/hw/blizzard.c index 5f329ad..c524550 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -19,7 +19,6 @@ */ #include "qemu-common.h" -#include "sysemu.h" #include "console.h" #include "devices.h" #include "vga_int.h" diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c index 65ffa37..d135ef4 100644 --- a/hw/bt-hci-csr.c +++ b/hw/bt-hci-csr.c @@ -22,7 +22,6 @@ #include "qemu-char.h" #include "qemu-timer.h" #include "irq.h" -#include "sysemu.h" #include "net.h" #include "bt.h" diff --git a/hw/collie.c b/hw/collie.c new file mode 100644 index 0000000..156404d --- /dev/null +++ b/hw/collie.c @@ -0,0 +1,69 @@ +/* + * SA-1110-based Sharp Zaurus SL-5500 platform. + * + * Copyright (C) 2011 Dmitry Eremin-Solenikov + * + * This code is licensed under GNU GPL v2. + */ +#include "hw.h" +#include "sysbus.h" +#include "boards.h" +#include "devices.h" +#include "strongarm.h" +#include "arm-misc.h" +#include "flash.h" +#include "blockdev.h" + +static struct arm_boot_info collie_binfo = { + .loader_start = SA_SDCS0, + .ram_size = 0x20000000, +}; + +static void collie_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) +{ + StrongARMState *s; + DriveInfo *dinfo; + ram_addr_t phys_flash; + + if (!cpu_model) { + cpu_model = "sa1110"; + } + + s = sa1110_init(collie_binfo.ram_size, cpu_model); + + phys_flash = qemu_ram_alloc(NULL, "collie.fl1", 0x02000000); + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(SA_CS0, phys_flash, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + + phys_flash = qemu_ram_alloc(NULL, "collie.fl2", 0x02000000); + dinfo = drive_get(IF_PFLASH, 0, 1); + pflash_cfi01_register(SA_CS1, phys_flash, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + + sysbus_create_simple("scoop", 0x40800000, NULL); + + collie_binfo.kernel_filename = kernel_filename; + collie_binfo.kernel_cmdline = kernel_cmdline; + collie_binfo.initrd_filename = initrd_filename; + collie_binfo.board_id = 0x208; + arm_load_kernel(s->env, &collie_binfo); +} + +static QEMUMachine collie_machine = { + .name = "collie", + .desc = "Collie PDA (SA-1110)", + .init = collie_init, +}; + +static void collie_machine_init(void) +{ + qemu_register_machine(&collie_machine); +} + +machine_init(collie_machine_init) diff --git a/hw/cris-boot.c b/hw/cris-boot.c index 2ef17f6..37894f8 100644 --- a/hw/cris-boot.c +++ b/hw/cris-boot.c @@ -23,7 +23,6 @@ */ #include "hw.h" -#include "sysemu.h" #include "loader.h" #include "elf.h" #include "cris-boot.h" @@ -644,80 +644,56 @@ static CPUReadMemoryFunc * const cuda_read[] = { &cuda_readl, }; -static void cuda_save_timer(QEMUFile *f, CUDATimer *s) +static bool cuda_timer_exist(void *opaque, int version_id) { - qemu_put_be16s(f, &s->latch); - qemu_put_be16s(f, &s->counter_value); - qemu_put_sbe64s(f, &s->load_time); - qemu_put_sbe64s(f, &s->next_irq_time); - if (s->timer) - qemu_put_timer(f, s->timer); -} - -static void cuda_save(QEMUFile *f, void *opaque) -{ - CUDAState *s = (CUDAState *)opaque; - - qemu_put_ubyte(f, s->b); - qemu_put_ubyte(f, s->a); - qemu_put_ubyte(f, s->dirb); - qemu_put_ubyte(f, s->dira); - qemu_put_ubyte(f, s->sr); - qemu_put_ubyte(f, s->acr); - qemu_put_ubyte(f, s->pcr); - qemu_put_ubyte(f, s->ifr); - qemu_put_ubyte(f, s->ier); - qemu_put_ubyte(f, s->anh); - qemu_put_sbe32s(f, &s->data_in_size); - qemu_put_sbe32s(f, &s->data_in_index); - qemu_put_sbe32s(f, &s->data_out_index); - qemu_put_ubyte(f, s->autopoll); - qemu_put_buffer(f, s->data_in, sizeof(s->data_in)); - qemu_put_buffer(f, s->data_out, sizeof(s->data_out)); - qemu_put_be32s(f, &s->tick_offset); - cuda_save_timer(f, &s->timers[0]); - cuda_save_timer(f, &s->timers[1]); -} + CUDATimer *s = opaque; -static void cuda_load_timer(QEMUFile *f, CUDATimer *s) -{ - qemu_get_be16s(f, &s->latch); - qemu_get_be16s(f, &s->counter_value); - qemu_get_sbe64s(f, &s->load_time); - qemu_get_sbe64s(f, &s->next_irq_time); - if (s->timer) - qemu_get_timer(f, s->timer); + return s->timer != NULL; } -static int cuda_load(QEMUFile *f, void *opaque, int version_id) -{ - CUDAState *s = (CUDAState *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->b = qemu_get_ubyte(f); - s->a = qemu_get_ubyte(f); - s->dirb = qemu_get_ubyte(f); - s->dira = qemu_get_ubyte(f); - s->sr = qemu_get_ubyte(f); - s->acr = qemu_get_ubyte(f); - s->pcr = qemu_get_ubyte(f); - s->ifr = qemu_get_ubyte(f); - s->ier = qemu_get_ubyte(f); - s->anh = qemu_get_ubyte(f); - qemu_get_sbe32s(f, &s->data_in_size); - qemu_get_sbe32s(f, &s->data_in_index); - qemu_get_sbe32s(f, &s->data_out_index); - s->autopoll = qemu_get_ubyte(f); - qemu_get_buffer(f, s->data_in, sizeof(s->data_in)); - qemu_get_buffer(f, s->data_out, sizeof(s->data_out)); - qemu_get_be32s(f, &s->tick_offset); - cuda_load_timer(f, &s->timers[0]); - cuda_load_timer(f, &s->timers[1]); +static const VMStateDescription vmstate_cuda_timer = { + .name = "cuda_timer", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT16(latch, CUDATimer), + VMSTATE_UINT16(counter_value, CUDATimer), + VMSTATE_INT64(load_time, CUDATimer), + VMSTATE_INT64(next_irq_time, CUDATimer), + VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist), + VMSTATE_END_OF_LIST() + } +}; - return 0; -} +static const VMStateDescription vmstate_cuda = { + .name = "cuda", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(a, CUDAState), + VMSTATE_UINT8(b, CUDAState), + VMSTATE_UINT8(dira, CUDAState), + VMSTATE_UINT8(dirb, CUDAState), + VMSTATE_UINT8(sr, CUDAState), + VMSTATE_UINT8(acr, CUDAState), + VMSTATE_UINT8(pcr, CUDAState), + VMSTATE_UINT8(ifr, CUDAState), + VMSTATE_UINT8(ier, CUDAState), + VMSTATE_UINT8(anh, CUDAState), + VMSTATE_INT32(data_in_size, CUDAState), + VMSTATE_INT32(data_in_index, CUDAState), + VMSTATE_INT32(data_out_index, CUDAState), + VMSTATE_UINT8(autopoll, CUDAState), + VMSTATE_BUFFER(data_in, CUDAState), + VMSTATE_BUFFER(data_out, CUDAState), + VMSTATE_UINT32(tick_offset, CUDAState), + VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1, + vmstate_cuda_timer, CUDATimer), + VMSTATE_END_OF_LIST() + } +}; static void cuda_reset(void *opaque) { @@ -764,6 +740,6 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq) s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s); *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s, DEVICE_NATIVE_ENDIAN); - register_savevm(NULL, "cuda", -1, 1, cuda_save, cuda_load, s); + vmstate_register(NULL, -1, &vmstate_cuda, s); qemu_register_reset(cuda_reset, s); } diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 61efb39..cec1cc8 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -7,7 +7,6 @@ */ #include "hw.h" -#include "sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 664b8d9..da8adc4 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -53,18 +53,21 @@ static CPUWriteMemoryFunc * const empty_slot_write[3] = { void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size) { - DeviceState *dev; - SysBusDevice *s; - EmptySlot *e; + if (slot_size > 0) { + /* Only empty slots larger than 0 byte need handling. */ + DeviceState *dev; + SysBusDevice *s; + EmptySlot *e; - dev = qdev_create(NULL, "empty_slot"); - s = sysbus_from_qdev(dev); - e = FROM_SYSBUS(EmptySlot, s); - e->size = slot_size; + dev = qdev_create(NULL, "empty_slot"); + s = sysbus_from_qdev(dev); + e = FROM_SYSBUS(EmptySlot, s); + e->size = slot_size; - qdev_init_nofail(dev); + qdev_init_nofail(dev); - sysbus_mmio_map(s, 0, addr); + sysbus_mmio_map(s, 0, addr); + } } static int empty_slot_init1(SysBusDevice *dev) diff --git a/hw/etraxfs.c b/hw/etraxfs.c index 5ee5f97..b84d74a 100644 --- a/hw/etraxfs.c +++ b/hw/etraxfs.c @@ -24,7 +24,6 @@ #include "sysbus.h" #include "boards.h" -#include "sysemu.h" #include "net.h" #include "flash.h" #include "etraxfs.h" @@ -21,8 +21,8 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, typedef struct NANDFlashState NANDFlashState; NANDFlashState *nand_init(int manf_id, int chip_id); void nand_done(NANDFlashState *s); -void nand_setpins(NANDFlashState *s, - int cle, int ale, int ce, int wp, int gnd); +void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale, + uint8_t ce, uint8_t wp, uint8_t gnd); void nand_getpins(NANDFlashState *s, int *rb); void nand_setio(NANDFlashState *s, uint8_t value); uint8_t nand_getio(NANDFlashState *s); diff --git a/hw/gumstix.c b/hw/gumstix.c index ee63f63..853f7e1 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -35,7 +35,6 @@ #include "pxa.h" #include "net.h" #include "flash.h" -#include "sysemu.h" #include "devices.h" #include "boards.h" #include "blockdev.h" diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index b19b754..5fd71a0 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -159,42 +159,31 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level) heathrow_pic_update(s); } -static void heathrow_pic_save_one(QEMUFile *f, HeathrowPIC *s) -{ - qemu_put_be32s(f, &s->events); - qemu_put_be32s(f, &s->mask); - qemu_put_be32s(f, &s->levels); - qemu_put_be32s(f, &s->level_triggered); -} - -static void heathrow_pic_save(QEMUFile *f, void *opaque) -{ - HeathrowPICS *s = (HeathrowPICS *)opaque; - - heathrow_pic_save_one(f, &s->pics[0]); - heathrow_pic_save_one(f, &s->pics[1]); -} - -static void heathrow_pic_load_one(QEMUFile *f, HeathrowPIC *s) -{ - qemu_get_be32s(f, &s->events); - qemu_get_be32s(f, &s->mask); - qemu_get_be32s(f, &s->levels); - qemu_get_be32s(f, &s->level_triggered); -} - -static int heathrow_pic_load(QEMUFile *f, void *opaque, int version_id) -{ - HeathrowPICS *s = (HeathrowPICS *)opaque; - - if (version_id != 1) - return -EINVAL; - - heathrow_pic_load_one(f, &s->pics[0]); - heathrow_pic_load_one(f, &s->pics[1]); +static const VMStateDescription vmstate_heathrow_pic_one = { + .name = "heathrow_pic_one", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(events, HeathrowPIC), + VMSTATE_UINT32(mask, HeathrowPIC), + VMSTATE_UINT32(levels, HeathrowPIC), + VMSTATE_UINT32(level_triggered, HeathrowPIC), + VMSTATE_END_OF_LIST() + } +}; - return 0; -} +static const VMStateDescription vmstate_heathrow_pic = { + .name = "heathrow_pic", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1, + vmstate_heathrow_pic_one, HeathrowPIC), + VMSTATE_END_OF_LIST() + } +}; static void heathrow_pic_reset_one(HeathrowPIC *s) { @@ -223,8 +212,7 @@ qemu_irq *heathrow_pic_init(int *pmem_index, *pmem_index = cpu_register_io_memory(pic_read, pic_write, s, DEVICE_LITTLE_ENDIAN); - register_savevm(NULL, "heathrow_pic", -1, 1, heathrow_pic_save, - heathrow_pic_load, s); + vmstate_register(NULL, -1, &vmstate_heathrow_pic, s); qemu_register_reset(heathrow_pic_reset, s); return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64); } @@ -689,6 +689,17 @@ extern const VMStateDescription vmstate_usb_device; .offset = vmstate_offset_macaddr(_state, _field), \ } +extern const VMStateDescription vmstate_ptimer; + +#define VMSTATE_PTIMER(_field, _state) { \ + .name = (stringify(_field)), \ + .version_id = (1), \ + .vmsd = &vmstate_ptimer, \ + .size = sizeof(ptimer_state *), \ + .flags = VMS_STRUCT|VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, ptimer_state), \ +} + /* _f : field name _f_n : num of elements field_name _n : num of elements @@ -784,12 +795,6 @@ extern const VMStateDescription vmstate_usb_device; #define VMSTATE_TIMER_ARRAY(_f, _s, _n) \ VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) -#define VMSTATE_PTIMER_V(_f, _s, _v) \ - VMSTATE_POINTER(_f, _s, _v, vmstate_info_ptimer, ptimer_state *) - -#define VMSTATE_PTIMER(_f, _s) \ - VMSTATE_PTIMER_V(_f, _s, 0) - #define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool) diff --git a/hw/ide/core.c b/hw/ide/core.c index c11d457..f028ddb 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1084,6 +1084,136 @@ static int ide_dvd_read_structure(IDEState *s, int format, } } +static unsigned int event_status_media(IDEState *s, + uint8_t *buf) +{ + enum media_event_code { + MEC_NO_CHANGE = 0, /* Status unchanged */ + MEC_EJECT_REQUESTED, /* received a request from user to eject */ + MEC_NEW_MEDIA, /* new media inserted and ready for access */ + MEC_MEDIA_REMOVAL, /* only for media changers */ + MEC_MEDIA_CHANGED, /* only for media changers */ + MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */ + MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */ + }; + enum media_status { + MS_TRAY_OPEN = 1, + MS_MEDIA_PRESENT = 2, + }; + uint8_t event_code, media_status; + + media_status = 0; + if (s->bs->tray_open) { + media_status = MS_TRAY_OPEN; + } else if (bdrv_is_inserted(s->bs)) { + media_status = MS_MEDIA_PRESENT; + } + + /* Event notification descriptor */ + event_code = MEC_NO_CHANGE; + if (media_status != MS_TRAY_OPEN && s->events.new_media) { + event_code = MEC_NEW_MEDIA; + s->events.new_media = false; + } + + buf[4] = event_code; + buf[5] = media_status; + + /* These fields are reserved, just clear them. */ + buf[6] = 0; + buf[7] = 0; + + return 8; /* We wrote to 4 extra bytes from the header */ +} + +static void handle_get_event_status_notification(IDEState *s, + uint8_t *buf, + const uint8_t *packet) +{ + struct { + uint8_t opcode; + uint8_t polled; /* lsb bit is polled; others are reserved */ + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; + } __attribute__((packed)) *gesn_cdb; + + struct { + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; + } __attribute((packed)) *gesn_event_header; + + enum notification_class_request_type { + NCR_RESERVED1 = 1 << 0, + NCR_OPERATIONAL_CHANGE = 1 << 1, + NCR_POWER_MANAGEMENT = 1 << 2, + NCR_EXTERNAL_REQUEST = 1 << 3, + NCR_MEDIA = 1 << 4, + NCR_MULTI_HOST = 1 << 5, + NCR_DEVICE_BUSY = 1 << 6, + NCR_RESERVED2 = 1 << 7, + }; + enum event_notification_class_field { + ENC_NO_EVENTS = 0, + ENC_OPERATIONAL_CHANGE, + ENC_POWER_MANAGEMENT, + ENC_EXTERNAL_REQUEST, + ENC_MEDIA, + ENC_MULTIPLE_HOSTS, + ENC_DEVICE_BUSY, + ENC_RESERVED, + }; + unsigned int max_len, used_len; + + gesn_cdb = (void *)packet; + gesn_event_header = (void *)buf; + + max_len = be16_to_cpu(gesn_cdb->len); + + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + return; + } + + /* polling mode operation */ + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + */ + gesn_event_header->supported_events = NCR_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & NCR_MEDIA) { + gesn_event_header->notification_class |= ENC_MEDIA; + used_len = event_status_media(s, buf); + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = cpu_to_be16(used_len + - sizeof(*gesn_event_header)); + ide_atapi_cmd_reply(s, used_len, max_len); +} + static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1102,13 +1232,21 @@ static void ide_atapi_cmd(IDEState *s) printf("\n"); } #endif - /* If there's a UNIT_ATTENTION condition pending, only - REQUEST_SENSE and INQUIRY commands are allowed to complete. */ + /* + * If there's a UNIT_ATTENTION condition pending, only + * REQUEST_SENSE, INQUIRY, GET_CONFIGURATION and + * GET_EVENT_STATUS_NOTIFICATION commands are allowed to complete. + * MMC-5, section 4.1.6.1 lists only these commands being allowed + * to complete, with other commands getting a CHECK condition + * response unless a higher priority status, defined by the drive + * here, is pending. + */ if (s->sense_key == SENSE_UNIT_ATTENTION && - s->io_buffer[0] != GPCMD_REQUEST_SENSE && - s->io_buffer[0] != GPCMD_INQUIRY) { - ide_atapi_cmd_check_status(s); - return; + s->io_buffer[0] != GPCMD_REQUEST_SENSE && + s->io_buffer[0] != GPCMD_INQUIRY && + s->io_buffer[0] != GPCMD_GET_EVENT_STATUS_NOTIFICATION) { + ide_atapi_cmd_check_status(s); + return; } switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: @@ -1230,13 +1368,8 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 18, max_len); break; case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - if (bdrv_is_inserted(s->bs)) { - bdrv_set_locked(s->bs, packet[4] & 1); - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } + bdrv_set_locked(s->bs, packet[4] & 1); + ide_atapi_cmd_ok(s); break; case GPCMD_READ_10: case GPCMD_READ_12: @@ -1309,7 +1442,7 @@ static void ide_atapi_cmd(IDEState *s) break; case GPCMD_START_STOP_UNIT: { - int start, eject, err = 0; + int start, eject, sense, err = 0; start = packet[4] & 1; eject = (packet[4] >> 1) & 1; @@ -1322,7 +1455,11 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_ok(s); break; case -EBUSY: - ide_atapi_cmd_error(s, SENSE_NOT_READY, + sense = SENSE_NOT_READY; + if (bdrv_is_inserted(s->bs)) { + sense = SENSE_ILLEGAL_REQUEST; + } + ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED); break; default: @@ -1522,19 +1659,7 @@ static void ide_atapi_cmd(IDEState *s) break; } case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - max_len = ube16_to_cpu(packet + 7); - - if (packet[1] & 0x01) { /* polling */ - /* We don't support any event class (yet). */ - cpu_to_ube16(buf, 0x00); /* No event descriptor returned */ - buf[2] = 0x80; /* No Event Available (NEA) */ - buf[3] = 0x00; /* Empty supported event classes */ - ide_atapi_cmd_reply(s, 4, max_len); - } else { /* asynchronous mode */ - /* Only polling is supported, asynchronous mode is not. */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - } + handle_get_event_status_notification(s, buf, packet); break; default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, @@ -1612,6 +1737,7 @@ static void cdrom_change_cb(void *opaque, int reason) s->sense_key = SENSE_UNIT_ATTENTION; s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; s->cdrom_changed = 1; + s->events.new_media = true; ide_set_irq(s->bus); } @@ -2756,6 +2882,25 @@ static bool ide_drive_pio_state_needed(void *opaque) return (s->status & DRQ_STAT) != 0; } +static bool ide_atapi_gesn_needed(void *opaque) +{ + IDEState *s = opaque; + + return s->events.new_media || s->events.eject_request; +} + +/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */ +const VMStateDescription vmstate_ide_atapi_gesn_state = { + .name ="ide_drive/atapi/gesn_state", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_BOOL(events.new_media, IDEState), + VMSTATE_BOOL(events.eject_request, IDEState), + } +}; + const VMStateDescription vmstate_ide_drive_pio_state = { .name = "ide_drive/pio_state", .version_id = 1, @@ -2810,6 +2955,9 @@ const VMStateDescription vmstate_ide_drive = { .vmsd = &vmstate_ide_drive_pio_state, .needed = ide_drive_pio_state_needed, }, { + .vmsd = &vmstate_ide_atapi_gesn_state, + .needed = ide_atapi_gesn_needed, + }, { /* empty */ } } diff --git a/hw/ide/ich.c b/hw/ide/ich.c index f242d7a..a3d475c 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -67,7 +67,6 @@ #include <hw/isa.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/pci.h> diff --git a/hw/ide/internal.h b/hw/ide/internal.h index d533fb6..ba7e9a8 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -373,6 +373,11 @@ typedef int DMAFunc(IDEDMA *); typedef int DMAIntFunc(IDEDMA *, int); typedef void DMARestartFunc(void *, int, int); +struct unreported_events { + bool eject_request; + bool new_media; +}; + /* NOTE: IDEState represents in fact one drive */ struct IDEState { IDEBus *bus; @@ -408,6 +413,7 @@ struct IDEState { BlockDriverState *bs; char version[9]; /* ATAPI specific */ + struct unreported_events events; uint8_t sense_key; uint8_t asc; uint8_t cdrom_changed; diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 8c59c5a..4ac7453 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -27,7 +27,6 @@ #include <hw/isa.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/macio.c b/hw/ide/macio.c index c1b4caa..7107f6b 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -27,7 +27,6 @@ #include <hw/mac_dbdma.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 2ceeb87..9fbbf0e 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -27,7 +27,6 @@ #include <hw/pcmcia.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 82b24b6..10f6f40 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -25,7 +25,6 @@ #include <hw/hw.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 35168cb..65cb56c 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -28,7 +28,6 @@ #include <hw/isa.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/pci.h> diff --git a/hw/integratorcp.c b/hw/integratorcp.c index b049940..a6c27be 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -10,7 +10,6 @@ #include "sysbus.h" #include "primecell.h" #include "devices.h" -#include "sysemu.h" #include "boards.h" #include "arm-misc.h" #include "net.h" diff --git a/hw/isa-bus.c b/hw/isa-bus.c index d07aa41..2765543 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -17,7 +17,6 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "sysemu.h" #include "monitor.h" #include "sysbus.h" #include "isa.h" diff --git a/hw/lan9118.c b/hw/lan9118.c index af6949f..2dc8d18 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -785,6 +785,12 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val) case MAC_FLOW: s->mac_flow = val & 0xffff0000; break; + case MAC_VLAN1: + /* Writing to this register changes a condition for + * FrameTooLong bit in rx_status. Since we do not set + * FrameTooLong anyway, just ignore write to this. + */ + break; default: hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n", s->mac_cmd & 0xf, val); diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index 85190f0..6462923 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -21,7 +21,6 @@ #include "hw.h" #include "net.h" #include "flash.h" -#include "sysemu.h" #include "devices.h" #include "boards.h" #include "loader.h" diff --git a/hw/m48t59.c b/hw/m48t59.c index 9f39d6b..537c0f7 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -585,28 +585,18 @@ static CPUReadMemoryFunc * const nvram_read[] = { &nvram_readl, }; -static void m48t59_save(QEMUFile *f, void *opaque) -{ - M48t59State *s = opaque; - - qemu_put_8s(f, &s->lock); - qemu_put_be16s(f, &s->addr); - qemu_put_buffer(f, s->buffer, s->size); -} - -static int m48t59_load(QEMUFile *f, void *opaque, int version_id) -{ - M48t59State *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_8s(f, &s->lock); - qemu_get_be16s(f, &s->addr); - qemu_get_buffer(f, s->buffer, s->size); - - return 0; -} +static const VMStateDescription vmstate_m48t59 = { + .name = "m48t59", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(lock, M48t59State), + VMSTATE_UINT16(addr, M48t59State), + VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size), + VMSTATE_END_OF_LIST() + } +}; static void m48t59_reset_common(M48t59State *NVRAM) { @@ -696,7 +686,7 @@ static void m48t59_init_common(M48t59State *s) } qemu_get_timedate(&s->alarm, 0); - register_savevm(NULL, "m48t59", -1, 1, m48t59_save, m48t59_load, s); + vmstate_register(NULL, -1, &vmstate_m48t59, s); } static int m48t59_init_isa1(ISADevice *dev) diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 5680fa9..ed4458e 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -165,6 +165,10 @@ typedef struct DBDMA_channel { int processing; } DBDMA_channel; +typedef struct { + DBDMA_channel channels[DBDMA_CHANNELS]; +} DBDMAState; + #ifdef DEBUG_DBDMA static void dump_dbdma_cmd(dbdma_cmd *cmd) { @@ -617,31 +621,34 @@ static void channel_run(DBDMA_channel *ch) } } -static void DBDMA_run (DBDMA_channel *ch) +static void DBDMA_run(DBDMAState *s) { int channel; - for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) { - uint32_t status = ch->regs[DBDMA_STATUS]; - if (!ch->processing && (status & RUN) && (status & ACTIVE)) - channel_run(ch); + for (channel = 0; channel < DBDMA_CHANNELS; channel++) { + DBDMA_channel *ch = &s->channels[channel]; + uint32_t status = ch->regs[DBDMA_STATUS]; + if (!ch->processing && (status & RUN) && (status & ACTIVE)) { + channel_run(ch); + } } } static void DBDMA_run_bh(void *opaque) { - DBDMA_channel *ch = opaque; + DBDMAState *s = opaque; DBDMA_DPRINTF("DBDMA_run_bh\n"); - DBDMA_run(ch); + DBDMA_run(s); } void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, DBDMA_rw rw, DBDMA_flush flush, void *opaque) { - DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan; + DBDMAState *s = dbdma; + DBDMA_channel *ch = &s->channels[nchan]; DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan); @@ -700,7 +707,8 @@ static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { int channel = addr >> DBDMA_CHANNEL_SHIFT; - DBDMA_channel *ch = (DBDMA_channel *)opaque + channel; + DBDMAState *s = opaque; + DBDMA_channel *ch = &s->channels[channel]; int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value); @@ -749,7 +757,8 @@ static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) { uint32_t value; int channel = addr >> DBDMA_CHANNEL_SHIFT; - DBDMA_channel *ch = (DBDMA_channel *)opaque + channel; + DBDMAState *s = opaque; + DBDMA_channel *ch = &s->channels[channel]; int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; value = ch->regs[reg]; @@ -801,49 +810,47 @@ static CPUReadMemoryFunc * const dbdma_read[] = { dbdma_readl, }; -static void dbdma_save(QEMUFile *f, void *opaque) -{ - DBDMA_channel *s = opaque; - unsigned int i, j; - - for (i = 0; i < DBDMA_CHANNELS; i++) - for (j = 0; j < DBDMA_REGS; j++) - qemu_put_be32s(f, &s[i].regs[j]); -} - -static int dbdma_load(QEMUFile *f, void *opaque, int version_id) -{ - DBDMA_channel *s = opaque; - unsigned int i, j; - - if (version_id != 2) - return -EINVAL; - - for (i = 0; i < DBDMA_CHANNELS; i++) - for (j = 0; j < DBDMA_REGS; j++) - qemu_get_be32s(f, &s[i].regs[j]); +static const VMStateDescription vmstate_dbdma_channel = { + .name = "dbdma_channel", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS), + VMSTATE_END_OF_LIST() + } +}; - return 0; -} +static const VMStateDescription vmstate_dbdma = { + .name = "dbdma", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1, + vmstate_dbdma_channel, DBDMA_channel), + VMSTATE_END_OF_LIST() + } +}; static void dbdma_reset(void *opaque) { - DBDMA_channel *s = opaque; + DBDMAState *s = opaque; int i; for (i = 0; i < DBDMA_CHANNELS; i++) - memset(s[i].regs, 0, DBDMA_SIZE); + memset(s->channels[i].regs, 0, DBDMA_SIZE); } void* DBDMA_init (int *dbdma_mem_index) { - DBDMA_channel *s; + DBDMAState *s; - s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS); + s = qemu_mallocz(sizeof(DBDMAState)); *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s, DEVICE_LITTLE_ENDIAN); - register_savevm(NULL, "dbdma", -1, 1, dbdma_save, dbdma_load, s); + vmstate_register(NULL, -1, &vmstate_dbdma, s); qemu_register_reset(dbdma_reset, s); dbdma_bh = qemu_bh_new(DBDMA_run_bh, s); diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index c2a2fc2..61e53d2 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -38,7 +38,7 @@ #endif struct MacIONVRAMState { - target_phys_addr_t size; + uint32_t size; int mem_index; unsigned int it_shift; uint8_t *data; @@ -105,24 +105,17 @@ static CPUReadMemoryFunc * const nvram_read[] = { &macio_nvram_readb, }; -static void macio_nvram_save(QEMUFile *f, void *opaque) -{ - MacIONVRAMState *s = (MacIONVRAMState *)opaque; - - qemu_put_buffer(f, s->data, s->size); -} - -static int macio_nvram_load(QEMUFile *f, void *opaque, int version_id) -{ - MacIONVRAMState *s = (MacIONVRAMState *)opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_buffer(f, s->data, s->size); +static const VMStateDescription vmstate_macio_nvram = { + .name = "macio_nvram", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size), + VMSTATE_END_OF_LIST() + } +}; - return 0; -} static void macio_nvram_reset(void *opaque) { @@ -141,8 +134,7 @@ MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size, s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s, DEVICE_NATIVE_ENDIAN); *mem_index = s->mem_index; - register_savevm(NULL, "macio_nvram", -1, 1, macio_nvram_save, - macio_nvram_load, s); + vmstate_register(NULL, -1, &vmstate_macio_nvram, s); qemu_register_reset(macio_nvram_reset, s); return s; diff --git a/hw/mainstone.c b/hw/mainstone.c index 50691ca..4792f0e 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -14,7 +14,6 @@ #include "net.h" #include "devices.h" #include "boards.h" -#include "sysemu.h" #include "flash.h" #include "blockdev.h" #include "sysbus.h" diff --git a/hw/max111x.c b/hw/max111x.c index 2844665..70cd1af 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -15,7 +15,7 @@ typedef struct { uint8_t tb1, rb2, rb3; int cycle; - int input[8]; + uint8_t input[8]; int inputs, com; } MAX111xState; @@ -94,36 +94,22 @@ static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) return max111x_read(s); } -static void max111x_save(QEMUFile *f, void *opaque) -{ - MAX111xState *s = (MAX111xState *) opaque; - int i; - - qemu_put_8s(f, &s->tb1); - qemu_put_8s(f, &s->rb2); - qemu_put_8s(f, &s->rb3); - qemu_put_be32(f, s->inputs); - qemu_put_be32(f, s->com); - for (i = 0; i < s->inputs; i ++) - qemu_put_byte(f, s->input[i]); -} - -static int max111x_load(QEMUFile *f, void *opaque, int version_id) -{ - MAX111xState *s = (MAX111xState *) opaque; - int i; - - qemu_get_8s(f, &s->tb1); - qemu_get_8s(f, &s->rb2); - qemu_get_8s(f, &s->rb3); - if (s->inputs != qemu_get_be32(f)) - return -EINVAL; - s->com = qemu_get_be32(f); - for (i = 0; i < s->inputs; i ++) - s->input[i] = qemu_get_byte(f); - - return 0; -} +static const VMStateDescription vmstate_max111x = { + .name = "max111x", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(tb1, MAX111xState), + VMSTATE_UINT8(rb2, MAX111xState), + VMSTATE_UINT8(rb3, MAX111xState), + VMSTATE_INT32_EQUAL(inputs, MAX111xState), + VMSTATE_INT32(com, MAX111xState), + VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs, + vmstate_info_uint8, uint8_t), + VMSTATE_END_OF_LIST() + } +}; static int max111x_init(SSISlave *dev, int inputs) { @@ -143,8 +129,7 @@ static int max111x_init(SSISlave *dev, int inputs) s->input[7] = 0x80; s->com = 0; - register_savevm(&dev->qdev, "max111x", -1, 0, - max111x_save, max111x_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_max111x, s); return 0; } diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index 4831e00..94e6315 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -163,7 +163,7 @@ static int pfpu_decode_insn(MilkymistPFPUState *s) uint32_t reg_b = (insn >> 11) & 0x7f; uint32_t op = (insn >> 7) & 0xf; uint32_t reg_d = insn & 0x7f; - uint32_t r; + uint32_t r = 0; int latency = 0; switch (op) { diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 0e90d68..420fada 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -263,11 +263,9 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, qemu_irq *cpu_exit_irq; int via_devfn; PCIBus *pci_bus; - uint8_t *eeprom_buf; i2c_bus *smbus; int i; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DeviceState *eeprom; CPUState *env; /* init CPUs */ @@ -353,13 +351,8 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4), 0xeee1, NULL); - eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ - memcpy(eeprom_buf, eeprom_spd, sizeof(eeprom_spd)); /* TODO: Populate SPD eeprom data. */ - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf); - qdev_init_nofail(eeprom); + smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); /* init other devices */ pit = pit_init(0x40, 0); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index bf0d76d..ed2a483 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -770,7 +770,6 @@ void mips_malta_init (ram_addr_t ram_size, qemu_irq *i8259; qemu_irq *cpu_exit_irq; int piix4_devfn; - uint8_t *eeprom_buf; i2c_bus *smbus; int i; DriveInfo *dinfo; @@ -913,15 +912,8 @@ void mips_malta_init (ram_addr_t ram_size, usb_uhci_piix4_init(pci_bus, piix4_devfn + 2); smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9), NULL, NULL, 0); - eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ - for (i = 0; i < 8; i++) { - /* TODO: Populate SPD eeprom data. */ - DeviceState *eeprom; - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50 + i); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); - qdev_init_nofail(eeprom); - } + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(smbus, 8, NULL, 0); pit = pit_init(0x40, 0); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(0, cpu_exit_irq); diff --git a/hw/mipsnet.c b/hw/mipsnet.c index c5e54ff..26aad51 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -202,44 +202,29 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static void mipsnet_save(QEMUFile *f, void *opaque) -{ - MIPSnetState *s = opaque; - - qemu_put_be32s(f, &s->busy); - qemu_put_be32s(f, &s->rx_count); - qemu_put_be32s(f, &s->rx_read); - qemu_put_be32s(f, &s->tx_count); - qemu_put_be32s(f, &s->tx_written); - qemu_put_be32s(f, &s->intctl); - qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE); - qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE); -} - -static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) -{ - MIPSnetState *s = opaque; - - if (version_id > 0) - return -EINVAL; - - qemu_get_be32s(f, &s->busy); - qemu_get_be32s(f, &s->rx_count); - qemu_get_be32s(f, &s->rx_read); - qemu_get_be32s(f, &s->tx_count); - qemu_get_be32s(f, &s->tx_written); - qemu_get_be32s(f, &s->intctl); - qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE); - qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE); - - return 0; -} +static const VMStateDescription vmstate_mipsnet = { + .name = "mipsnet", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(busy, MIPSnetState), + VMSTATE_UINT32(rx_count, MIPSnetState), + VMSTATE_UINT32(rx_read, MIPSnetState), + VMSTATE_UINT32(tx_count, MIPSnetState), + VMSTATE_UINT32(tx_written, MIPSnetState), + VMSTATE_UINT32(intctl, MIPSnetState), + VMSTATE_BUFFER(rx_buffer, MIPSnetState), + VMSTATE_BUFFER(tx_buffer, MIPSnetState), + VMSTATE_END_OF_LIST() + } +}; static void mipsnet_cleanup(VLANClientState *nc) { MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - unregister_savevm(NULL, "mipsnet", s); + vmstate_unregister(NULL, &vmstate_mipsnet, s); isa_unassign_ioport(s->io_base, 36); @@ -284,5 +269,5 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) } mipsnet_reset(s); - register_savevm(NULL, "mipsnet", 0, 0, mipsnet_save, mipsnet_load, s); + vmstate_register(NULL, 0, &vmstate_mipsnet, s); } diff --git a/hw/multiboot.c b/hw/multiboot.c index 0d2bfb4..394ed01 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -272,7 +272,7 @@ int load_multiboot(void *fw_cfg, mb_debug("multiboot loading module: %s\n", initrd_filename); mb_mod_length = get_image_size(initrd_filename); if (mb_mod_length < 0) { - fprintf(stderr, "failed to get %s image size\n", initrd_filename); + fprintf(stderr, "Failed to open file '%s'\n", initrd_filename); exit(1); } diff --git a/hw/musicpal.c b/hw/musicpal.c index d98aa8d..52b2931 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1597,11 +1597,11 @@ static void musicpal_init(ram_addr_t ram_size, musicpal_misc_init(); dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); - i2c_dev = sysbus_create_simple("gpio_i2c", 0, NULL); + i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"); lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); - key_dev = sysbus_create_simple("musicpal_key", 0, NULL); + key_dev = sysbus_create_simple("musicpal_key", -1, NULL); /* I2C read data */ qdev_connect_gpio_out(i2c_dev, 0, @@ -52,7 +52,7 @@ struct NANDFlashState { BlockDriverState *bdrv; int mem_oob; - int cle, ale, ce, wp, gnd; + uint8_t cle, ale, ce, wp, gnd; uint8_t io[MAX_PAGE + MAX_OOB + 0x400]; uint8_t *ioaddr; @@ -66,6 +66,8 @@ struct NANDFlashState { void (*blk_write)(NANDFlashState *s); void (*blk_erase)(NANDFlashState *s); void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset); + + uint32_t ioaddr_vmstate; }; # define NAND_NO_AUTOINCR 0x00000001 @@ -281,56 +283,59 @@ static void nand_command(NANDFlashState *s) } } -static void nand_save(QEMUFile *f, void *opaque) +static void nand_pre_save(void *opaque) { - NANDFlashState *s = (NANDFlashState *) opaque; - qemu_put_byte(f, s->cle); - qemu_put_byte(f, s->ale); - qemu_put_byte(f, s->ce); - qemu_put_byte(f, s->wp); - qemu_put_byte(f, s->gnd); - qemu_put_buffer(f, s->io, sizeof(s->io)); - qemu_put_be32(f, s->ioaddr - s->io); - qemu_put_be32(f, s->iolen); - - qemu_put_be32s(f, &s->cmd); - qemu_put_be32s(f, &s->addr); - qemu_put_be32(f, s->addrlen); - qemu_put_be32(f, s->status); - qemu_put_be32(f, s->offset); - /* XXX: do we want to save s->storage too? */ + NANDFlashState *s = opaque; + + s->ioaddr_vmstate = s->ioaddr - s->io; } -static int nand_load(QEMUFile *f, void *opaque, int version_id) +static int nand_post_load(void *opaque, int version_id) { - NANDFlashState *s = (NANDFlashState *) opaque; - s->cle = qemu_get_byte(f); - s->ale = qemu_get_byte(f); - s->ce = qemu_get_byte(f); - s->wp = qemu_get_byte(f); - s->gnd = qemu_get_byte(f); - qemu_get_buffer(f, s->io, sizeof(s->io)); - s->ioaddr = s->io + qemu_get_be32(f); - s->iolen = qemu_get_be32(f); - if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io) + NANDFlashState *s = opaque; + + if (s->ioaddr_vmstate > sizeof(s->io)) { return -EINVAL; + } + s->ioaddr = s->io + s->ioaddr_vmstate; - qemu_get_be32s(f, &s->cmd); - qemu_get_be32s(f, &s->addr); - s->addrlen = qemu_get_be32(f); - s->status = qemu_get_be32(f); - s->offset = qemu_get_be32(f); return 0; } +static const VMStateDescription vmstate_nand = { + .name = "nand", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .pre_save = nand_pre_save, + .post_load = nand_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(cle, NANDFlashState), + VMSTATE_UINT8(ale, NANDFlashState), + VMSTATE_UINT8(ce, NANDFlashState), + VMSTATE_UINT8(wp, NANDFlashState), + VMSTATE_UINT8(gnd, NANDFlashState), + VMSTATE_BUFFER(io, NANDFlashState), + VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState), + VMSTATE_INT32(iolen, NANDFlashState), + VMSTATE_UINT32(cmd, NANDFlashState), + VMSTATE_UINT32(addr, NANDFlashState), + VMSTATE_INT32(addrlen, NANDFlashState), + VMSTATE_INT32(status, NANDFlashState), + VMSTATE_INT32(offset, NANDFlashState), + /* XXX: do we want to save s->storage too? */ + VMSTATE_END_OF_LIST() + } +}; + /* * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip * outputs are R/B and eight I/O pins. * * CE, WP and R/B are active low. */ -void nand_setpins(NANDFlashState *s, - int cle, int ale, int ce, int wp, int gnd) +void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale, + uint8_t ce, uint8_t wp, uint8_t gnd) { s->cle = cle; s->ale = ale; @@ -502,7 +507,7 @@ NANDFlashState *nand_init(int manf_id, int chip_id) is used. */ s->ioaddr = s->io; - register_savevm(NULL, "nand", -1, 0, nand_save, nand_load, s); + vmstate_register(NULL, -1, &vmstate_nand, s); return s; } diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 06bccbd..a7b687b 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -26,7 +26,6 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "sysemu.h" #include "console.h" #include "omap.h" #include "boards.h" diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 4d54ca1..a85214b 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -37,6 +37,7 @@ #include "sysbus.h" #include "arch_init.h" #include "blockdev.h" +#include "smbus.h" #define MAX_IDE_BUS 2 @@ -154,7 +155,6 @@ static void pc_init1(ram_addr_t ram_size, } if (pci_enabled && acpi_enabled) { - uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ i2c_bus *smbus; cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); @@ -163,13 +163,7 @@ static void pc_init1(ram_addr_t ram_size, smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, isa_get_irq(9), *cmos_s3, *smi_irq, kvm_enabled()); - for (i = 0; i < 8; i++) { - DeviceState *eeprom; - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50 + i); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); - qdev_init_nofail(eeprom); - } + smbus_eeprom_init(smbus, 8, NULL, 0); } if (i440fx_state) { @@ -18,8 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "sysemu.h" -#include "range.h" +#include "qemu-common.h" #include "pci_bridge.h" #include "pcie.h" #include "msix.h" diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 30c8aa4..370c5ee 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -112,7 +112,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset); ret = -1; - if (pfl->rom_mode) { + if (!pfl->rom_mode) { /* Lazy reset of to ROMD mode */ if (pfl->wcycle == 0) pflash_register_memory(pfl, 1); @@ -30,10 +30,14 @@ PCIDevice *piix4_dev; +typedef struct PIIX4State { + PCIDevice dev; +} PIIX4State; + static void piix4_reset(void *opaque) { - PCIDevice *d = opaque; - uint8_t *pci_conf = d->config; + PIIX4State *d = opaque; + uint8_t *pci_conf = d->dev.config; pci_conf[0x04] = 0x07; // master, memory and I/O pci_conf[0x05] = 0x00; @@ -68,33 +72,30 @@ static void piix4_reset(void *opaque) pci_conf[0xae] = 0x00; } -static void piix_save(QEMUFile* f, void *opaque) -{ - PCIDevice *d = opaque; - pci_device_save(d, f); -} - -static int piix_load(QEMUFile* f, void *opaque, int version_id) -{ - PCIDevice *d = opaque; - if (version_id != 2) - return -EINVAL; - return pci_device_load(d, f); -} +static const VMStateDescription vmstate_piix4 = { + .name = "PIIX4", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PIIX4State), + VMSTATE_END_OF_LIST() + } +}; -static int piix4_initfn(PCIDevice *d) +static int piix4_initfn(PCIDevice *dev) { + PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev); uint8_t *pci_conf; - isa_bus_new(&d->qdev); - register_savevm(&d->qdev, "PIIX4", 0, 2, piix_save, piix_load, d); + isa_bus_new(&d->dev.qdev); - pci_conf = d->config; + pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA); - piix4_dev = d; + piix4_dev = &d->dev; qemu_register_reset(piix4_reset, d); return 0; } @@ -111,7 +112,8 @@ static PCIDeviceInfo piix4_info[] = { { .qdev.name = "PIIX4", .qdev.desc = "ISA bridge", - .qdev.size = sizeof(PCIDevice), + .qdev.size = sizeof(PIIX4State), + .qdev.vmsd = &vmstate_piix4, .qdev.no_user = 1, .no_hotplug = 1, .init = piix4_initfn, @@ -235,56 +235,30 @@ static CPUWriteMemoryFunc * const pl011_writefn[] = { pl011_write }; -static void pl011_save(QEMUFile *f, void *opaque) -{ - pl011_state *s = (pl011_state *)opaque; - int i; - - qemu_put_be32(f, s->readbuff); - qemu_put_be32(f, s->flags); - qemu_put_be32(f, s->lcr); - qemu_put_be32(f, s->cr); - qemu_put_be32(f, s->dmacr); - qemu_put_be32(f, s->int_enabled); - qemu_put_be32(f, s->int_level); - for (i = 0; i < 16; i++) - qemu_put_be32(f, s->read_fifo[i]); - qemu_put_be32(f, s->ilpr); - qemu_put_be32(f, s->ibrd); - qemu_put_be32(f, s->fbrd); - qemu_put_be32(f, s->ifl); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - qemu_put_be32(f, s->read_trigger); -} - -static int pl011_load(QEMUFile *f, void *opaque, int version_id) -{ - pl011_state *s = (pl011_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->readbuff = qemu_get_be32(f); - s->flags = qemu_get_be32(f); - s->lcr = qemu_get_be32(f); - s->cr = qemu_get_be32(f); - s->dmacr = qemu_get_be32(f); - s->int_enabled = qemu_get_be32(f); - s->int_level = qemu_get_be32(f); - for (i = 0; i < 16; i++) - s->read_fifo[i] = qemu_get_be32(f); - s->ilpr = qemu_get_be32(f); - s->ibrd = qemu_get_be32(f); - s->fbrd = qemu_get_be32(f); - s->ifl = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - s->read_trigger = qemu_get_be32(f); - - return 0; -} +static const VMStateDescription vmstate_pl011 = { + .name = "pl011", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(readbuff, pl011_state), + VMSTATE_UINT32(flags, pl011_state), + VMSTATE_UINT32(lcr, pl011_state), + VMSTATE_UINT32(cr, pl011_state), + VMSTATE_UINT32(dmacr, pl011_state), + VMSTATE_UINT32(int_enabled, pl011_state), + VMSTATE_UINT32(int_level, pl011_state), + VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16), + VMSTATE_UINT32(ilpr, pl011_state), + VMSTATE_UINT32(ibrd, pl011_state), + VMSTATE_UINT32(fbrd, pl011_state), + VMSTATE_UINT32(ifl, pl011_state), + VMSTATE_INT32(read_pos, pl011_state), + VMSTATE_INT32(read_count, pl011_state), + VMSTATE_INT32(read_trigger, pl011_state), + VMSTATE_END_OF_LIST() + } +}; static int pl011_init(SysBusDevice *dev, const unsigned char *id) { @@ -307,7 +281,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, pl011_event, s); } - register_savevm(&dev->qdev, "pl011_uart", -1, 1, pl011_save, pl011_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); return 0; } @@ -239,54 +239,42 @@ static CPUWriteMemoryFunc * const pl022_writefn[] = { pl022_write }; -static void pl022_save(QEMUFile *f, void *opaque) -{ - pl022_state *s = (pl022_state *)opaque; - int i; - - qemu_put_be32(f, s->cr0); - qemu_put_be32(f, s->cr1); - qemu_put_be32(f, s->bitmask); - qemu_put_be32(f, s->sr); - qemu_put_be32(f, s->cpsr); - qemu_put_be32(f, s->is); - qemu_put_be32(f, s->im); - qemu_put_be32(f, s->tx_fifo_head); - qemu_put_be32(f, s->rx_fifo_head); - qemu_put_be32(f, s->tx_fifo_len); - qemu_put_be32(f, s->rx_fifo_len); - for (i = 0; i < 8; i++) { - qemu_put_be16(f, s->tx_fifo[i]); - qemu_put_be16(f, s->rx_fifo[i]); - } -} - -static int pl022_load(QEMUFile *f, void *opaque, int version_id) -{ - pl022_state *s = (pl022_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->cr0 = qemu_get_be32(f); - s->cr1 = qemu_get_be32(f); - s->bitmask = qemu_get_be32(f); - s->sr = qemu_get_be32(f); - s->cpsr = qemu_get_be32(f); - s->is = qemu_get_be32(f); - s->im = qemu_get_be32(f); - s->tx_fifo_head = qemu_get_be32(f); - s->rx_fifo_head = qemu_get_be32(f); - s->tx_fifo_len = qemu_get_be32(f); - s->rx_fifo_len = qemu_get_be32(f); - for (i = 0; i < 8; i++) { - s->tx_fifo[i] = qemu_get_be16(f); - s->rx_fifo[i] = qemu_get_be16(f); +static const VMStateDescription vmstate_pl022 = { + .name = "pl022_ssp", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cr0, pl022_state), + VMSTATE_UINT32(cr1, pl022_state), + VMSTATE_UINT32(bitmask, pl022_state), + VMSTATE_UINT32(sr, pl022_state), + VMSTATE_UINT32(cpsr, pl022_state), + VMSTATE_UINT32(is, pl022_state), + VMSTATE_UINT32(im, pl022_state), + VMSTATE_INT32(tx_fifo_head, pl022_state), + VMSTATE_INT32(rx_fifo_head, pl022_state), + VMSTATE_INT32(tx_fifo_len, pl022_state), + VMSTATE_INT32(rx_fifo_len, pl022_state), + VMSTATE_UINT16(tx_fifo[0], pl022_state), + VMSTATE_UINT16(rx_fifo[0], pl022_state), + VMSTATE_UINT16(tx_fifo[1], pl022_state), + VMSTATE_UINT16(rx_fifo[1], pl022_state), + VMSTATE_UINT16(tx_fifo[2], pl022_state), + VMSTATE_UINT16(rx_fifo[2], pl022_state), + VMSTATE_UINT16(tx_fifo[3], pl022_state), + VMSTATE_UINT16(rx_fifo[3], pl022_state), + VMSTATE_UINT16(tx_fifo[4], pl022_state), + VMSTATE_UINT16(rx_fifo[4], pl022_state), + VMSTATE_UINT16(tx_fifo[5], pl022_state), + VMSTATE_UINT16(rx_fifo[5], pl022_state), + VMSTATE_UINT16(tx_fifo[6], pl022_state), + VMSTATE_UINT16(rx_fifo[6], pl022_state), + VMSTATE_UINT16(tx_fifo[7], pl022_state), + VMSTATE_UINT16(rx_fifo[7], pl022_state), + VMSTATE_END_OF_LIST() } - - return 0; -} +}; static int pl022_init(SysBusDevice *dev) { @@ -300,7 +288,7 @@ static int pl022_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->ssi = ssi_create_bus(&dev->qdev, "ssi"); pl022_reset(s); - register_savevm(&dev->qdev, "pl022_ssp", -1, 1, pl022_save, pl022_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_pl022, s); return 0; } @@ -252,11 +252,9 @@ void ppc970_irq_init (CPUState *env) static void power7_set_irq (void *opaque, int pin, int level) { CPUState *env = opaque; - int cur_level; LOG_IRQ("%s: env %p pin %d level %d\n", __func__, env, pin, level); - cur_level = (env->irq_input_state >> pin) & 1; switch (pin) { case POWER7_INPUT_INT: diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 645e84f..20b8629 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -17,7 +17,6 @@ #include "hw.h" #include "pci.h" #include "boards.h" -#include "sysemu.h" #include "ppc440.h" #include "kvm.h" #include "kvm_ppc.h" diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 5f581fe..7f9ed17 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -24,7 +24,6 @@ #include "hw.h" #include "ppc.h" #include "ppc4xx.h" -#include "sysemu.h" #include "qemu-log.h" //#define DEBUG_MMIO diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index f62f1f9..299473c 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -285,50 +285,48 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pci_irqs[irq_num], level); } -static void ppc4xx_pci_save(QEMUFile *f, void *opaque) -{ - PPC4xxPCIState *controller = opaque; - int i; - - pci_device_save(controller->pci_dev, f); - - for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) { - qemu_put_be32s(f, &controller->pmm[i].la); - qemu_put_be32s(f, &controller->pmm[i].ma); - qemu_put_be32s(f, &controller->pmm[i].pcila); - qemu_put_be32s(f, &controller->pmm[i].pciha); - } - - for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) { - qemu_put_be32s(f, &controller->ptm[i].ms); - qemu_put_be32s(f, &controller->ptm[i].la); +static const VMStateDescription vmstate_pci_master_map = { + .name = "pci_master_map", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(la, struct PCIMasterMap), + VMSTATE_UINT32(ma, struct PCIMasterMap), + VMSTATE_UINT32(pcila, struct PCIMasterMap), + VMSTATE_UINT32(pciha, struct PCIMasterMap), + VMSTATE_END_OF_LIST() } -} - -static int ppc4xx_pci_load(QEMUFile *f, void *opaque, int version_id) -{ - PPC4xxPCIState *controller = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - pci_device_load(controller->pci_dev, f); +}; - for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) { - qemu_get_be32s(f, &controller->pmm[i].la); - qemu_get_be32s(f, &controller->pmm[i].ma); - qemu_get_be32s(f, &controller->pmm[i].pcila); - qemu_get_be32s(f, &controller->pmm[i].pciha); +static const VMStateDescription vmstate_pci_target_map = { + .name = "pci_target_map", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ms, struct PCITargetMap), + VMSTATE_UINT32(la, struct PCITargetMap), + VMSTATE_END_OF_LIST() } +}; - for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) { - qemu_get_be32s(f, &controller->ptm[i].ms); - qemu_get_be32s(f, &controller->ptm[i].la); +static const VMStateDescription vmstate_ppc4xx_pci = { + .name = "ppc4xx_pci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState), + VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1, + vmstate_pci_master_map, + struct PCIMasterMap), + VMSTATE_STRUCT_ARRAY(ptm, PPC4xxPCIState, PPC4xx_PCI_NR_PTMS, 1, + vmstate_pci_target_map, + struct PCITargetMap), + VMSTATE_END_OF_LIST() } - - return 0; -} +}; /* XXX Interrupt acknowledge cycles not supported. */ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], @@ -381,8 +379,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], qemu_register_reset(ppc4xx_pci_reset, controller); /* XXX load/save code not tested. */ - register_savevm(&controller->pci_dev->qdev, "ppc4xx_pci", ppc4xx_pci_id++, - 1, ppc4xx_pci_save, ppc4xx_pci_load, controller); + vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++, + &vmstate_ppc4xx_pci, controller); return controller->pci_state.bus; diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 11edd03..83a20e4 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -198,7 +198,7 @@ static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) ret = (irq_num + devno - 0x10) % 4; break; default: - printf("Error:%s:unknow dev number\n", __func__); + printf("Error:%s:unknown dev number\n", __func__); } pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__, @@ -216,56 +216,49 @@ static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num], level); } -static void ppce500_pci_save(QEMUFile *f, void *opaque) -{ - PPCE500PCIState *controller = opaque; - int i; - - pci_device_save(controller->pci_dev, f); - - for (i = 0; i < PPCE500_PCI_NR_POBS; i++) { - qemu_put_be32s(f, &controller->pob[i].potar); - qemu_put_be32s(f, &controller->pob[i].potear); - qemu_put_be32s(f, &controller->pob[i].powbar); - qemu_put_be32s(f, &controller->pob[i].powar); - } - - for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) { - qemu_put_be32s(f, &controller->pib[i].pitar); - qemu_put_be32s(f, &controller->pib[i].piwbar); - qemu_put_be32s(f, &controller->pib[i].piwbear); - qemu_put_be32s(f, &controller->pib[i].piwar); +static const VMStateDescription vmstate_pci_outbound = { + .name = "pci_outbound", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(potar, struct pci_outbound), + VMSTATE_UINT32(potear, struct pci_outbound), + VMSTATE_UINT32(powbar, struct pci_outbound), + VMSTATE_UINT32(powar, struct pci_outbound), + VMSTATE_END_OF_LIST() } - qemu_put_be32s(f, &controller->gasket_time); -} - -static int ppce500_pci_load(QEMUFile *f, void *opaque, int version_id) -{ - PPCE500PCIState *controller = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - pci_device_load(controller->pci_dev, f); +}; - for (i = 0; i < PPCE500_PCI_NR_POBS; i++) { - qemu_get_be32s(f, &controller->pob[i].potar); - qemu_get_be32s(f, &controller->pob[i].potear); - qemu_get_be32s(f, &controller->pob[i].powbar); - qemu_get_be32s(f, &controller->pob[i].powar); +static const VMStateDescription vmstate_pci_inbound = { + .name = "pci_inbound", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(pitar, struct pci_inbound), + VMSTATE_UINT32(piwbar, struct pci_inbound), + VMSTATE_UINT32(piwbear, struct pci_inbound), + VMSTATE_UINT32(piwar, struct pci_inbound), + VMSTATE_END_OF_LIST() } +}; - for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) { - qemu_get_be32s(f, &controller->pib[i].pitar); - qemu_get_be32s(f, &controller->pib[i].piwbar); - qemu_get_be32s(f, &controller->pib[i].piwbear); - qemu_get_be32s(f, &controller->pib[i].piwar); +static const VMStateDescription vmstate_ppce500_pci = { + .name = "ppce500_pci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPCE500PCIState), + VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1, + vmstate_pci_outbound, struct pci_outbound), + VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1, + vmstate_pci_outbound, struct pci_inbound), + VMSTATE_UINT32(gasket_time, PPCE500PCIState), + VMSTATE_END_OF_LIST() } - qemu_get_be32s(f, &controller->gasket_time); - - return 0; -} +}; PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) { @@ -314,8 +307,8 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) PCIE500_REG_SIZE, index); /* XXX load/save code not tested. */ - register_savevm(&d->qdev, "ppce500_pci", ppce500_pci_id++, - 1, ppce500_pci_save, ppce500_pci_load, controller); + vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci, + controller); return controller->pci_state.bus; diff --git a/hw/ptimer.c b/hw/ptimer.c index e68c1d1..47964a6 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -11,7 +11,7 @@ struct ptimer_state { - int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ + uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ uint64_t limit; uint64_t delta; uint32_t period_frac; @@ -188,49 +188,22 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) } } -void qemu_put_ptimer(QEMUFile *f, ptimer_state *s) -{ - qemu_put_byte(f, s->enabled); - qemu_put_be64s(f, &s->limit); - qemu_put_be64s(f, &s->delta); - qemu_put_be32s(f, &s->period_frac); - qemu_put_sbe64s(f, &s->period); - qemu_put_sbe64s(f, &s->last_event); - qemu_put_sbe64s(f, &s->next_event); - qemu_put_timer(f, s->timer); -} - -void qemu_get_ptimer(QEMUFile *f, ptimer_state *s) -{ - s->enabled = qemu_get_byte(f); - qemu_get_be64s(f, &s->limit); - qemu_get_be64s(f, &s->delta); - qemu_get_be32s(f, &s->period_frac); - qemu_get_sbe64s(f, &s->period); - qemu_get_sbe64s(f, &s->last_event); - qemu_get_sbe64s(f, &s->next_event); - qemu_get_timer(f, s->timer); -} - -static int get_ptimer(QEMUFile *f, void *pv, size_t size) -{ - ptimer_state *v = pv; - - qemu_get_ptimer(f, v); - return 0; -} - -static void put_ptimer(QEMUFile *f, void *pv, size_t size) -{ - ptimer_state *v = pv; - - qemu_put_ptimer(f, v); -} - -const VMStateInfo vmstate_info_ptimer = { +const VMStateDescription vmstate_ptimer = { .name = "ptimer", - .get = get_ptimer, - .put = put_ptimer, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(enabled, ptimer_state), + VMSTATE_UINT64(limit, ptimer_state), + VMSTATE_UINT64(delta, ptimer_state), + VMSTATE_UINT32(period_frac, ptimer_state), + VMSTATE_INT64(period, ptimer_state), + VMSTATE_INT64(last_event, ptimer_state), + VMSTATE_INT64(next_event, ptimer_state), + VMSTATE_TIMER(timer, ptimer_state), + VMSTATE_END_OF_LIST() + } }; ptimer_state *ptimer_init(QEMUBH *bh) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 9b95e2c..ac5d95d 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -146,25 +146,16 @@ static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = { pxa2xx_pm_write, }; -static void pxa2xx_pm_save(QEMUFile *f, void *opaque) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x40; i ++) - qemu_put_be32s(f, &s->pm_regs[i]); -} - -static int pxa2xx_pm_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x40; i ++) - qemu_get_be32s(f, &s->pm_regs[i]); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_pm = { + .name = "pxa2xx_pm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40), + VMSTATE_END_OF_LIST() + } +}; #define CCCR 0x00 /* Core Clock Configuration register */ #define CKEN 0x04 /* Clock Enable register */ @@ -227,29 +218,18 @@ static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = { pxa2xx_cm_write, }; -static void pxa2xx_cm_save(QEMUFile *f, void *opaque) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 4; i ++) - qemu_put_be32s(f, &s->cm_regs[i]); - qemu_put_be32s(f, &s->clkcfg); - qemu_put_be32s(f, &s->pmnc); -} - -static int pxa2xx_cm_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 4; i ++) - qemu_get_be32s(f, &s->cm_regs[i]); - qemu_get_be32s(f, &s->clkcfg); - qemu_get_be32s(f, &s->pmnc); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_cm = { + .name = "pxa2xx_cm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4), + VMSTATE_UINT32(clkcfg, PXA2xxState), + VMSTATE_UINT32(pmnc, PXA2xxState), + VMSTATE_END_OF_LIST() + } +}; static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm) { @@ -527,25 +507,16 @@ static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = { pxa2xx_mm_write, }; -static void pxa2xx_mm_save(QEMUFile *f, void *opaque) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x1a; i ++) - qemu_put_be32s(f, &s->mm_regs[i]); -} - -static int pxa2xx_mm_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x1a; i ++) - qemu_get_be32s(f, &s->mm_regs[i]); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_mm = { + .name = "pxa2xx_mm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a), + VMSTATE_END_OF_LIST() + } +}; /* Synchronous Serial Ports */ typedef struct { @@ -1748,39 +1719,23 @@ static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = { pxa2xx_i2s_write, }; -static void pxa2xx_i2s_save(QEMUFile *f, void *opaque) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - - qemu_put_be32s(f, &s->control[0]); - qemu_put_be32s(f, &s->control[1]); - qemu_put_be32s(f, &s->status); - qemu_put_be32s(f, &s->mask); - qemu_put_be32s(f, &s->clk); - - qemu_put_be32(f, s->enable); - qemu_put_be32(f, s->rx_len); - qemu_put_be32(f, s->tx_len); - qemu_put_be32(f, s->fifo_len); -} - -static int pxa2xx_i2s_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - - qemu_get_be32s(f, &s->control[0]); - qemu_get_be32s(f, &s->control[1]); - qemu_get_be32s(f, &s->status); - qemu_get_be32s(f, &s->mask); - qemu_get_be32s(f, &s->clk); - - s->enable = qemu_get_be32(f); - s->rx_len = qemu_get_be32(f); - s->tx_len = qemu_get_be32(f); - s->fifo_len = qemu_get_be32(f); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_i2s = { + .name = "pxa2xx_i2s", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2), + VMSTATE_UINT32(status, PXA2xxI2SState), + VMSTATE_UINT32(mask, PXA2xxI2SState), + VMSTATE_UINT32(clk, PXA2xxI2SState), + VMSTATE_INT32(enable, PXA2xxI2SState), + VMSTATE_INT32(rx_len, PXA2xxI2SState), + VMSTATE_INT32(tx_len, PXA2xxI2SState), + VMSTATE_INT32(fifo_len, PXA2xxI2SState), + VMSTATE_END_OF_LIST() + } +}; static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) { @@ -1822,8 +1777,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base, pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(base, 0x100000, iomemtype); - register_savevm(NULL, "pxa2xx_i2s", base, 0, - pxa2xx_i2s_save, pxa2xx_i2s_load, s); + vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s); return s; } @@ -2188,7 +2142,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -2199,13 +2153,13 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); - register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa27x_ssp[i].io_base; i ++); s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i); @@ -2324,7 +2278,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -2335,13 +2289,13 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); - register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa255_ssp[i].io_base; i ++); s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i); diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index d77dbf1..10ef154 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -289,40 +289,22 @@ static CPUWriteMemoryFunc * const pxa2xx_keypad_writefn[] = { pxa2xx_keypad_write }; -static void pxa2xx_keypad_save(QEMUFile *f, void *opaque) -{ - PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; - - qemu_put_be32s(f, &s->kpc); - qemu_put_be32s(f, &s->kpdk); - qemu_put_be32s(f, &s->kprec); - qemu_put_be32s(f, &s->kpmk); - qemu_put_be32s(f, &s->kpas); - qemu_put_be32s(f, &s->kpasmkp[0]); - qemu_put_be32s(f, &s->kpasmkp[1]); - qemu_put_be32s(f, &s->kpasmkp[2]); - qemu_put_be32s(f, &s->kpasmkp[3]); - qemu_put_be32s(f, &s->kpkdi); - -} - -static int pxa2xx_keypad_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; - - qemu_get_be32s(f, &s->kpc); - qemu_get_be32s(f, &s->kpdk); - qemu_get_be32s(f, &s->kprec); - qemu_get_be32s(f, &s->kpmk); - qemu_get_be32s(f, &s->kpas); - qemu_get_be32s(f, &s->kpasmkp[0]); - qemu_get_be32s(f, &s->kpasmkp[1]); - qemu_get_be32s(f, &s->kpasmkp[2]); - qemu_get_be32s(f, &s->kpasmkp[3]); - qemu_get_be32s(f, &s->kpkdi); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_keypad = { + .name = "pxa2xx_keypad", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(kpc, PXA2xxKeyPadState), + VMSTATE_UINT32(kpdk, PXA2xxKeyPadState), + VMSTATE_UINT32(kprec, PXA2xxKeyPadState), + VMSTATE_UINT32(kpmk, PXA2xxKeyPadState), + VMSTATE_UINT32(kpas, PXA2xxKeyPadState), + VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4), + VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState), + VMSTATE_END_OF_LIST() + } +}; PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base, qemu_irq irq) @@ -337,8 +319,7 @@ PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base, pxa2xx_keypad_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(base, 0x00100000, iomemtype); - register_savevm(NULL, "pxa2xx_keypad", 0, 0, - pxa2xx_keypad_save, pxa2xx_keypad_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s); return s; } diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 5b2b07e..e524802 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -15,6 +15,20 @@ #include "sysemu.h" #include "framebuffer.h" +struct DMAChannel { + target_phys_addr_t branch; + uint8_t up; + uint8_t palette[1024]; + uint8_t pbuffer[1024]; + void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr, + int *miny, int *maxy); + + target_phys_addr_t descriptor; + target_phys_addr_t source; + uint32_t id; + uint32_t command; +}; + struct PXA2xxLCDState { qemu_irq irq; int irqlevel; @@ -50,19 +64,7 @@ struct PXA2xxLCDState { uint32_t liidr; uint8_t bscntr; - struct { - target_phys_addr_t branch; - int up; - uint8_t palette[1024]; - uint8_t pbuffer[1024]; - void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr, - int *miny, int *maxy); - - target_phys_addr_t descriptor; - target_phys_addr_t source; - uint32_t id; - uint32_t command; - } dma_ch[7]; + struct DMAChannel dma_ch[7]; qemu_irq vsync_cb; int orientation; @@ -831,74 +833,26 @@ static void pxa2xx_lcdc_orientation(void *opaque, int angle) pxa2xx_lcdc_resize(s); } -static void pxa2xx_lcdc_save(QEMUFile *f, void *opaque) -{ - PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; - int i; - - qemu_put_be32(f, s->irqlevel); - qemu_put_be32(f, s->transp); - - for (i = 0; i < 6; i ++) - qemu_put_be32s(f, &s->control[i]); - for (i = 0; i < 2; i ++) - qemu_put_be32s(f, &s->status[i]); - for (i = 0; i < 2; i ++) - qemu_put_be32s(f, &s->ovl1c[i]); - for (i = 0; i < 2; i ++) - qemu_put_be32s(f, &s->ovl2c[i]); - qemu_put_be32s(f, &s->ccr); - qemu_put_be32s(f, &s->cmdcr); - qemu_put_be32s(f, &s->trgbr); - qemu_put_be32s(f, &s->tcr); - qemu_put_be32s(f, &s->liidr); - qemu_put_8s(f, &s->bscntr); - - for (i = 0; i < 7; i ++) { - qemu_put_betl(f, s->dma_ch[i].branch); - qemu_put_byte(f, s->dma_ch[i].up); - qemu_put_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); - - qemu_put_betl(f, s->dma_ch[i].descriptor); - qemu_put_betl(f, s->dma_ch[i].source); - qemu_put_be32s(f, &s->dma_ch[i].id); - qemu_put_be32s(f, &s->dma_ch[i].command); +static const VMStateDescription vmstate_dma_channel = { + .name = "dma_channel", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINTTL(branch, struct DMAChannel), + VMSTATE_UINT8(up, struct DMAChannel), + VMSTATE_BUFFER(pbuffer, struct DMAChannel), + VMSTATE_UINTTL(descriptor, struct DMAChannel), + VMSTATE_UINTTL(source, struct DMAChannel), + VMSTATE_UINT32(id, struct DMAChannel), + VMSTATE_UINT32(command, struct DMAChannel), + VMSTATE_END_OF_LIST() } -} +}; -static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id) +static int pxa2xx_lcdc_post_load(void *opaque, int version_id) { - PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; - int i; - - s->irqlevel = qemu_get_be32(f); - s->transp = qemu_get_be32(f); - - for (i = 0; i < 6; i ++) - qemu_get_be32s(f, &s->control[i]); - for (i = 0; i < 2; i ++) - qemu_get_be32s(f, &s->status[i]); - for (i = 0; i < 2; i ++) - qemu_get_be32s(f, &s->ovl1c[i]); - for (i = 0; i < 2; i ++) - qemu_get_be32s(f, &s->ovl2c[i]); - qemu_get_be32s(f, &s->ccr); - qemu_get_be32s(f, &s->cmdcr); - qemu_get_be32s(f, &s->trgbr); - qemu_get_be32s(f, &s->tcr); - qemu_get_be32s(f, &s->liidr); - qemu_get_8s(f, &s->bscntr); - - for (i = 0; i < 7; i ++) { - s->dma_ch[i].branch = qemu_get_betl(f); - s->dma_ch[i].up = qemu_get_byte(f); - qemu_get_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); - - s->dma_ch[i].descriptor = qemu_get_betl(f); - s->dma_ch[i].source = qemu_get_betl(f); - qemu_get_be32s(f, &s->dma_ch[i].id); - qemu_get_be32s(f, &s->dma_ch[i].command); - } + PXA2xxLCDState *s = opaque; s->bpp = LCCR3_BPP(s->control[3]); s->xres = s->yres = s->pal_for = -1; @@ -906,6 +860,31 @@ static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static const VMStateDescription vmstate_pxa2xx_lcdc = { + .name = "pxa2xx_lcdc", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = pxa2xx_lcdc_post_load, + .fields = (VMStateField[]) { + VMSTATE_INT32(irqlevel, PXA2xxLCDState), + VMSTATE_INT32(transp, PXA2xxLCDState), + VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6), + VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2), + VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2), + VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2), + VMSTATE_UINT32(ccr, PXA2xxLCDState), + VMSTATE_UINT32(cmdcr, PXA2xxLCDState), + VMSTATE_UINT32(trgbr, PXA2xxLCDState), + VMSTATE_UINT32(tcr, PXA2xxLCDState), + VMSTATE_UINT32(liidr, PXA2xxLCDState), + VMSTATE_UINT8(bscntr, PXA2xxLCDState), + VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0, + vmstate_dma_channel, struct DMAChannel), + VMSTATE_END_OF_LIST() + } +}; + #define BITS 8 #include "pxa2xx_template.h" #define BITS 15 @@ -970,8 +949,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq) exit(1); } - register_savevm(NULL, "pxa2xx_lcdc", 0, 0, - pxa2xx_lcdc_save, pxa2xx_lcdc_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s); return s; } diff --git a/hw/rc4030.c b/hw/rc4030.c index d30230a..6563336 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -307,7 +307,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) { target_phys_addr_t dest = s->cache_ptag & ~0x1; dest += (s->cache_maint & 0x3) << 3; - cpu_physical_memory_rw(dest, (uint8_t*)&val, 4, 1); + cpu_physical_memory_write(dest, &val, 4); } break; /* Remote Speed Registers */ @@ -704,7 +704,7 @@ void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, i entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry); /* XXX: not sure. should we really use only lowest bits? */ entry_addr &= 0x7fffffff; - cpu_physical_memory_rw(entry_addr, (uint8_t *)&entry, sizeof(entry), 0); + cpu_physical_memory_read(entry_addr, &entry, sizeof(entry)); /* Read/write data at right place */ phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1)); diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 58af164..bb49e39 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -43,6 +43,8 @@ do { } while (0) #endif +#define VIRTIO_EXT_CODE 0x2603 + struct BusInfo s390_virtio_bus_info = { .name = "s390-virtio", .size = sizeof(VirtIOS390Bus), @@ -223,7 +225,7 @@ void s390_virtio_device_sync(VirtIOS390Device *dev) cur_offs += num_vq * VIRTIO_VQCONFIG_LEN; /* Sync feature bitmap */ - stl_phys(cur_offs, dev->host_features); + stl_phys(cur_offs, bswap32(dev->host_features)); dev->feat_offs = cur_offs + dev->feat_len; cur_offs += dev->feat_len * 2; @@ -233,7 +235,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev) dev->vdev->get_config(dev->vdev, dev->vdev->config); } - cpu_physical_memory_rw(cur_offs, dev->vdev->config, dev->vdev->config_len, 1); + cpu_physical_memory_write(cur_offs, + dev->vdev->config, dev->vdev->config_len); cur_offs += dev->vdev->config_len; } @@ -246,7 +249,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev) /* Update guest supported feature bitmap */ - features = ldl_phys(dev->feat_offs); + features = bswap32(ldl_phys(dev->feat_offs)); if (vdev->set_features) { vdev->set_features(vdev, features); } @@ -304,9 +307,13 @@ static void virtio_s390_notify(void *opaque, uint16_t vector) { VirtIOS390Device *dev = (VirtIOS390Device*)opaque; uint64_t token = s390_virtio_device_vq_token(dev, vector); + CPUState *env = s390_cpu_addr2state(0); - /* XXX kvm dependency! */ - kvm_s390_virtio_irq(s390_cpu_addr2state(0), 0, token); + if (kvm_enabled()) { + kvm_s390_virtio_irq(env, 0, token); + } else { + cpu_inject_ext(env, VIRTIO_EXT_CODE, 0, token); + } } static unsigned virtio_s390_get_features(void *opaque) diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 850422f..698ff6f 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -82,13 +82,12 @@ CPUState *s390_cpu_addr2state(uint16_t cpu_addr) return ipi_states[cpu_addr]; } -int s390_virtio_hypercall(CPUState *env) +int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall) { int r = 0, i; - target_ulong mem = env->regs[2]; - dprintf("KVM hypercall: %ld\n", env->regs[1]); - switch (env->regs[1]) { + dprintf("KVM hypercall: %ld\n", hypercall); + switch (hypercall) { case KVM_S390_VIRTIO_NOTIFY: if (mem > ram_size) { VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus, @@ -128,8 +127,7 @@ int s390_virtio_hypercall(CPUState *env) break; } - env->regs[2] = r; - return 0; + return r; } /* PC hardware initialisation */ @@ -145,14 +143,9 @@ static void s390_init(ram_addr_t ram_size, ram_addr_t kernel_size = 0; ram_addr_t initrd_offset; ram_addr_t initrd_size = 0; + uint8_t *storage_keys; int i; - /* XXX we only work on KVM for now */ - - if (!kvm_enabled()) { - fprintf(stderr, "The S390 target only works with KVM enabled\n"); - exit(1); - } /* get a BUS */ s390_bus = s390_virtio_bus_init(&ram_size); @@ -161,6 +154,9 @@ static void s390_init(ram_addr_t ram_size, ram_addr = qemu_ram_alloc(NULL, "s390.ram", ram_size); cpu_register_physical_memory(0, ram_size, ram_addr); + /* allocate storage keys */ + storage_keys = qemu_mallocz(ram_size / TARGET_PAGE_SIZE); + /* init CPUs */ if (cpu_model == NULL) { cpu_model = "host"; @@ -178,6 +174,7 @@ static void s390_init(ram_addr_t ram_size, ipi_states[i] = tmp_env; tmp_env->halted = 1; tmp_env->exception_index = EXCP_HLT; + tmp_env->storage_keys = storage_keys; } env->halted = 0; @@ -230,8 +227,8 @@ static void s390_init(ram_addr_t ram_size, } if (kernel_cmdline) { - cpu_physical_memory_rw(KERN_PARM_AREA, (uint8_t *)kernel_cmdline, - strlen(kernel_cmdline), 1); + cpu_physical_memory_write(KERN_PARM_AREA, kernel_cmdline, + strlen(kernel_cmdline)); } /* Create VirtIO network adapters */ diff --git a/hw/sm501_template.h b/hw/sm501_template.h index d1ceef9..2d4a3d8 100644 --- a/hw/sm501_template.h +++ b/hw/sm501_template.h @@ -120,7 +120,7 @@ static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt, /* get pixel value */ if (i % 4 == 0) { - cpu_physical_memory_rw(cursor_addr, &bitset, 1, 0); + bitset = ldub_phys(cursor_addr); cursor_addr++; } v = bitset & 3; @@ -66,3 +66,6 @@ void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data); void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data, int len); + +void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom, + const uint8_t *eeprom_spd, int size); diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 52463e0..3634754 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -96,7 +96,7 @@ static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) return eeprom_receive_byte(dev); } -static int smbus_eeprom_init(SMBusDevice *dev) +static int smbus_eeprom_initfn(SMBusDevice *dev) { SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev; @@ -111,7 +111,7 @@ static SMBusDeviceInfo smbus_eeprom_info = { DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data), DEFINE_PROP_END_OF_LIST(), }, - .init = smbus_eeprom_init, + .init = smbus_eeprom_initfn, .quick_cmd = eeprom_quick_cmd, .send_byte = eeprom_send_byte, .receive_byte = eeprom_receive_byte, @@ -125,3 +125,21 @@ static void smbus_eeprom_register_devices(void) } device_init(smbus_eeprom_register_devices) + +void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom, + const uint8_t *eeprom_spd, int eeprom_spd_size) +{ + int i; + uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ + if (eeprom_spd_size > 0) { + memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size); + } + + for (i = 0; i < nb_eeprom; i++) { + DeviceState *eeprom; + eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); + qdev_prop_set_uint8(eeprom, "address", 0x50 + i); + qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); + qdev_init_nofail(eeprom); + } +} diff --git a/hw/stellaris.c b/hw/stellaris.c index 0d52926..ac9fcc1 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -14,7 +14,6 @@ #include "qemu-timer.h" #include "i2c.h" #include "net.h" -#include "sysemu.h" #include "boards.h" #define GPIO_A 0 @@ -280,64 +279,28 @@ static CPUWriteMemoryFunc * const gptm_writefn[] = { gptm_write }; -static void gptm_save(QEMUFile *f, void *opaque) -{ - gptm_state *s = (gptm_state *)opaque; - - qemu_put_be32(f, s->config); - qemu_put_be32(f, s->mode[0]); - qemu_put_be32(f, s->mode[1]); - qemu_put_be32(f, s->control); - qemu_put_be32(f, s->state); - qemu_put_be32(f, s->mask); - qemu_put_be32(f, s->mode[0]); - qemu_put_be32(f, s->mode[0]); - qemu_put_be32(f, s->load[0]); - qemu_put_be32(f, s->load[1]); - qemu_put_be32(f, s->match[0]); - qemu_put_be32(f, s->match[1]); - qemu_put_be32(f, s->prescale[0]); - qemu_put_be32(f, s->prescale[1]); - qemu_put_be32(f, s->match_prescale[0]); - qemu_put_be32(f, s->match_prescale[1]); - qemu_put_be32(f, s->rtc); - qemu_put_be64(f, s->tick[0]); - qemu_put_be64(f, s->tick[1]); - qemu_put_timer(f, s->timer[0]); - qemu_put_timer(f, s->timer[1]); -} - -static int gptm_load(QEMUFile *f, void *opaque, int version_id) -{ - gptm_state *s = (gptm_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->config = qemu_get_be32(f); - s->mode[0] = qemu_get_be32(f); - s->mode[1] = qemu_get_be32(f); - s->control = qemu_get_be32(f); - s->state = qemu_get_be32(f); - s->mask = qemu_get_be32(f); - s->mode[0] = qemu_get_be32(f); - s->mode[0] = qemu_get_be32(f); - s->load[0] = qemu_get_be32(f); - s->load[1] = qemu_get_be32(f); - s->match[0] = qemu_get_be32(f); - s->match[1] = qemu_get_be32(f); - s->prescale[0] = qemu_get_be32(f); - s->prescale[1] = qemu_get_be32(f); - s->match_prescale[0] = qemu_get_be32(f); - s->match_prescale[1] = qemu_get_be32(f); - s->rtc = qemu_get_be32(f); - s->tick[0] = qemu_get_be64(f); - s->tick[1] = qemu_get_be64(f); - qemu_get_timer(f, s->timer[0]); - qemu_get_timer(f, s->timer[1]); - - return 0; -} +static const VMStateDescription vmstate_stellaris_gptm = { + .name = "stellaris_gptm", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(config, gptm_state), + VMSTATE_UINT32_ARRAY(mode, gptm_state, 2), + VMSTATE_UINT32(control, gptm_state), + VMSTATE_UINT32(state, gptm_state), + VMSTATE_UINT32(mask, gptm_state), + VMSTATE_UNUSED(8), + VMSTATE_UINT32_ARRAY(load, gptm_state, 2), + VMSTATE_UINT32_ARRAY(match, gptm_state, 2), + VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2), + VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2), + VMSTATE_UINT32(rtc, gptm_state), + VMSTATE_INT64_ARRAY(tick, gptm_state, 2), + VMSTATE_TIMER_ARRAY(timer, gptm_state, 2), + VMSTATE_END_OF_LIST() + } +}; static int stellaris_gptm_init(SysBusDevice *dev) { @@ -355,8 +318,7 @@ static int stellaris_gptm_init(SysBusDevice *dev) s->opaque[0] = s->opaque[1] = s; s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]); s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]); - register_savevm(&dev->qdev, "stellaris_gptm", -1, 1, - gptm_save, gptm_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s); return 0; } @@ -605,58 +567,37 @@ static void ssys_reset(void *opaque) s->dcgc[0] = 1; } -static void ssys_save(QEMUFile *f, void *opaque) -{ - ssys_state *s = (ssys_state *)opaque; - - qemu_put_be32(f, s->pborctl); - qemu_put_be32(f, s->ldopctl); - qemu_put_be32(f, s->int_mask); - qemu_put_be32(f, s->int_status); - qemu_put_be32(f, s->resc); - qemu_put_be32(f, s->rcc); - qemu_put_be32(f, s->rcgc[0]); - qemu_put_be32(f, s->rcgc[1]); - qemu_put_be32(f, s->rcgc[2]); - qemu_put_be32(f, s->scgc[0]); - qemu_put_be32(f, s->scgc[1]); - qemu_put_be32(f, s->scgc[2]); - qemu_put_be32(f, s->dcgc[0]); - qemu_put_be32(f, s->dcgc[1]); - qemu_put_be32(f, s->dcgc[2]); - qemu_put_be32(f, s->clkvclr); - qemu_put_be32(f, s->ldoarst); -} - -static int ssys_load(QEMUFile *f, void *opaque, int version_id) +static int stellaris_sys_post_load(void *opaque, int version_id) { - ssys_state *s = (ssys_state *)opaque; + ssys_state *s = opaque; - if (version_id != 1) - return -EINVAL; - - s->pborctl = qemu_get_be32(f); - s->ldopctl = qemu_get_be32(f); - s->int_mask = qemu_get_be32(f); - s->int_status = qemu_get_be32(f); - s->resc = qemu_get_be32(f); - s->rcc = qemu_get_be32(f); - s->rcgc[0] = qemu_get_be32(f); - s->rcgc[1] = qemu_get_be32(f); - s->rcgc[2] = qemu_get_be32(f); - s->scgc[0] = qemu_get_be32(f); - s->scgc[1] = qemu_get_be32(f); - s->scgc[2] = qemu_get_be32(f); - s->dcgc[0] = qemu_get_be32(f); - s->dcgc[1] = qemu_get_be32(f); - s->dcgc[2] = qemu_get_be32(f); - s->clkvclr = qemu_get_be32(f); - s->ldoarst = qemu_get_be32(f); ssys_calculate_system_clock(s); return 0; } +static const VMStateDescription vmstate_stellaris_sys = { + .name = "stellaris_sys", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = stellaris_sys_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(pborctl, ssys_state), + VMSTATE_UINT32(ldopctl, ssys_state), + VMSTATE_UINT32(int_mask, ssys_state), + VMSTATE_UINT32(int_status, ssys_state), + VMSTATE_UINT32(resc, ssys_state), + VMSTATE_UINT32(rcc, ssys_state), + VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3), + VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3), + VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3), + VMSTATE_UINT32(clkvclr, ssys_state), + VMSTATE_UINT32(ldoarst, ssys_state), + VMSTATE_END_OF_LIST() + } +}; + static int stellaris_sys_init(uint32_t base, qemu_irq irq, stellaris_board_info * board, uint8_t *macaddr) @@ -676,7 +617,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(base, 0x00001000, iomemtype); ssys_reset(s); - register_savevm(NULL, "stellaris_sys", -1, 1, ssys_save, ssys_load, s); + vmstate_register(NULL, -1, &vmstate_stellaris_sys, s); return 0; } @@ -844,36 +785,22 @@ static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = { stellaris_i2c_write }; -static void stellaris_i2c_save(QEMUFile *f, void *opaque) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - qemu_put_be32(f, s->msa); - qemu_put_be32(f, s->mcs); - qemu_put_be32(f, s->mdr); - qemu_put_be32(f, s->mtpr); - qemu_put_be32(f, s->mimr); - qemu_put_be32(f, s->mris); - qemu_put_be32(f, s->mcr); -} - -static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->msa = qemu_get_be32(f); - s->mcs = qemu_get_be32(f); - s->mdr = qemu_get_be32(f); - s->mtpr = qemu_get_be32(f); - s->mimr = qemu_get_be32(f); - s->mris = qemu_get_be32(f); - s->mcr = qemu_get_be32(f); - - return 0; -} +static const VMStateDescription vmstate_stellaris_i2c = { + .name = "stellaris_i2c", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(msa, stellaris_i2c_state), + VMSTATE_UINT32(mcs, stellaris_i2c_state), + VMSTATE_UINT32(mdr, stellaris_i2c_state), + VMSTATE_UINT32(mtpr, stellaris_i2c_state), + VMSTATE_UINT32(mimr, stellaris_i2c_state), + VMSTATE_UINT32(mris, stellaris_i2c_state), + VMSTATE_UINT32(mcr, stellaris_i2c_state), + VMSTATE_END_OF_LIST() + } +}; static int stellaris_i2c_init(SysBusDevice * dev) { @@ -891,8 +818,7 @@ static int stellaris_i2c_init(SysBusDevice * dev) sysbus_init_mmio(dev, 0x1000, iomemtype); /* ??? For now we only implement the master interface. */ stellaris_i2c_reset(s); - register_savevm(&dev->qdev, "stellaris_i2c", -1, 1, - stellaris_i2c_save, stellaris_i2c_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s); return 0; } @@ -1130,60 +1056,40 @@ static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = { stellaris_adc_write }; -static void stellaris_adc_save(QEMUFile *f, void *opaque) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - int i; - int j; - - qemu_put_be32(f, s->actss); - qemu_put_be32(f, s->ris); - qemu_put_be32(f, s->im); - qemu_put_be32(f, s->emux); - qemu_put_be32(f, s->ostat); - qemu_put_be32(f, s->ustat); - qemu_put_be32(f, s->sspri); - qemu_put_be32(f, s->sac); - for (i = 0; i < 4; i++) { - qemu_put_be32(f, s->fifo[i].state); - for (j = 0; j < 16; j++) { - qemu_put_be32(f, s->fifo[i].data[j]); - } - qemu_put_be32(f, s->ssmux[i]); - qemu_put_be32(f, s->ssctl[i]); - } - qemu_put_be32(f, s->noise); -} - -static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - int i; - int j; - - if (version_id != 1) - return -EINVAL; - - s->actss = qemu_get_be32(f); - s->ris = qemu_get_be32(f); - s->im = qemu_get_be32(f); - s->emux = qemu_get_be32(f); - s->ostat = qemu_get_be32(f); - s->ustat = qemu_get_be32(f); - s->sspri = qemu_get_be32(f); - s->sac = qemu_get_be32(f); - for (i = 0; i < 4; i++) { - s->fifo[i].state = qemu_get_be32(f); - for (j = 0; j < 16; j++) { - s->fifo[i].data[j] = qemu_get_be32(f); - } - s->ssmux[i] = qemu_get_be32(f); - s->ssctl[i] = qemu_get_be32(f); +static const VMStateDescription vmstate_stellaris_adc = { + .name = "stellaris_adc", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(actss, stellaris_adc_state), + VMSTATE_UINT32(ris, stellaris_adc_state), + VMSTATE_UINT32(im, stellaris_adc_state), + VMSTATE_UINT32(emux, stellaris_adc_state), + VMSTATE_UINT32(ostat, stellaris_adc_state), + VMSTATE_UINT32(ustat, stellaris_adc_state), + VMSTATE_UINT32(sspri, stellaris_adc_state), + VMSTATE_UINT32(sac, stellaris_adc_state), + VMSTATE_UINT32(fifo[0].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[0], stellaris_adc_state), + VMSTATE_UINT32(ssctl[0], stellaris_adc_state), + VMSTATE_UINT32(fifo[1].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[1], stellaris_adc_state), + VMSTATE_UINT32(ssctl[1], stellaris_adc_state), + VMSTATE_UINT32(fifo[2].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[2], stellaris_adc_state), + VMSTATE_UINT32(ssctl[2], stellaris_adc_state), + VMSTATE_UINT32(fifo[3].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[3], stellaris_adc_state), + VMSTATE_UINT32(ssctl[3], stellaris_adc_state), + VMSTATE_UINT32(noise, stellaris_adc_state), + VMSTATE_END_OF_LIST() } - s->noise = qemu_get_be32(f); - - return 0; -} +}; static int stellaris_adc_init(SysBusDevice *dev) { @@ -1201,8 +1107,7 @@ static int stellaris_adc_init(SysBusDevice *dev) sysbus_init_mmio(dev, 0x1000, iomemtype); stellaris_adc_reset(s); qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1); - register_savevm(&dev->qdev, "stellaris_adc", -1, 1, - stellaris_adc_save, stellaris_adc_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s); return 0; } @@ -1234,24 +1139,16 @@ static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val) return ssi_transfer(s->bus[s->current_dev], val); } -static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque) -{ - stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; - - qemu_put_be32(f, s->current_dev); -} - -static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->current_dev = qemu_get_be32(f); - - return 0; -} +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) { @@ -1261,8 +1158,7 @@ static int stellaris_ssi_bus_init(SSISlave *dev) s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1); - register_savevm(&dev->qdev, "stellaris_ssi_bus", -1, 1, - stellaris_ssi_bus_save, stellaris_ssi_bus_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s); return 0; } diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c index 16aae96..06c5f9d 100644 --- a/hw/stellaris_input.c +++ b/hw/stellaris_input.c @@ -13,7 +13,7 @@ typedef struct { qemu_irq irq; int keycode; - int pressed; + uint8_t pressed; } gamepad_button; typedef struct { @@ -47,30 +47,29 @@ static void stellaris_gamepad_put_key(void * opaque, int keycode) s->extension = 0; } -static void stellaris_gamepad_save(QEMUFile *f, void *opaque) -{ - gamepad_state *s = (gamepad_state *)opaque; - int i; - - qemu_put_be32(f, s->extension); - for (i = 0; i < s->num_buttons; i++) - qemu_put_byte(f, s->buttons[i].pressed); -} - -static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id) -{ - gamepad_state *s = (gamepad_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->extension = qemu_get_be32(f); - for (i = 0; i < s->num_buttons; i++) - s->buttons[i].pressed = qemu_get_byte(f); +static const VMStateDescription vmstate_stellaris_button = { + .name = "stellaris_button", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(pressed, gamepad_button), + VMSTATE_END_OF_LIST() + } +}; - return 0; -} +static const VMStateDescription vmstate_stellaris_gamepad = { + .name = "stellaris_gamepad", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(extension, gamepad_state), + VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0, + vmstate_stellaris_button, gamepad_button), + VMSTATE_END_OF_LIST() + } +}; /* Returns an array 5 ouput slots. */ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) @@ -86,6 +85,5 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) } s->num_buttons = n; qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); - register_savevm(NULL, "stellaris_gamepad", -1, 1, - stellaris_gamepad_save, stellaris_gamepad_load, s); + vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s); } diff --git a/hw/strongarm.c b/hw/strongarm.c new file mode 100644 index 0000000..de08bdf --- /dev/null +++ b/hw/strongarm.c @@ -0,0 +1,1598 @@ +/* + * StrongARM SA-1100/SA-1110 emulation + * + * Copyright (C) 2011 Dmitry Eremin-Solenikov + * + * Largely based on StrongARM emulation: + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski <balrog@zabor.org> + * + * UART code based on QEMU 16550A UART emulation + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 "sysbus.h" +#include "strongarm.h" +#include "qemu-error.h" +#include "arm-misc.h" +#include "sysemu.h" +#include "ssi.h" + +//#define DEBUG + +/* + TODO + - Implement cp15, c14 ? + - Implement cp15, c15 !!! (idle used in L) + - Implement idle mode handling/DIM + - Implement sleep mode/Wake sources + - Implement reset control + - Implement memory control regs + - PCMCIA handling + - Maybe support MBGNT/MBREQ + - DMA channels + - GPCLK + - IrDA + - MCP + - Enhance UART with modem signals + */ + +#ifdef DEBUG +# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__) +#else +# define DPRINTF(format, ...) do { } while (0) +#endif + +static struct { + target_phys_addr_t io_base; + int irq; +} sa_serial[] = { + { 0x80010000, SA_PIC_UART1 }, + { 0x80030000, SA_PIC_UART2 }, + { 0x80050000, SA_PIC_UART3 }, + { 0, 0 } +}; + +/* Interrupt Controller */ +typedef struct { + SysBusDevice busdev; + qemu_irq irq; + qemu_irq fiq; + + uint32_t pending; + uint32_t enabled; + uint32_t is_fiq; + uint32_t int_idle; +} StrongARMPICState; + +#define ICIP 0x00 +#define ICMR 0x04 +#define ICLR 0x08 +#define ICFP 0x10 +#define ICPR 0x20 +#define ICCR 0x0c + +#define SA_PIC_SRCS 32 + + +static void strongarm_pic_update(void *opaque) +{ + StrongARMPICState *s = opaque; + + /* FIXME: reflect DIM */ + qemu_set_irq(s->fiq, s->pending & s->enabled & s->is_fiq); + qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq); +} + +static void strongarm_pic_set_irq(void *opaque, int irq, int level) +{ + StrongARMPICState *s = opaque; + + if (level) { + s->pending |= 1 << irq; + } else { + s->pending &= ~(1 << irq); + } + + strongarm_pic_update(s); +} + +static uint32_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset) +{ + StrongARMPICState *s = opaque; + + switch (offset) { + case ICIP: + return s->pending & ~s->is_fiq & s->enabled; + case ICMR: + return s->enabled; + case ICLR: + return s->is_fiq; + case ICCR: + return s->int_idle == 0; + case ICFP: + return s->pending & s->is_fiq & s->enabled; + case ICPR: + return s->pending; + default: + printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", + __func__, offset); + return 0; + } +} + +static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + StrongARMPICState *s = opaque; + + switch (offset) { + case ICMR: + s->enabled = value; + break; + case ICLR: + s->is_fiq = value; + break; + case ICCR: + s->int_idle = (value & 1) ? 0 : ~0; + break; + default: + printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", + __func__, offset); + break; + } + strongarm_pic_update(s); +} + +static CPUReadMemoryFunc * const strongarm_pic_readfn[] = { + strongarm_pic_mem_read, + strongarm_pic_mem_read, + strongarm_pic_mem_read, +}; + +static CPUWriteMemoryFunc * const strongarm_pic_writefn[] = { + strongarm_pic_mem_write, + strongarm_pic_mem_write, + strongarm_pic_mem_write, +}; + +static int strongarm_pic_initfn(SysBusDevice *dev) +{ + StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev); + int iomemtype; + + qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS); + iomemtype = cpu_register_io_memory(strongarm_pic_readfn, + strongarm_pic_writefn, s, DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x1000, iomemtype); + sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(dev, &s->fiq); + + return 0; +} + +static int strongarm_pic_post_load(void *opaque, int version_id) +{ + strongarm_pic_update(opaque); + return 0; +} + +static VMStateDescription vmstate_strongarm_pic_regs = { + .name = "strongarm_pic", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = strongarm_pic_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(pending, StrongARMPICState), + VMSTATE_UINT32(enabled, StrongARMPICState), + VMSTATE_UINT32(is_fiq, StrongARMPICState), + VMSTATE_UINT32(int_idle, StrongARMPICState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_pic_info = { + .init = strongarm_pic_initfn, + .qdev.name = "strongarm_pic", + .qdev.desc = "StrongARM PIC", + .qdev.size = sizeof(StrongARMPICState), + .qdev.vmsd = &vmstate_strongarm_pic_regs, +}; + +/* Real-Time Clock */ +#define RTAR 0x00 /* RTC Alarm register */ +#define RCNR 0x04 /* RTC Counter register */ +#define RTTR 0x08 /* RTC Timer Trim register */ +#define RTSR 0x10 /* RTC Status register */ + +#define RTSR_AL (1 << 0) /* RTC Alarm detected */ +#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */ +#define RTSR_ALE (1 << 2) /* RTC Alarm enable */ +#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */ + +/* 16 LSB of RTTR are clockdiv for internal trim logic, + * trim delete isn't emulated, so + * f = 32 768 / (RTTR_trim + 1) */ + +typedef struct { + SysBusDevice busdev; + uint32_t rttr; + uint32_t rtsr; + uint32_t rtar; + uint32_t last_rcnr; + int64_t last_hz; + QEMUTimer *rtc_alarm; + QEMUTimer *rtc_hz; + qemu_irq rtc_irq; + qemu_irq rtc_hz_irq; +} StrongARMRTCState; + +static inline void strongarm_rtc_int_update(StrongARMRTCState *s) +{ + qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL); + qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ); +} + +static void strongarm_rtc_hzupdate(StrongARMRTCState *s) +{ + int64_t rt = qemu_get_clock_ms(rt_clock); + s->last_rcnr += ((rt - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + s->last_hz = rt; +} + +static inline void strongarm_rtc_timer_update(StrongARMRTCState *s) +{ + if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) { + qemu_mod_timer(s->rtc_hz, s->last_hz + 1000); + } else { + qemu_del_timer(s->rtc_hz); + } + + if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) { + qemu_mod_timer(s->rtc_alarm, s->last_hz + + (((s->rtar - s->last_rcnr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); + } else { + qemu_del_timer(s->rtc_alarm); + } +} + +static inline void strongarm_rtc_alarm_tick(void *opaque) +{ + StrongARMRTCState *s = opaque; + s->rtsr |= RTSR_AL; + strongarm_rtc_timer_update(s); + strongarm_rtc_int_update(s); +} + +static inline void strongarm_rtc_hz_tick(void *opaque) +{ + StrongARMRTCState *s = opaque; + s->rtsr |= RTSR_HZ; + strongarm_rtc_timer_update(s); + strongarm_rtc_int_update(s); +} + +static uint32_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr) +{ + StrongARMRTCState *s = opaque; + + switch (addr) { + case RTTR: + return s->rttr; + case RTSR: + return s->rtsr; + case RTAR: + return s->rtar; + case RCNR: + return s->last_rcnr + + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + return 0; + } +} + +static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + StrongARMRTCState *s = opaque; + uint32_t old_rtsr; + + switch (addr) { + case RTTR: + strongarm_rtc_hzupdate(s); + s->rttr = value; + strongarm_rtc_timer_update(s); + break; + + case RTSR: + old_rtsr = s->rtsr; + s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) | + (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ))); + + if (s->rtsr != old_rtsr) { + strongarm_rtc_timer_update(s); + } + + strongarm_rtc_int_update(s); + break; + + case RTAR: + s->rtar = value; + strongarm_rtc_timer_update(s); + break; + + case RCNR: + strongarm_rtc_hzupdate(s); + s->last_rcnr = value; + strongarm_rtc_timer_update(s); + break; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + } +} + +static CPUReadMemoryFunc * const strongarm_rtc_readfn[] = { + strongarm_rtc_read, + strongarm_rtc_read, + strongarm_rtc_read, +}; + +static CPUWriteMemoryFunc * const strongarm_rtc_writefn[] = { + strongarm_rtc_write, + strongarm_rtc_write, + strongarm_rtc_write, +}; + +static int strongarm_rtc_init(SysBusDevice *dev) +{ + StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev); + struct tm tm; + int iomemtype; + + s->rttr = 0x0; + s->rtsr = 0; + + qemu_get_timedate(&tm, 0); + + s->last_rcnr = (uint32_t) mktimegm(&tm); + s->last_hz = qemu_get_clock_ms(rt_clock); + + s->rtc_alarm = qemu_new_timer_ms(rt_clock, strongarm_rtc_alarm_tick, s); + s->rtc_hz = qemu_new_timer_ms(rt_clock, strongarm_rtc_hz_tick, s); + + sysbus_init_irq(dev, &s->rtc_irq); + sysbus_init_irq(dev, &s->rtc_hz_irq); + + iomemtype = cpu_register_io_memory(strongarm_rtc_readfn, + strongarm_rtc_writefn, s, DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x10000, iomemtype); + + return 0; +} + +static void strongarm_rtc_pre_save(void *opaque) +{ + StrongARMRTCState *s = opaque; + + strongarm_rtc_hzupdate(s); +} + +static int strongarm_rtc_post_load(void *opaque, int version_id) +{ + StrongARMRTCState *s = opaque; + + strongarm_rtc_timer_update(s); + strongarm_rtc_int_update(s); + + return 0; +} + +static const VMStateDescription vmstate_strongarm_rtc_regs = { + .name = "strongarm-rtc", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .pre_save = strongarm_rtc_pre_save, + .post_load = strongarm_rtc_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(rttr, StrongARMRTCState), + VMSTATE_UINT32(rtsr, StrongARMRTCState), + VMSTATE_UINT32(rtar, StrongARMRTCState), + VMSTATE_UINT32(last_rcnr, StrongARMRTCState), + VMSTATE_INT64(last_hz, StrongARMRTCState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_rtc_sysbus_info = { + .init = strongarm_rtc_init, + .qdev.name = "strongarm-rtc", + .qdev.desc = "StrongARM RTC Controller", + .qdev.size = sizeof(StrongARMRTCState), + .qdev.vmsd = &vmstate_strongarm_rtc_regs, +}; + +/* GPIO */ +#define GPLR 0x00 +#define GPDR 0x04 +#define GPSR 0x08 +#define GPCR 0x0c +#define GRER 0x10 +#define GFER 0x14 +#define GEDR 0x18 +#define GAFR 0x1c + +typedef struct StrongARMGPIOInfo StrongARMGPIOInfo; +struct StrongARMGPIOInfo { + SysBusDevice busdev; + qemu_irq handler[28]; + qemu_irq irqs[11]; + qemu_irq irqX; + + uint32_t ilevel; + uint32_t olevel; + uint32_t dir; + uint32_t rising; + uint32_t falling; + uint32_t status; + uint32_t gpsr; + uint32_t gafr; + + uint32_t prev_level; +}; + + +static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s) +{ + int i; + for (i = 0; i < 11; i++) { + qemu_set_irq(s->irqs[i], s->status & (1 << i)); + } + + qemu_set_irq(s->irqX, (s->status & ~0x7ff)); +} + +static void strongarm_gpio_set(void *opaque, int line, int level) +{ + StrongARMGPIOInfo *s = opaque; + uint32_t mask; + + mask = 1 << line; + + if (level) { + s->status |= s->rising & mask & + ~s->ilevel & ~s->dir; + s->ilevel |= mask; + } else { + s->status |= s->falling & mask & + s->ilevel & ~s->dir; + s->ilevel &= ~mask; + } + + if (s->status & mask) { + strongarm_gpio_irq_update(s); + } +} + +static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s) +{ + uint32_t level, diff; + int bit; + + level = s->olevel & s->dir; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->handler[bit], (level >> bit) & 1); + } + + s->prev_level = level; +} + +static uint32_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset) +{ + StrongARMGPIOInfo *s = opaque; + + switch (offset) { + case GPDR: /* GPIO Pin-Direction registers */ + return s->dir; + + case GPSR: /* GPIO Pin-Output Set registers */ + DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n", + __func__, offset); + return s->gpsr; /* Return last written value. */ + + case GPCR: /* GPIO Pin-Output Clear registers */ + DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n", + __func__, offset); + return 31337; /* Specified as unpredictable in the docs. */ + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + return s->rising; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + return s->falling; + + case GAFR: /* GPIO Alternate Function registers */ + return s->gafr; + + case GPLR: /* GPIO Pin-Level registers */ + return (s->olevel & s->dir) | + (s->ilevel & ~s->dir); + + case GEDR: /* GPIO Edge Detect Status registers */ + return s->status; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } + + return 0; +} + +static void strongarm_gpio_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + StrongARMGPIOInfo *s = opaque; + + switch (offset) { + case GPDR: /* GPIO Pin-Direction registers */ + s->dir = value; + strongarm_gpio_handler_update(s); + break; + + case GPSR: /* GPIO Pin-Output Set registers */ + s->olevel |= value; + strongarm_gpio_handler_update(s); + s->gpsr = value; + break; + + case GPCR: /* GPIO Pin-Output Clear registers */ + s->olevel &= ~value; + strongarm_gpio_handler_update(s); + break; + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + s->rising = value; + break; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + s->falling = value; + break; + + case GAFR: /* GPIO Alternate Function registers */ + s->gafr = value; + break; + + case GEDR: /* GPIO Edge Detect Status registers */ + s->status &= ~value; + strongarm_gpio_irq_update(s); + break; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } +} + +static CPUReadMemoryFunc * const strongarm_gpio_readfn[] = { + strongarm_gpio_read, + strongarm_gpio_read, + strongarm_gpio_read +}; + +static CPUWriteMemoryFunc * const strongarm_gpio_writefn[] = { + strongarm_gpio_write, + strongarm_gpio_write, + strongarm_gpio_write +}; + +static DeviceState *strongarm_gpio_init(target_phys_addr_t base, + DeviceState *pic) +{ + DeviceState *dev; + int i; + + dev = qdev_create(NULL, "strongarm-gpio"); + qdev_init_nofail(dev); + + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + for (i = 0; i < 12; i++) + sysbus_connect_irq(sysbus_from_qdev(dev), i, + qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i)); + + return dev; +} + +static int strongarm_gpio_initfn(SysBusDevice *dev) +{ + int iomemtype; + StrongARMGPIOInfo *s; + int i; + + s = FROM_SYSBUS(StrongARMGPIOInfo, dev); + + qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28); + qdev_init_gpio_out(&dev->qdev, s->handler, 28); + + iomemtype = cpu_register_io_memory(strongarm_gpio_readfn, + strongarm_gpio_writefn, s, DEVICE_NATIVE_ENDIAN); + + sysbus_init_mmio(dev, 0x1000, iomemtype); + for (i = 0; i < 11; i++) { + sysbus_init_irq(dev, &s->irqs[i]); + } + sysbus_init_irq(dev, &s->irqX); + + return 0; +} + +static const VMStateDescription vmstate_strongarm_gpio_regs = { + .name = "strongarm-gpio", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ilevel, StrongARMGPIOInfo), + VMSTATE_UINT32(olevel, StrongARMGPIOInfo), + VMSTATE_UINT32(dir, StrongARMGPIOInfo), + VMSTATE_UINT32(rising, StrongARMGPIOInfo), + VMSTATE_UINT32(falling, StrongARMGPIOInfo), + VMSTATE_UINT32(status, StrongARMGPIOInfo), + VMSTATE_UINT32(gafr, StrongARMGPIOInfo), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_gpio_info = { + .init = strongarm_gpio_initfn, + .qdev.name = "strongarm-gpio", + .qdev.desc = "StrongARM GPIO controller", + .qdev.size = sizeof(StrongARMGPIOInfo), +}; + +/* Peripheral Pin Controller */ +#define PPDR 0x00 +#define PPSR 0x04 +#define PPAR 0x08 +#define PSDR 0x0c +#define PPFR 0x10 + +typedef struct StrongARMPPCInfo StrongARMPPCInfo; +struct StrongARMPPCInfo { + SysBusDevice busdev; + qemu_irq handler[28]; + + uint32_t ilevel; + uint32_t olevel; + uint32_t dir; + uint32_t ppar; + uint32_t psdr; + uint32_t ppfr; + + uint32_t prev_level; +}; + +static void strongarm_ppc_set(void *opaque, int line, int level) +{ + StrongARMPPCInfo *s = opaque; + + if (level) { + s->ilevel |= 1 << line; + } else { + s->ilevel &= ~(1 << line); + } +} + +static void strongarm_ppc_handler_update(StrongARMPPCInfo *s) +{ + uint32_t level, diff; + int bit; + + level = s->olevel & s->dir; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->handler[bit], (level >> bit) & 1); + } + + s->prev_level = level; +} + +static uint32_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset) +{ + StrongARMPPCInfo *s = opaque; + + switch (offset) { + case PPDR: /* PPC Pin Direction registers */ + return s->dir | ~0x3fffff; + + case PPSR: /* PPC Pin State registers */ + return (s->olevel & s->dir) | + (s->ilevel & ~s->dir) | + ~0x3fffff; + + case PPAR: + return s->ppar | ~0x41000; + + case PSDR: + return s->psdr; + + case PPFR: + return s->ppfr | ~0x7f001; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } + + return 0; +} + +static void strongarm_ppc_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + StrongARMPPCInfo *s = opaque; + + switch (offset) { + case PPDR: /* PPC Pin Direction registers */ + s->dir = value & 0x3fffff; + strongarm_ppc_handler_update(s); + break; + + case PPSR: /* PPC Pin State registers */ + s->olevel = value & s->dir & 0x3fffff; + strongarm_ppc_handler_update(s); + break; + + case PPAR: + s->ppar = value & 0x41000; + break; + + case PSDR: + s->psdr = value & 0x3fffff; + break; + + case PPFR: + s->ppfr = value & 0x7f001; + break; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } +} + +static CPUReadMemoryFunc * const strongarm_ppc_readfn[] = { + strongarm_ppc_read, + strongarm_ppc_read, + strongarm_ppc_read +}; + +static CPUWriteMemoryFunc * const strongarm_ppc_writefn[] = { + strongarm_ppc_write, + strongarm_ppc_write, + strongarm_ppc_write +}; + +static int strongarm_ppc_init(SysBusDevice *dev) +{ + int iomemtype; + StrongARMPPCInfo *s; + + s = FROM_SYSBUS(StrongARMPPCInfo, dev); + + qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22); + qdev_init_gpio_out(&dev->qdev, s->handler, 22); + + iomemtype = cpu_register_io_memory(strongarm_ppc_readfn, + strongarm_ppc_writefn, s, DEVICE_NATIVE_ENDIAN); + + sysbus_init_mmio(dev, 0x1000, iomemtype); + + return 0; +} + +static const VMStateDescription vmstate_strongarm_ppc_regs = { + .name = "strongarm-ppc", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ilevel, StrongARMPPCInfo), + VMSTATE_UINT32(olevel, StrongARMPPCInfo), + VMSTATE_UINT32(dir, StrongARMPPCInfo), + VMSTATE_UINT32(ppar, StrongARMPPCInfo), + VMSTATE_UINT32(psdr, StrongARMPPCInfo), + VMSTATE_UINT32(ppfr, StrongARMPPCInfo), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_ppc_info = { + .init = strongarm_ppc_init, + .qdev.name = "strongarm-ppc", + .qdev.desc = "StrongARM PPC controller", + .qdev.size = sizeof(StrongARMPPCInfo), +}; + +/* UART Ports */ +#define UTCR0 0x00 +#define UTCR1 0x04 +#define UTCR2 0x08 +#define UTCR3 0x0c +#define UTDR 0x14 +#define UTSR0 0x1c +#define UTSR1 0x20 + +#define UTCR0_PE (1 << 0) /* Parity enable */ +#define UTCR0_OES (1 << 1) /* Even parity */ +#define UTCR0_SBS (1 << 2) /* 2 stop bits */ +#define UTCR0_DSS (1 << 3) /* 8-bit data */ + +#define UTCR3_RXE (1 << 0) /* Rx enable */ +#define UTCR3_TXE (1 << 1) /* Tx enable */ +#define UTCR3_BRK (1 << 2) /* Force Break */ +#define UTCR3_RIE (1 << 3) /* Rx int enable */ +#define UTCR3_TIE (1 << 4) /* Tx int enable */ +#define UTCR3_LBM (1 << 5) /* Loopback */ + +#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */ +#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */ +#define UTSR0_RID (1 << 2) /* Receiver Idle */ +#define UTSR0_RBB (1 << 3) /* Receiver begin break */ +#define UTSR0_REB (1 << 4) /* Receiver end break */ +#define UTSR0_EIF (1 << 5) /* Error in FIFO */ + +#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */ +#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */ +#define UTSR1_PRE (1 << 3) /* Parity error */ +#define UTSR1_FRE (1 << 4) /* Frame error */ +#define UTSR1_ROR (1 << 5) /* Receive Over Run */ + +#define RX_FIFO_PRE (1 << 8) +#define RX_FIFO_FRE (1 << 9) +#define RX_FIFO_ROR (1 << 10) + +typedef struct { + SysBusDevice busdev; + CharDriverState *chr; + qemu_irq irq; + + uint8_t utcr0; + uint16_t brd; + uint8_t utcr3; + uint8_t utsr0; + uint8_t utsr1; + + uint8_t tx_fifo[8]; + uint8_t tx_start; + uint8_t tx_len; + uint16_t rx_fifo[12]; /* value + error flags in high bits */ + uint8_t rx_start; + uint8_t rx_len; + + uint64_t char_transmit_time; /* time to transmit a char in ticks*/ + bool wait_break_end; + QEMUTimer *rx_timeout_timer; + QEMUTimer *tx_timer; +} StrongARMUARTState; + +static void strongarm_uart_update_status(StrongARMUARTState *s) +{ + uint16_t utsr1 = 0; + + if (s->tx_len != 8) { + utsr1 |= UTSR1_TNF; + } + + if (s->rx_len != 0) { + uint16_t ent = s->rx_fifo[s->rx_start]; + + utsr1 |= UTSR1_RNE; + if (ent & RX_FIFO_PRE) { + s->utsr1 |= UTSR1_PRE; + } + if (ent & RX_FIFO_FRE) { + s->utsr1 |= UTSR1_FRE; + } + if (ent & RX_FIFO_ROR) { + s->utsr1 |= UTSR1_ROR; + } + } + + s->utsr1 = utsr1; +} + +static void strongarm_uart_update_int_status(StrongARMUARTState *s) +{ + uint16_t utsr0 = s->utsr0 & + (UTSR0_REB | UTSR0_RBB | UTSR0_RID); + int i; + + if ((s->utcr3 & UTCR3_TXE) && + (s->utcr3 & UTCR3_TIE) && + s->tx_len <= 4) { + utsr0 |= UTSR0_TFS; + } + + if ((s->utcr3 & UTCR3_RXE) && + (s->utcr3 & UTCR3_RIE) && + s->rx_len > 4) { + utsr0 |= UTSR0_RFS; + } + + for (i = 0; i < s->rx_len && i < 4; i++) + if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) { + utsr0 |= UTSR0_EIF; + break; + } + + s->utsr0 = utsr0; + qemu_set_irq(s->irq, utsr0); +} + +static void strongarm_uart_update_parameters(StrongARMUARTState *s) +{ + int speed, parity, data_bits, stop_bits, frame_size; + QEMUSerialSetParams ssp; + + /* Start bit. */ + frame_size = 1; + if (s->utcr0 & UTCR0_PE) { + /* Parity bit. */ + frame_size++; + if (s->utcr0 & UTCR0_OES) { + parity = 'E'; + } else { + parity = 'O'; + } + } else { + parity = 'N'; + } + if (s->utcr0 & UTCR0_SBS) { + stop_bits = 2; + } else { + stop_bits = 1; + } + + data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7; + frame_size += data_bits + stop_bits; + speed = 3686400 / 16 / (s->brd + 1); + ssp.speed = speed; + ssp.parity = parity; + ssp.data_bits = data_bits; + ssp.stop_bits = stop_bits; + s->char_transmit_time = (get_ticks_per_sec() / speed) * frame_size; + if (s->chr) { + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); + } + + DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label, + speed, parity, data_bits, stop_bits); +} + +static void strongarm_uart_rx_to(void *opaque) +{ + StrongARMUARTState *s = opaque; + + if (s->rx_len) { + s->utsr0 |= UTSR0_RID; + strongarm_uart_update_int_status(s); + } +} + +static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c) +{ + if ((s->utcr3 & UTCR3_RXE) == 0) { + /* rx disabled */ + return; + } + + if (s->wait_break_end) { + s->utsr0 |= UTSR0_REB; + s->wait_break_end = false; + } + + if (s->rx_len < 12) { + s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c; + s->rx_len++; + } else + s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR; +} + +static int strongarm_uart_can_receive(void *opaque) +{ + StrongARMUARTState *s = opaque; + + if (s->rx_len == 12) { + return 0; + } + /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */ + if (s->rx_len < 8) { + return 8 - s->rx_len; + } + return 1; +} + +static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + StrongARMUARTState *s = opaque; + int i; + + for (i = 0; i < size; i++) { + strongarm_uart_rx_push(s, buf[i]); + } + + /* call the timeout receive callback in 3 char transmit time */ + qemu_mod_timer(s->rx_timeout_timer, + qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3); + + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); +} + +static void strongarm_uart_event(void *opaque, int event) +{ + StrongARMUARTState *s = opaque; + if (event == CHR_EVENT_BREAK) { + s->utsr0 |= UTSR0_RBB; + strongarm_uart_rx_push(s, RX_FIFO_FRE); + s->wait_break_end = true; + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + } +} + +static void strongarm_uart_tx(void *opaque) +{ + StrongARMUARTState *s = opaque; + uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock); + + if (s->utcr3 & UTCR3_LBM) /* loopback */ { + strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1); + } else if (s->chr) { + qemu_chr_write(s->chr, &s->tx_fifo[s->tx_start], 1); + } + + s->tx_start = (s->tx_start + 1) % 8; + s->tx_len--; + if (s->tx_len) { + qemu_mod_timer(s->tx_timer, new_xmit_ts + s->char_transmit_time); + } + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); +} + +static uint32_t strongarm_uart_read(void *opaque, target_phys_addr_t addr) +{ + StrongARMUARTState *s = opaque; + uint16_t ret; + + switch (addr) { + case UTCR0: + return s->utcr0; + + case UTCR1: + return s->brd >> 8; + + case UTCR2: + return s->brd & 0xff; + + case UTCR3: + return s->utcr3; + + case UTDR: + if (s->rx_len != 0) { + ret = s->rx_fifo[s->rx_start]; + s->rx_start = (s->rx_start + 1) % 12; + s->rx_len--; + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + return ret; + } + return 0; + + case UTSR0: + return s->utsr0; + + case UTSR1: + return s->utsr1; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + return 0; + } +} + +static void strongarm_uart_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + StrongARMUARTState *s = opaque; + + switch (addr) { + case UTCR0: + s->utcr0 = value & 0x7f; + strongarm_uart_update_parameters(s); + break; + + case UTCR1: + s->brd = (s->brd & 0xff) | ((value & 0xf) << 8); + strongarm_uart_update_parameters(s); + break; + + case UTCR2: + s->brd = (s->brd & 0xf00) | (value & 0xff); + strongarm_uart_update_parameters(s); + break; + + case UTCR3: + s->utcr3 = value & 0x3f; + if ((s->utcr3 & UTCR3_RXE) == 0) { + s->rx_len = 0; + } + if ((s->utcr3 & UTCR3_TXE) == 0) { + s->tx_len = 0; + } + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + break; + + case UTDR: + if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) { + s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value; + s->tx_len++; + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + if (s->tx_len == 1) { + strongarm_uart_tx(s); + } + } + break; + + case UTSR0: + s->utsr0 = s->utsr0 & ~(value & + (UTSR0_REB | UTSR0_RBB | UTSR0_RID)); + strongarm_uart_update_int_status(s); + break; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + } +} + +static CPUReadMemoryFunc * const strongarm_uart_readfn[] = { + strongarm_uart_read, + strongarm_uart_read, + strongarm_uart_read, +}; + +static CPUWriteMemoryFunc * const strongarm_uart_writefn[] = { + strongarm_uart_write, + strongarm_uart_write, + strongarm_uart_write, +}; + +static int strongarm_uart_init(SysBusDevice *dev) +{ + StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); + int iomemtype; + + iomemtype = cpu_register_io_memory(strongarm_uart_readfn, + strongarm_uart_writefn, s, DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x10000, iomemtype); + sysbus_init_irq(dev, &s->irq); + + s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s); + s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s); + + if (s->chr) { + qemu_chr_add_handlers(s->chr, + strongarm_uart_can_receive, + strongarm_uart_receive, + strongarm_uart_event, + s); + } + + return 0; +} + +static void strongarm_uart_reset(DeviceState *dev) +{ + StrongARMUARTState *s = DO_UPCAST(StrongARMUARTState, busdev.qdev, dev); + + s->utcr0 = UTCR0_DSS; /* 8 data, no parity */ + s->brd = 23; /* 9600 */ + /* enable send & recv - this actually violates spec */ + s->utcr3 = UTCR3_TXE | UTCR3_RXE; + + s->rx_len = s->tx_len = 0; + + strongarm_uart_update_parameters(s); + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); +} + +static int strongarm_uart_post_load(void *opaque, int version_id) +{ + StrongARMUARTState *s = opaque; + + strongarm_uart_update_parameters(s); + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + + /* tx and restart timer */ + if (s->tx_len) { + strongarm_uart_tx(s); + } + + /* restart rx timeout timer */ + if (s->rx_len) { + qemu_mod_timer(s->rx_timeout_timer, + qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3); + } + + return 0; +} + +static const VMStateDescription vmstate_strongarm_uart_regs = { + .name = "strongarm-uart", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = strongarm_uart_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(utcr0, StrongARMUARTState), + VMSTATE_UINT16(brd, StrongARMUARTState), + VMSTATE_UINT8(utcr3, StrongARMUARTState), + VMSTATE_UINT8(utsr0, StrongARMUARTState), + VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8), + VMSTATE_UINT8(tx_start, StrongARMUARTState), + VMSTATE_UINT8(tx_len, StrongARMUARTState), + VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12), + VMSTATE_UINT8(rx_start, StrongARMUARTState), + VMSTATE_UINT8(rx_len, StrongARMUARTState), + VMSTATE_BOOL(wait_break_end, StrongARMUARTState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_uart_info = { + .init = strongarm_uart_init, + .qdev.name = "strongarm-uart", + .qdev.desc = "StrongARM UART controller", + .qdev.size = sizeof(StrongARMUARTState), + .qdev.reset = strongarm_uart_reset, + .qdev.vmsd = &vmstate_strongarm_uart_regs, + .qdev.props = (Property[]) { + DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr), + DEFINE_PROP_END_OF_LIST(), + } +}; + +/* Synchronous Serial Ports */ +typedef struct { + SysBusDevice busdev; + qemu_irq irq; + SSIBus *bus; + + uint16_t sscr[2]; + uint16_t sssr; + + uint16_t rx_fifo[8]; + uint8_t rx_level; + uint8_t rx_start; +} StrongARMSSPState; + +#define SSCR0 0x60 /* SSP Control register 0 */ +#define SSCR1 0x64 /* SSP Control register 1 */ +#define SSDR 0x6c /* SSP Data register */ +#define SSSR 0x74 /* SSP Status register */ + +/* Bitfields for above registers */ +#define SSCR0_SPI(x) (((x) & 0x30) == 0x00) +#define SSCR0_SSP(x) (((x) & 0x30) == 0x10) +#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20) +#define SSCR0_PSP(x) (((x) & 0x30) == 0x30) +#define SSCR0_SSE (1 << 7) +#define SSCR0_DSS(x) (((x) & 0xf) + 1) +#define SSCR1_RIE (1 << 0) +#define SSCR1_TIE (1 << 1) +#define SSCR1_LBM (1 << 2) +#define SSSR_TNF (1 << 2) +#define SSSR_RNE (1 << 3) +#define SSSR_TFS (1 << 5) +#define SSSR_RFS (1 << 6) +#define SSSR_ROR (1 << 7) +#define SSSR_RW 0x0080 + +static void strongarm_ssp_int_update(StrongARMSSPState *s) +{ + int level = 0; + + level |= (s->sssr & SSSR_ROR); + level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE); + level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE); + qemu_set_irq(s->irq, level); +} + +static void strongarm_ssp_fifo_update(StrongARMSSPState *s) +{ + s->sssr &= ~SSSR_TFS; + s->sssr &= ~SSSR_TNF; + if (s->sscr[0] & SSCR0_SSE) { + if (s->rx_level >= 4) { + s->sssr |= SSSR_RFS; + } else { + s->sssr &= ~SSSR_RFS; + } + if (s->rx_level) { + s->sssr |= SSSR_RNE; + } else { + s->sssr &= ~SSSR_RNE; + } + /* TX FIFO is never filled, so it is always in underrun + condition if SSP is enabled */ + s->sssr |= SSSR_TFS; + s->sssr |= SSSR_TNF; + } + + strongarm_ssp_int_update(s); +} + +static uint32_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr) +{ + StrongARMSSPState *s = opaque; + uint32_t retval; + + switch (addr) { + case SSCR0: + return s->sscr[0]; + case SSCR1: + return s->sscr[1]; + case SSSR: + return s->sssr; + case SSDR: + if (~s->sscr[0] & SSCR0_SSE) { + return 0xffffffff; + } + if (s->rx_level < 1) { + printf("%s: SSP Rx Underrun\n", __func__); + return 0xffffffff; + } + s->rx_level--; + retval = s->rx_fifo[s->rx_start++]; + s->rx_start &= 0x7; + strongarm_ssp_fifo_update(s); + return retval; + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + break; + } + return 0; +} + +static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + StrongARMSSPState *s = opaque; + + switch (addr) { + case SSCR0: + s->sscr[0] = value & 0xffbf; + if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) { + printf("%s: Wrong data size: %i bits\n", __func__, + SSCR0_DSS(value)); + } + if (!(value & SSCR0_SSE)) { + s->sssr = 0; + s->rx_level = 0; + } + strongarm_ssp_fifo_update(s); + break; + + case SSCR1: + s->sscr[1] = value & 0x2f; + if (value & SSCR1_LBM) { + printf("%s: Attempt to use SSP LBM mode\n", __func__); + } + strongarm_ssp_fifo_update(s); + break; + + case SSSR: + s->sssr &= ~(value & SSSR_RW); + strongarm_ssp_int_update(s); + break; + + case SSDR: + if (SSCR0_UWIRE(s->sscr[0])) { + value &= 0xff; + } else + /* Note how 32bits overflow does no harm here */ + value &= (1 << SSCR0_DSS(s->sscr[0])) - 1; + + /* Data goes from here to the Tx FIFO and is shifted out from + * there directly to the slave, no need to buffer it. + */ + if (s->sscr[0] & SSCR0_SSE) { + uint32_t readval; + if (s->sscr[1] & SSCR1_LBM) { + readval = value; + } else { + readval = ssi_transfer(s->bus, value); + } + + if (s->rx_level < 0x08) { + s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval; + } else { + s->sssr |= SSSR_ROR; + } + } + strongarm_ssp_fifo_update(s); + break; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + break; + } +} + +static CPUReadMemoryFunc * const strongarm_ssp_readfn[] = { + strongarm_ssp_read, + strongarm_ssp_read, + strongarm_ssp_read, +}; + +static CPUWriteMemoryFunc * const strongarm_ssp_writefn[] = { + strongarm_ssp_write, + strongarm_ssp_write, + strongarm_ssp_write, +}; + +static int strongarm_ssp_post_load(void *opaque, int version_id) +{ + StrongARMSSPState *s = opaque; + + strongarm_ssp_fifo_update(s); + + return 0; +} + +static int strongarm_ssp_init(SysBusDevice *dev) +{ + int iomemtype; + StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev); + + sysbus_init_irq(dev, &s->irq); + + iomemtype = cpu_register_io_memory(strongarm_ssp_readfn, + strongarm_ssp_writefn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x1000, iomemtype); + + s->bus = ssi_create_bus(&dev->qdev, "ssi"); + return 0; +} + +static void strongarm_ssp_reset(DeviceState *dev) +{ + StrongARMSSPState *s = DO_UPCAST(StrongARMSSPState, busdev.qdev, dev); + s->sssr = 0x03; /* 3 bit data, SPI, disabled */ + s->rx_start = 0; + s->rx_level = 0; +} + +static const VMStateDescription vmstate_strongarm_ssp_regs = { + .name = "strongarm-ssp", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = strongarm_ssp_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2), + VMSTATE_UINT16(sssr, StrongARMSSPState), + VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8), + VMSTATE_UINT8(rx_start, StrongARMSSPState), + VMSTATE_UINT8(rx_level, StrongARMSSPState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_ssp_info = { + .init = strongarm_ssp_init, + .qdev.name = "strongarm-ssp", + .qdev.desc = "StrongARM SSP controller", + .qdev.size = sizeof(StrongARMSSPState), + .qdev.reset = strongarm_ssp_reset, + .qdev.vmsd = &vmstate_strongarm_ssp_regs, +}; + +/* Main CPU functions */ +StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev) +{ + StrongARMState *s; + qemu_irq *pic; + int i; + + s = qemu_mallocz(sizeof(StrongARMState)); + + if (!rev) { + rev = "sa1110-b5"; + } + + if (strncmp(rev, "sa1110", 6)) { + error_report("Machine requires a SA1110 processor.\n"); + exit(1); + } + + s->env = cpu_init(rev); + + if (!s->env) { + error_report("Unable to find CPU definition\n"); + exit(1); + } + + cpu_register_physical_memory(SA_SDCS0, + sdram_size, qemu_ram_alloc(NULL, "strongarm.sdram", + sdram_size) | IO_MEM_RAM); + + pic = arm_pic_init_cpu(s->env); + s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, + pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL); + + sysbus_create_varargs("pxa25x-timer", 0x90000000, + qdev_get_gpio_in(s->pic, SA_PIC_OSTC0), + qdev_get_gpio_in(s->pic, SA_PIC_OSTC1), + qdev_get_gpio_in(s->pic, SA_PIC_OSTC2), + qdev_get_gpio_in(s->pic, SA_PIC_OSTC3), + NULL); + + sysbus_create_simple("strongarm-rtc", 0x90010000, + qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM)); + + s->gpio = strongarm_gpio_init(0x90040000, s->pic); + + s->ppc = sysbus_create_varargs("strongarm-ppc", 0x90060000, NULL); + + for (i = 0; sa_serial[i].io_base; i++) { + DeviceState *dev = qdev_create(NULL, "strongarm-uart"); + qdev_prop_set_chr(dev, "chardev", serial_hds[i]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, + sa_serial[i].io_base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, + qdev_get_gpio_in(s->pic, sa_serial[i].irq)); + } + + s->ssp = sysbus_create_varargs("strongarm-ssp", 0x80070000, + qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL); + s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi"); + + return s; +} + +static void strongarm_register_devices(void) +{ + sysbus_register_withprop(&strongarm_pic_info); + sysbus_register_withprop(&strongarm_rtc_sysbus_info); + sysbus_register_withprop(&strongarm_gpio_info); + sysbus_register_withprop(&strongarm_ppc_info); + sysbus_register_withprop(&strongarm_uart_info); + sysbus_register_withprop(&strongarm_ssp_info); +} +device_init(strongarm_register_devices) diff --git a/hw/strongarm.h b/hw/strongarm.h new file mode 100644 index 0000000..a81b110 --- /dev/null +++ b/hw/strongarm.h @@ -0,0 +1,64 @@ +#ifndef _STRONGARM_H +#define _STRONGARM_H + +#define SA_CS0 0x00000000 +#define SA_CS1 0x08000000 +#define SA_CS2 0x10000000 +#define SA_CS3 0x18000000 +#define SA_PCMCIA_CS0 0x20000000 +#define SA_PCMCIA_CS1 0x30000000 +#define SA_CS4 0x40000000 +#define SA_CS5 0x48000000 +/* system registers here */ +#define SA_SDCS0 0xc0000000 +#define SA_SDCS1 0xc8000000 +#define SA_SDCS2 0xd0000000 +#define SA_SDCS3 0xd8000000 + +enum { + SA_PIC_GPIO0_EDGE = 0, + SA_PIC_GPIO1_EDGE, + SA_PIC_GPIO2_EDGE, + SA_PIC_GPIO3_EDGE, + SA_PIC_GPIO4_EDGE, + SA_PIC_GPIO5_EDGE, + SA_PIC_GPIO6_EDGE, + SA_PIC_GPIO7_EDGE, + SA_PIC_GPIO8_EDGE, + SA_PIC_GPIO9_EDGE, + SA_PIC_GPIO10_EDGE, + SA_PIC_GPIOX_EDGE, + SA_PIC_LCD, + SA_PIC_UDC, + SA_PIC_RSVD1, + SA_PIC_UART1, + SA_PIC_UART2, + SA_PIC_UART3, + SA_PIC_MCP, + SA_PIC_SSP, + SA_PIC_DMA_CH0, + SA_PIC_DMA_CH1, + SA_PIC_DMA_CH2, + SA_PIC_DMA_CH3, + SA_PIC_DMA_CH4, + SA_PIC_DMA_CH5, + SA_PIC_OSTC0, + SA_PIC_OSTC1, + SA_PIC_OSTC2, + SA_PIC_OSTC3, + SA_PIC_RTC_HZ, + SA_PIC_RTC_ALARM, +}; + +typedef struct { + CPUState *env; + DeviceState *pic; + DeviceState *gpio; + DeviceState *ppc; + DeviceState *ssp; + SSIBus *ssp_bus; +} StrongARMState; + +StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev); + +#endif diff --git a/hw/syborg.c b/hw/syborg.c index 758c69a..bc200e4 100644 --- a/hw/syborg.c +++ b/hw/syborg.c @@ -25,7 +25,6 @@ #include "sysbus.h" #include "boards.h" #include "arm-misc.h" -#include "sysemu.h" #include "net.h" static struct arm_boot_info syborg_binfo; diff --git a/hw/syborg_keyboard.c b/hw/syborg_keyboard.c index d295e99..706a039 100644 --- a/hw/syborg_keyboard.c +++ b/hw/syborg_keyboard.c @@ -51,11 +51,11 @@ enum { typedef struct { SysBusDevice busdev; - int int_enabled; + uint32_t int_enabled; int extension_bit; uint32_t fifo_size; uint32_t *key_fifo; - int read_pos, read_count; + uint32_t read_pos, read_count; qemu_irq irq; } SyborgKeyboardState; @@ -165,43 +165,21 @@ static void syborg_keyboard_event(void *opaque, int keycode) syborg_keyboard_update(s); } -static void syborg_keyboard_save(QEMUFile *f, void *opaque) -{ - SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; - int i; - - qemu_put_be32(f, s->fifo_size); - qemu_put_be32(f, s->int_enabled); - qemu_put_be32(f, s->extension_bit); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - for (i = 0; i < s->fifo_size; i++) { - qemu_put_be32(f, s->key_fifo[i]); - } -} - -static int syborg_keyboard_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; - uint32_t val; - int i; - - if (version_id != 1) - return -EINVAL; - - val = qemu_get_be32(f); - if (val != s->fifo_size) - return -EINVAL; - - s->int_enabled = qemu_get_be32(f); - s->extension_bit = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - for (i = 0; i < s->fifo_size; i++) { - s->key_fifo[i] = qemu_get_be32(f); +static const VMStateDescription vmstate_syborg_keyboard = { + .name = "syborg_keyboard", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_EQUAL(fifo_size, SyborgKeyboardState), + VMSTATE_UINT32(int_enabled, SyborgKeyboardState), + VMSTATE_UINT32(read_pos, SyborgKeyboardState), + VMSTATE_UINT32(read_count, SyborgKeyboardState), + VMSTATE_VARRAY_UINT32(key_fifo, SyborgKeyboardState, fifo_size, 1, + vmstate_info_uint32, uint32), + VMSTATE_END_OF_LIST() } - return 0; -} +}; static int syborg_keyboard_init(SysBusDevice *dev) { @@ -221,8 +199,7 @@ static int syborg_keyboard_init(SysBusDevice *dev) qemu_add_kbd_event_handler(syborg_keyboard_event, s); - register_savevm(&dev->qdev, "syborg_keyboard", -1, 1, - syborg_keyboard_save, syborg_keyboard_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_keyboard, s); return 0; } diff --git a/hw/syborg_pointer.c b/hw/syborg_pointer.c index a886888..2f99707 100644 --- a/hw/syborg_pointer.c +++ b/hw/syborg_pointer.c @@ -152,52 +152,36 @@ static void syborg_pointer_event(void *opaque, int dx, int dy, int dz, syborg_pointer_update(s); } -static void syborg_pointer_save(QEMUFile *f, void *opaque) -{ - SyborgPointerState *s = (SyborgPointerState *)opaque; - int i; - - qemu_put_be32(f, s->fifo_size); - qemu_put_be32(f, s->absolute); - qemu_put_be32(f, s->int_enabled); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - for (i = 0; i < s->fifo_size; i++) { - qemu_put_be32(f, s->event_fifo[i].x); - qemu_put_be32(f, s->event_fifo[i].y); - qemu_put_be32(f, s->event_fifo[i].z); - qemu_put_be32(f, s->event_fifo[i].pointer_buttons); +static const VMStateDescription vmstate_event_data = { + .name = "dbma_channel", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_INT32(x, event_data), + VMSTATE_INT32(y, event_data), + VMSTATE_INT32(z, event_data), + VMSTATE_INT32(pointer_buttons, event_data), + VMSTATE_END_OF_LIST() } -} +}; -static int syborg_pointer_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgPointerState *s = (SyborgPointerState *)opaque; - uint32_t val; - int i; - - if (version_id != 1) - return -EINVAL; - - val = qemu_get_be32(f); - if (val != s->fifo_size) - return -EINVAL; - - val = qemu_get_be32(f); - if (val != s->absolute) - return -EINVAL; - - s->int_enabled = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - for (i = 0; i < s->fifo_size; i++) { - s->event_fifo[i].x = qemu_get_be32(f); - s->event_fifo[i].y = qemu_get_be32(f); - s->event_fifo[i].z = qemu_get_be32(f); - s->event_fifo[i].pointer_buttons = qemu_get_be32(f); +static const VMStateDescription vmstate_syborg_pointer = { + .name = "syborg_pointer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_EQUAL(fifo_size, SyborgPointerState), + VMSTATE_UINT32_EQUAL(absolute, SyborgPointerState), + VMSTATE_INT32(int_enabled, SyborgPointerState), + VMSTATE_INT32(read_pos, SyborgPointerState), + VMSTATE_INT32(read_count, SyborgPointerState), + VMSTATE_STRUCT_VARRAY_UINT32(event_fifo, SyborgPointerState, fifo_size, + 1, vmstate_event_data, event_data), + VMSTATE_END_OF_LIST() } - return 0; -} +}; static int syborg_pointer_init(SysBusDevice *dev) { @@ -219,8 +203,7 @@ static int syborg_pointer_init(SysBusDevice *dev) qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute, "Syborg Pointer"); - register_savevm(&dev->qdev, "syborg_pointer", -1, 1, - syborg_pointer_save, syborg_pointer_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_pointer, s); return 0; } diff --git a/hw/syborg_rtc.c b/hw/syborg_rtc.c index 16d8f9e..69f6ccf 100644 --- a/hw/syborg_rtc.c +++ b/hw/syborg_rtc.c @@ -102,26 +102,17 @@ static CPUWriteMemoryFunc * const syborg_rtc_writefn[] = { syborg_rtc_write }; -static void syborg_rtc_save(QEMUFile *f, void *opaque) -{ - SyborgRTCState *s = opaque; - - qemu_put_be64(f, s->offset); - qemu_put_be64(f, s->data); -} - -static int syborg_rtc_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgRTCState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - s->offset = qemu_get_be64(f); - s->data = qemu_get_be64(f); - - return 0; -} +static const VMStateDescription vmstate_syborg_rtc = { + .name = "syborg_keyboard", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(offset, SyborgRTCState), + VMSTATE_INT64(data, SyborgRTCState), + VMSTATE_END_OF_LIST() + } +}; static int syborg_rtc_init(SysBusDevice *dev) { @@ -137,8 +128,7 @@ static int syborg_rtc_init(SysBusDevice *dev) qemu_get_timedate(&tm, 0); s->offset = (uint64_t)mktime(&tm) * 1000000000; - register_savevm(&dev->qdev, "syborg_rtc", -1, 1, - syborg_rtc_save, syborg_rtc_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_rtc, s); return 0; } diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c index 34ce076..df2950f 100644 --- a/hw/syborg_serial.c +++ b/hw/syborg_serial.c @@ -273,47 +273,24 @@ static CPUWriteMemoryFunc * const syborg_serial_writefn[] = { syborg_serial_write }; -static void syborg_serial_save(QEMUFile *f, void *opaque) -{ - SyborgSerialState *s = opaque; - int i; - - qemu_put_be32(f, s->fifo_size); - qemu_put_be32(f, s->int_enable); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - qemu_put_be32(f, s->dma_tx_ptr); - qemu_put_be32(f, s->dma_rx_ptr); - qemu_put_be32(f, s->dma_rx_size); - for (i = 0; i < s->fifo_size; i++) { - qemu_put_be32(f, s->read_fifo[i]); - } -} - -static int syborg_serial_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgSerialState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - i = qemu_get_be32(f); - if (s->fifo_size != i) - return -EINVAL; - - s->int_enable = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - s->dma_tx_ptr = qemu_get_be32(f); - s->dma_rx_ptr = qemu_get_be32(f); - s->dma_rx_size = qemu_get_be32(f); - for (i = 0; i < s->fifo_size; i++) { - s->read_fifo[i] = qemu_get_be32(f); +static const VMStateDescription vmstate_syborg_serial = { + .name = "syborg_serial", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_EQUAL(fifo_size, SyborgSerialState), + VMSTATE_UINT32(int_enable, SyborgSerialState), + VMSTATE_INT32(read_pos, SyborgSerialState), + VMSTATE_INT32(read_count, SyborgSerialState), + VMSTATE_UINT32(dma_tx_ptr, SyborgSerialState), + VMSTATE_UINT32(dma_rx_ptr, SyborgSerialState), + VMSTATE_UINT32(dma_rx_size, SyborgSerialState), + VMSTATE_VARRAY_UINT32(read_fifo, SyborgSerialState, fifo_size, 1, + vmstate_info_uint32, uint32), + VMSTATE_END_OF_LIST() } - - return 0; -} +}; static int syborg_serial_init(SysBusDevice *dev) { @@ -336,8 +313,6 @@ static int syborg_serial_init(SysBusDevice *dev) } s->read_fifo = qemu_mallocz(s->fifo_size * sizeof(s->read_fifo[0])); - register_savevm(&dev->qdev, "syborg_serial", -1, 1, - syborg_serial_save, syborg_serial_load, s); return 0; } @@ -345,6 +320,7 @@ static SysBusDeviceInfo syborg_serial_info = { .init = syborg_serial_init, .qdev.name = "syborg,serial", .qdev.size = sizeof(SyborgSerialState), + .qdev.vmsd = &vmstate_syborg_serial, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("fifo-size", SyborgSerialState, fifo_size, 16), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/syborg_timer.c b/hw/syborg_timer.c index cedcd8e..50c813e 100644 --- a/hw/syborg_timer.c +++ b/hw/syborg_timer.c @@ -174,34 +174,21 @@ static CPUWriteMemoryFunc * const syborg_timer_writefn[] = { syborg_timer_write }; -static void syborg_timer_save(QEMUFile *f, void *opaque) -{ - SyborgTimerState *s = opaque; - - qemu_put_be32(f, s->running); - qemu_put_be32(f, s->oneshot); - qemu_put_be32(f, s->limit); - qemu_put_be32(f, s->int_level); - qemu_put_be32(f, s->int_enabled); - qemu_put_ptimer(f, s->timer); -} - -static int syborg_timer_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgTimerState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - s->running = qemu_get_be32(f); - s->oneshot = qemu_get_be32(f); - s->limit = qemu_get_be32(f); - s->int_level = qemu_get_be32(f); - s->int_enabled = qemu_get_be32(f); - qemu_get_ptimer(f, s->timer); - - return 0; -} +static const VMStateDescription vmstate_syborg_timer = { + .name = "syborg_timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(running, SyborgTimerState), + VMSTATE_INT32(oneshot, SyborgTimerState), + VMSTATE_UINT32(limit, SyborgTimerState), + VMSTATE_UINT32(int_level, SyborgTimerState), + VMSTATE_UINT32(int_enabled, SyborgTimerState), + VMSTATE_PTIMER(timer, SyborgTimerState), + VMSTATE_END_OF_LIST() + } +}; static int syborg_timer_init(SysBusDevice *dev) { @@ -222,8 +209,7 @@ static int syborg_timer_init(SysBusDevice *dev) bh = qemu_bh_new(syborg_timer_tick, s); s->timer = ptimer_init(bh); ptimer_set_freq(s->timer, s->freq); - register_savevm(&dev->qdev, "syborg_timer", -1, 1, - syborg_timer_save, syborg_timer_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_timer, s); return 0; } diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c index ee08c49..2f3e6da 100644 --- a/hw/syborg_virtio.c +++ b/hw/syborg_virtio.c @@ -26,7 +26,6 @@ #include "sysbus.h" #include "virtio.h" #include "virtio-net.h" -#include "sysemu.h" //#define DEBUG_SYBORG_VIRTIO diff --git a/hw/sysbus.c b/hw/sysbus.c index acad72a..2e22be7 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -18,7 +18,6 @@ */ #include "sysbus.h" -#include "sysemu.h" #include "monitor.h" static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); diff --git a/hw/tc58128.c b/hw/tc58128.c index 672a01c..61b99dd 100644 --- a/hw/tc58128.c +++ b/hw/tc58128.c @@ -1,6 +1,5 @@ #include "hw.h" #include "sh.h" -#include "sysemu.h" #include "loader.h" #define CE1 0x0100 @@ -11,7 +11,6 @@ #include "hw.h" #include "pxa.h" #include "arm-misc.h" -#include "sysemu.h" #include "devices.h" #include "sharpsl.h" #include "pcmcia.h" diff --git a/hw/twl92230.c b/hw/twl92230.c index 8e74acc..a75448f 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -22,7 +22,6 @@ #include "hw.h" #include "qemu-timer.h" #include "i2c.h" -#include "sysemu.h" #include "console.h" #define VERBOSE 1 diff --git a/hw/usb-hid.c b/hw/usb-hid.c index c25362c..89c293c 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -26,7 +26,7 @@ #include "console.h" #include "usb.h" #include "usb-desc.h" -#include "sysemu.h" +#include "qemu-timer.h" /* HID interface requests */ #define GET_REPORT 0xa101 diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 76f5b02..947fd3f 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -33,7 +33,7 @@ do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0) enum USBMSDMode { USB_MSDM_CBW, /* Command Block. */ - USB_MSDM_DATAOUT, /* Tranfer data to device. */ + USB_MSDM_DATAOUT, /* Transfer data to device. */ USB_MSDM_DATAIN, /* Transfer data from device. */ USB_MSDM_CSW /* Command Status. */ }; @@ -253,7 +253,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, usb_msd_copy_data(s); if (s->usb_len == 0) { /* Set s->packet to NULL before calling usb_packet_complete - because annother request may be issued before + because another request may be issued before usb_packet_complete returns. */ DPRINTF("Packet complete %p\n", p); s->packet = NULL; diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index d2b14f7..0ad4f55 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -427,7 +427,7 @@ static inline int get_dwords(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); + cpu_physical_memory_read(addr, buf, sizeof(*buf)); *buf = le32_to_cpu(*buf); } @@ -444,7 +444,7 @@ static inline int put_dwords(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint32_t tmp = cpu_to_le32(*buf); - cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); + cpu_physical_memory_write(addr, &tmp, sizeof(tmp)); } return 1; @@ -459,7 +459,7 @@ static inline int get_words(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); + cpu_physical_memory_read(addr, buf, sizeof(*buf)); *buf = le16_to_cpu(*buf); } @@ -476,7 +476,7 @@ static inline int put_words(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint16_t tmp = cpu_to_le16(*buf); - cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); + cpu_physical_memory_write(addr, &tmp, sizeof(tmp)); } return 1; @@ -504,8 +504,7 @@ static inline int ohci_read_iso_td(OHCIState *ohci, static inline int ohci_read_hcca(OHCIState *ohci, uint32_t addr, struct ohci_hcca *hcca) { - cpu_physical_memory_rw(addr + ohci->localmem_base, - (uint8_t *)hcca, sizeof(*hcca), 0); + cpu_physical_memory_read(addr + ohci->localmem_base, hcca, sizeof(*hcca)); return 1; } @@ -531,8 +530,7 @@ static inline int ohci_put_iso_td(OHCIState *ohci, static inline int ohci_put_hcca(OHCIState *ohci, uint32_t addr, struct ohci_hcca *hcca) { - cpu_physical_memory_rw(addr + ohci->localmem_base, - (uint8_t *)hcca, sizeof(*hcca), 1); + cpu_physical_memory_write(addr + ohci->localmem_base, hcca, sizeof(*hcca)); return 1; } diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 257baf8..70a8710 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -15,7 +15,6 @@ #include "qemu-common.h" #include "virtio.h" #include "pc.h" -#include "sysemu.h" #include "cpu.h" #include "monitor.h" #include "balloon.h" diff --git a/hw/virtio.c b/hw/virtio.c index 31bd9e3..6e8814c 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -16,7 +16,6 @@ #include "trace.h" #include "qemu-error.h" #include "virtio.h" -#include "sysemu.h" /* The alignment to use between consumer and producer parts of vring. * x86 pagesize again. */ diff --git a/hw/vmport.c b/hw/vmport.c index 19010e4..c8aefaa 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -24,7 +24,6 @@ #include "hw.h" #include "isa.h" #include "pc.h" -#include "sysemu.h" #include "kvm.h" #include "qdev.h" diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 818460d..ca8f826 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -156,12 +156,10 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address, typedef struct VT686PMState { PCIDevice dev; - uint16_t pmsts; - uint16_t pmen; - uint16_t pmcntrl; + ACPIPM1EVT pm1a; + ACPIPM1CNT pm1_cnt; APMState apm; - QEMUTimer *tmr_timer; - int64_t tmr_overflow_time; + ACPIPMTimer tmr; PMSMBus smb; uint32_t smb_io_base; } VT686PMState; @@ -174,54 +172,25 @@ typedef struct VT686MC97State { PCIDevice dev; } VT686MC97State; -#define RTC_EN (1 << 10) -#define PWRBTN_EN (1 << 8) -#define GBL_EN (1 << 5) -#define TMROF_EN (1 << 0) -#define SUS_EN (1 << 13) - -#define ACPI_ENABLE 0xf1 -#define ACPI_DISABLE 0xf0 - -static uint32_t get_pmtmr(VT686PMState *s) -{ - uint32_t d; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - return d & 0xffffff; -} - -static int get_pmsts(VT686PMState *s) -{ - int64_t d; - int pmsts; - pmsts = s->pmsts; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - if (d >= s->tmr_overflow_time) - s->pmsts |= TMROF_EN; - return pmsts; -} - static void pm_update_sci(VT686PMState *s) { int sci_level, pmsts; - int64_t expire_time; - pmsts = get_pmsts(s); - sci_level = (((pmsts & s->pmen) & - (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); + pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); + sci_level = (((pmsts & s->pm1a.en) & + (ACPI_BITMASK_RT_CLOCK_ENABLE | + ACPI_BITMASK_POWER_BUTTON_ENABLE | + ACPI_BITMASK_GLOBAL_LOCK_ENABLE | + ACPI_BITMASK_TIMER_ENABLE)) != 0); qemu_set_irq(s->dev.irq[0], sci_level); /* schedule a timer interruption if needed */ - if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { - expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), PM_TIMER_FREQUENCY); - qemu_mod_timer(s->tmr_timer, expire_time); - } else { - qemu_del_timer(s->tmr_timer); - } + acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } -static void pm_tmr_timer(void *opaque) +static void pm_tmr_timer(ACPIPMTimer *tmr) { - VT686PMState *s = opaque; + VT686PMState *s = container_of(tmr, VT686PMState, tmr); pm_update_sci(s); } @@ -232,39 +201,15 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) addr &= 0x0f; switch (addr) { case 0x00: - { - int64_t d; - int pmsts; - pmsts = get_pmsts(s); - if (pmsts & val & TMROF_EN) { - /* if TMRSTS is reset, then compute the new overflow time */ - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; - } - s->pmsts &= ~val; - pm_update_sci(s); - } + acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val); + pm_update_sci(s); break; case 0x02: - s->pmen = val; + s->pm1a.en = val; pm_update_sci(s); break; case 0x04: - { - int sus_typ; - s->pmcntrl = val & ~(SUS_EN); - if (val & SUS_EN) { - /* change suspend type */ - sus_typ = (val >> 10) & 3; - switch (sus_typ) { - case 0: /* soft power off */ - qemu_system_shutdown_request(); - break; - default: - break; - } - } - } + acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val); break; default: break; @@ -280,13 +225,13 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) addr &= 0x0f; switch (addr) { case 0x00: - val = get_pmsts(s); + val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); break; case 0x02: - val = s->pmen; + val = s->pm1a.en; break; case 0x04: - val = s->pmcntrl; + val = s->pm1_cnt.cnt; break; default: val = 0; @@ -310,7 +255,7 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) addr &= 0x0f; switch (addr) { case 0x08: - val = get_pmtmr(s); + val = acpi_pm_tmr_get(&s->tmr); break; default: val = 0; @@ -361,12 +306,12 @@ static const VMStateDescription vmstate_acpi = { .post_load = vmstate_acpi_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, VT686PMState), - VMSTATE_UINT16(pmsts, VT686PMState), - VMSTATE_UINT16(pmen, VT686PMState), - VMSTATE_UINT16(pmcntrl, VT686PMState), + VMSTATE_UINT16(pm1a.sts, VT686PMState), + VMSTATE_UINT16(pm1a.en, VT686PMState), + VMSTATE_UINT16(pm1_cnt.cnt, VT686PMState), VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(tmr_timer, VT686PMState), - VMSTATE_INT64(tmr_overflow_time, VT686PMState), + VMSTATE_TIMER(tmr.timer, VT686PMState), + VMSTATE_INT64(tmr.overflow_time, VT686PMState), VMSTATE_END_OF_LIST() } }; @@ -486,7 +431,8 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) apm_init(&s->apm, NULL, s); - s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s); + acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); + acpi_pm1_cnt_init(&s->pm1_cnt, NULL); pm_smbus_init(&s->dev.qdev, &s->smb); diff --git a/hw/xen_console.c b/hw/xen_console.c index d2261f4..c6c8163 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -33,7 +33,6 @@ #include <xenctrl.h> #include "hw.h" -#include "sysemu.h" #include "qemu-char.h" #include "xen_backend.h" diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index 371c562..4093587 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -1,7 +1,6 @@ #include <signal.h> #include "xen_backend.h" #include "xen_domainbuild.h" -#include "sysemu.h" #include "qemu-timer.h" #include "qemu-log.h" diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 77a34bf..0d7f73e 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -24,7 +24,6 @@ #include "hw.h" #include "pc.h" -#include "sysemu.h" #include "boards.h" #include "xen_backend.h" #include "xen_domainbuild.h" @@ -44,7 +44,6 @@ #include <xen/io/protocols.h> #include "hw.h" -#include "sysemu.h" #include "console.h" #include "qemu-char.h" #include "xen_backend.h" diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index 30827b0..d398c18 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -23,7 +23,6 @@ */ #include "sysbus.h" -#include "sysemu.h" #include "qemu-timer.h" #define D(x) @@ -161,15 +161,15 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) if (mouse_event) { if (graphic_rotate) { - if (entry->qemu_put_mouse_event_absolute) + if (entry->qemu_put_mouse_event_absolute) { width = 0x7fff; - else + } else { width = graphic_width - 1; - mouse_event(mouse_event_opaque, - width - dy, dx, dz, buttons_state); - } else - mouse_event(mouse_event_opaque, - dx, dy, dz, buttons_state); + } + mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state); + } else { + mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); + } } } diff --git a/json-lexer.c b/json-lexer.c index c736f42..65c9720 100644 --- a/json-lexer.c +++ b/json-lexer.c @@ -28,7 +28,7 @@ */ enum json_lexer_state { - ERROR = 0, + IN_ERROR = 0, IN_DQ_UCODE3, IN_DQ_UCODE2, IN_DQ_UCODE1, @@ -150,7 +150,7 @@ static const uint8_t json_lexer[][256] = { /* Zero */ [IN_ZERO] = { TERMINAL(JSON_INTEGER), - ['0' ... '9'] = ERROR, + ['0' ... '9'] = IN_ERROR, ['.'] = IN_MANTISSA, }, @@ -302,7 +302,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch) lexer->token = qstring_new(); new_state = IN_START; break; - case ERROR: + case IN_ERROR: return -EINVAL; default: break; @@ -11,7 +11,6 @@ */ #include "qemu-common.h" -#include "sysemu.h" #include "hw/hw.h" #include "exec-all.h" #include "gdbstub.h" diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 71f2ba3..baada52 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -955,7 +955,7 @@ count_tokens(const char *str, char token, char token_end) static const char * strip(const char *str) { - for (; *str && !isspace(*str); str++) { + for (; *str && isspace(*str); str++) { } return str; } @@ -963,7 +963,7 @@ strip(const char *str) static const char * find_blank(const char *str) { - for (; *str && isspace(*str); str++) { + for (; *str && !isspace(*str); str++) { } return str; } diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c index be54e95..8011897 100644 --- a/linux-user/arm/nwfpe/fpa11_cprt.c +++ b/linux-user/arm/nwfpe/fpa11_cprt.c @@ -159,7 +159,7 @@ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) } /* test for equal condition */ - if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) + if (floatx80_eq_quiet(Fn,Fm, &fpa11->fp_status)) { flags |= CC_ZERO; } diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fe5410e..4c399f8 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -339,6 +339,80 @@ enum #endif +#ifdef TARGET_UNICORE32 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ((x) == EM_UNICORE32) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_UNICORE32 + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + regs->UC32_REG_asr = 0x10; + regs->UC32_REG_pc = infop->entry & 0xfffffffe; + regs->UC32_REG_sp = infop->start_stack; + /* FIXME - what to for failure of get_user()? */ + get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */ + get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */ + /* XXX: it seems that r0 is zeroed after ! */ + regs->UC32_REG_00 = 0; +} + +#define ELF_NREG 34 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) +{ + (*regs)[0] = env->regs[0]; + (*regs)[1] = env->regs[1]; + (*regs)[2] = env->regs[2]; + (*regs)[3] = env->regs[3]; + (*regs)[4] = env->regs[4]; + (*regs)[5] = env->regs[5]; + (*regs)[6] = env->regs[6]; + (*regs)[7] = env->regs[7]; + (*regs)[8] = env->regs[8]; + (*regs)[9] = env->regs[9]; + (*regs)[10] = env->regs[10]; + (*regs)[11] = env->regs[11]; + (*regs)[12] = env->regs[12]; + (*regs)[13] = env->regs[13]; + (*regs)[14] = env->regs[14]; + (*regs)[15] = env->regs[15]; + (*regs)[16] = env->regs[16]; + (*regs)[17] = env->regs[17]; + (*regs)[18] = env->regs[18]; + (*regs)[19] = env->regs[19]; + (*regs)[20] = env->regs[20]; + (*regs)[21] = env->regs[21]; + (*regs)[22] = env->regs[22]; + (*regs)[23] = env->regs[23]; + (*regs)[24] = env->regs[24]; + (*regs)[25] = env->regs[25]; + (*regs)[26] = env->regs[26]; + (*regs)[27] = env->regs[27]; + (*regs)[28] = env->regs[28]; + (*regs)[29] = env->regs[29]; + (*regs)[30] = env->regs[30]; + (*regs)[31] = env->regs[31]; + + (*regs)[32] = cpu_asr_read((CPUState *)env); + (*regs)[33] = env->regs[0]; /* XXX */ +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_HWCAP (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64) + +#endif + #ifdef TARGET_SPARC #ifdef TARGET_SPARC64 diff --git a/linux-user/main.c b/linux-user/main.c index e651bfd..a1e37e4 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -816,6 +816,83 @@ void cpu_loop(CPUARMState *env) #endif +#ifdef TARGET_UNICORE32 + +void cpu_loop(CPUState *env) +{ + int trapnr; + unsigned int n, insn; + target_siginfo_t info; + + for (;;) { + cpu_exec_start(env); + trapnr = uc32_cpu_exec(env); + cpu_exec_end(env); + switch (trapnr) { + case UC32_EXCP_PRIV: + { + /* system call */ + get_user_u32(insn, env->regs[31] - 4); + n = insn & 0xffffff; + + if (n >= UC32_SYSCALL_BASE) { + /* linux syscall */ + n -= UC32_SYSCALL_BASE; + if (n == UC32_SYSCALL_NR_set_tls) { + cpu_set_tls(env, env->regs[0]); + env->regs[0] = 0; + } else { + env->regs[0] = do_syscall(env, + n, + env->regs[0], + env->regs[1], + env->regs[2], + env->regs[3], + env->regs[4], + env->regs[5]); + } + } else { + goto error; + } + } + break; + case UC32_EXCP_TRAP: + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->cp0.c4_faultaddr; + queue_signal(env, info.si_signo, &info); + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, info.si_signo, &info); + } + } + break; + default: + goto error; + } + process_pending_signals(env); + } + +error: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); +} +#endif + #ifdef TARGET_SPARC #define SPARC64_STACK_BIAS 2047 @@ -2258,7 +2335,7 @@ void cpu_loop (CPUState *env) break; default: printf ("Unhandled hw-exception: 0x%x\n", - env->sregs[SR_ESR] & 5); + env->sregs[SR_ESR] & ESR_EC_MASK); cpu_dump_state(env, stderr, fprintf, 0); exit (1); break; @@ -2925,6 +3002,8 @@ int main(int argc, char **argv, char **envp) #endif #elif defined(TARGET_ARM) cpu_model = "any"; +#elif defined(TARGET_UNICORE32) + cpu_model = "any"; #elif defined(TARGET_M68K) cpu_model = "any"; #elif defined(TARGET_SPARC) @@ -3227,6 +3306,14 @@ int main(int argc, char **argv, char **envp) env->regs[i] = regs->uregs[i]; } } +#elif defined(TARGET_UNICORE32) + { + int i; + cpu_asr_write(env, regs->uregs[32], 0xffffffff); + for (i = 0; i < 32; i++) { + env->regs[i] = regs->uregs[i]; + } + } #elif defined(TARGET_SPARC) { int i; @@ -3367,7 +3454,7 @@ int main(int argc, char **argv, char **envp) #error unsupported target CPU #endif -#if defined(TARGET_ARM) || defined(TARGET_M68K) +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) ts->stack_base = info->start_stack; ts->heap_base = info->brk; /* This will be filled in on the first SYS_HEAPINFO call. */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 250814d..f522f5e 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -105,6 +105,9 @@ typedef struct TaskState { FPA11 fpa; int swi_errno; #endif +#ifdef TARGET_UNICORE32 + int swi_errno; +#endif #if defined(TARGET_I386) && !defined(TARGET_X86_64) abi_ulong target_v86; struct vm86_saved_state vm86_saved_regs; @@ -118,7 +121,7 @@ typedef struct TaskState { #ifdef TARGET_M68K int sim_syscalls; #endif -#if defined(TARGET_ARM) || defined(TARGET_M68K) +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) /* Extra fields for semihosted binaries. */ uint32_t stack_base; uint32_t heap_base; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 702652c..bde8921 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -55,7 +55,7 @@ #endif #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ - || defined(TARGET_M68K) || defined(TARGET_CRIS) + || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -315,7 +315,10 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ + || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined(TARGET_SH4) \ + || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \ + || defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -1002,7 +1005,8 @@ struct target_winsize { #define TARGET_MAP_UNINITIALIZED 0x4000000 /* for anonymous mmap, memory could be uninitialized */ #endif -#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_CRIS) +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) \ + || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) struct target_stat { unsigned short st_dev; unsigned short __pad1; diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h new file mode 100644 index 0000000..010cdd8 --- /dev/null +++ b/linux-user/unicore32/syscall.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __UC32_SYSCALL_H__ +#define __UC32_SYSCALL_H__ +struct target_pt_regs { + abi_ulong uregs[34]; +}; + +#define UC32_REG_pc uregs[31] +#define UC32_REG_lr uregs[30] +#define UC32_REG_sp uregs[29] +#define UC32_REG_ip uregs[28] +#define UC32_REG_fp uregs[27] +#define UC32_REG_26 uregs[26] +#define UC32_REG_25 uregs[25] +#define UC32_REG_24 uregs[24] +#define UC32_REG_23 uregs[23] +#define UC32_REG_22 uregs[22] +#define UC32_REG_21 uregs[21] +#define UC32_REG_20 uregs[20] +#define UC32_REG_19 uregs[19] +#define UC32_REG_18 uregs[18] +#define UC32_REG_17 uregs[17] +#define UC32_REG_16 uregs[16] +#define UC32_REG_15 uregs[15] +#define UC32_REG_14 uregs[14] +#define UC32_REG_13 uregs[13] +#define UC32_REG_12 uregs[12] +#define UC32_REG_11 uregs[11] +#define UC32_REG_10 uregs[10] +#define UC32_REG_09 uregs[9] +#define UC32_REG_08 uregs[8] +#define UC32_REG_07 uregs[7] +#define UC32_REG_06 uregs[6] +#define UC32_REG_05 uregs[5] +#define UC32_REG_04 uregs[4] +#define UC32_REG_03 uregs[3] +#define UC32_REG_02 uregs[2] +#define UC32_REG_01 uregs[1] +#define UC32_REG_00 uregs[0] +#define UC32_REG_asr uregs[32] +#define UC32_REG_ORIG_00 uregs[33] + +#define UC32_SYSCALL_BASE 0x900000 +#define UC32_SYSCALL_ARCH_BASE 0xf0000 +#define UC32_SYSCALL_NR_set_tls (UC32_SYSCALL_ARCH_BASE + 5) + +#define UNAME_MACHINE "UniCore-II" + +#endif /* __UC32_SYSCALL_H__ */ diff --git a/linux-user/unicore32/syscall_nr.h b/linux-user/unicore32/syscall_nr.h new file mode 100644 index 0000000..9c72d84 --- /dev/null +++ b/linux-user/unicore32/syscall_nr.h @@ -0,0 +1,371 @@ +/* + * This file contains the system call numbers for UniCore32 oldabi. + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 + /* 18 */ +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 + /* 28 */ +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 + /* 59 */ +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 + /* 84 */ +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 + /* 109 */ + /* 110 */ +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_syscall 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread 180 +#define TARGET_NR_pwrite 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 + /* 188 */ + /* 189 */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_getdents64 217 +#define TARGET_NR_pivot_root 218 +#define TARGET_NR_mincore 219 +#define TARGET_NR_madvise 220 +#define TARGET_NR_fcntl64 221 + /* 222 */ + /* 223 */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_io_setup 243 +#define TARGET_NR_io_destroy 244 +#define TARGET_NR_io_getevents 245 +#define TARGET_NR_io_submit 246 +#define TARGET_NR_io_cancel 247 +#define TARGET_NR_exit_group 248 +#define TARGET_NR_lookup_dcookie 249 +#define TARGET_NR_epoll_create 250 +#define TARGET_NR_epoll_ctl 251 +#define TARGET_NR_epoll_wait 252 +#define TARGET_NR_remap_file_pages 253 + /* 254 */ + /* 255 */ + /* 256 */ +#define TARGET_NR_set_tid_address 256 +#define TARGET_NR_timer_create 257 +#define TARGET_NR_timer_settime 258 +#define TARGET_NR_timer_gettime 259 +#define TARGET_NR_timer_getoverrun 260 +#define TARGET_NR_timer_delete 261 +#define TARGET_NR_clock_settime 262 +#define TARGET_NR_clock_gettime 263 +#define TARGET_NR_clock_getres 264 +#define TARGET_NR_clock_nanosleep 265 +#define TARGET_NR_statfs64 266 +#define TARGET_NR_fstatfs64 267 +#define TARGET_NR_tgkill 268 +#define TARGET_NR_utimes 269 +#define TARGET_NR_fadvise64_64 270 +#define TARGET_NR_pciconfig_iobase 271 +#define TARGET_NR_pciconfig_read 272 +#define TARGET_NR_pciconfig_write 273 +#define TARGET_NR_mq_open 274 +#define TARGET_NR_mq_unlink 275 +#define TARGET_NR_mq_timedsend 276 +#define TARGET_NR_mq_timedreceive 277 +#define TARGET_NR_mq_notify 278 +#define TARGET_NR_mq_getsetattr 279 +#define TARGET_NR_waitid 280 +#define TARGET_NR_socket 281 +#define TARGET_NR_bind 282 +#define TARGET_NR_connect 283 +#define TARGET_NR_listen 284 +#define TARGET_NR_accept 285 +#define TARGET_NR_getsockname 286 +#define TARGET_NR_getpeername 287 +#define TARGET_NR_socketpair 288 +#define TARGET_NR_send 289 +#define TARGET_NR_sendto 290 +#define TARGET_NR_recv 291 +#define TARGET_NR_recvfrom 292 +#define TARGET_NR_shutdown 293 +#define TARGET_NR_setsockopt 294 +#define TARGET_NR_getsockopt 295 +#define TARGET_NR_sendmsg 296 +#define TARGET_NR_recvmsg 297 +#define TARGET_NR_semop 298 +#define TARGET_NR_semget 299 +#define TARGET_NR_semctl 300 +#define TARGET_NR_msgsnd 301 +#define TARGET_NR_msgrcv 302 +#define TARGET_NR_msgget 303 +#define TARGET_NR_msgctl 304 +#define TARGET_NR_shmat 305 +#define TARGET_NR_shmdt 306 +#define TARGET_NR_shmget 307 +#define TARGET_NR_shmctl 308 +#define TARGET_NR_add_key 309 +#define TARGET_NR_request_key 310 +#define TARGET_NR_keyctl 311 +#define TARGET_NR_semtimedop 312 +#define TARGET_NR_vserver 313 +#define TARGET_NR_ioprio_set 314 +#define TARGET_NR_ioprio_get 315 +#define TARGET_NR_inotify_init 316 +#define TARGET_NR_inotify_add_watch 317 +#define TARGET_NR_inotify_rm_watch 318 +#define TARGET_NR_mbind 319 +#define TARGET_NR_get_mempolicy 320 +#define TARGET_NR_set_mempolicy 321 +#define TARGET_NR_openat 322 +#define TARGET_NR_mkdirat 323 +#define TARGET_NR_mknodat 324 +#define TARGET_NR_fchownat 325 +#define TARGET_NR_futimesat 326 +#define TARGET_NR_fstatat64 327 +#define TARGET_NR_unlinkat 328 +#define TARGET_NR_renameat 329 +#define TARGET_NR_linkat 330 +#define TARGET_NR_symlinkat 331 +#define TARGET_NR_readlinkat 332 +#define TARGET_NR_fchmodat 333 +#define TARGET_NR_faccessat 334 + /* 335 */ + /* 336 */ +#define TARGET_NR_unshare 337 +#define TARGET_NR_set_robust_list 338 +#define TARGET_NR_get_robust_list 339 +#define TARGET_NR_splice 340 +#define TARGET_NR_sync_file_range2 341 +#define TARGET_NR_tee 342 +#define TARGET_NR_vmsplice 343 +#define TARGET_NR_move_pages 344 +#define TARGET_NR_getcpu 345 + /* 346 */ +#define TARGET_NR_kexec_load 347 +#define TARGET_NR_utimensat 348 +#define TARGET_NR_signalfd 349 +#define TARGET_NR_timerfd 350 +#define TARGET_NR_eventfd 351 +#define TARGET_NR_fallocate 352 +#define TARGET_NR_timerfd_settime 353 +#define TARGET_NR_timerfd_gettime 354 +#define TARGET_NR_signalfd4 355 +#define TARGET_NR_eventfd2 356 +#define TARGET_NR_epoll_create1 357 +#define TARGET_NR_dup3 358 +#define TARGET_NR_pipe2 359 +#define TARGET_NR_inotify_init1 360 diff --git a/linux-user/unicore32/target_signal.h b/linux-user/unicore32/target_signal.h new file mode 100644 index 0000000..8b255c4 --- /dev/null +++ b/linux-user/unicore32/target_signal.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +/* this struct defines a stack used during syscall handling */ +typedef struct target_sigaltstack { + abi_ulong ss_sp; + abi_ulong ss_flags; + abi_ulong ss_size; +} target_stack_t; + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define get_sp_from_cpustate(cpustate) (cpustate->regs[29]) + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/unicore32/termbits.h b/linux-user/unicore32/termbits.h new file mode 100644 index 0000000..a5fcd64 --- /dev/null +++ b/linux-user/unicore32/termbits.h @@ -0,0 +1,2 @@ +/* NOTE: exactly the same as i386 */ +#include "../i386/termbits.h" diff --git a/migration-exec.c b/migration-exec.c index 14718dd..4b7aad8 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -17,7 +17,6 @@ #include "qemu_socket.h" #include "migration.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" #include <sys/types.h> diff --git a/migration-fd.c b/migration-fd.c index 6d14505..66d51c1 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -16,7 +16,6 @@ #include "migration.h" #include "monitor.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" #include "qemu_socket.h" diff --git a/migration-tcp.c b/migration-tcp.c index e8dff9d..d3d80c9 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -15,7 +15,6 @@ #include "qemu_socket.h" #include "migration.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" diff --git a/migration-unix.c b/migration-unix.c index 8b967f2..c8625c7 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -15,7 +15,6 @@ #include "qemu_socket.h" #include "migration.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" diff --git a/migration.h b/migration.h index 21707922..050c56c 100644 --- a/migration.h +++ b/migration.h @@ -139,4 +139,13 @@ void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); int get_migration_state(void); +uint64_t ram_bytes_remaining(void); +uint64_t ram_bytes_transferred(void); +uint64_t ram_bytes_total(void); + +int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque); +int ram_load(QEMUFile *f, void *opaque, int version_id); + +extern int incoming_expected; + #endif @@ -1429,7 +1429,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, if (l > line_size) l = line_size; if (is_physical) { - cpu_physical_memory_rw(addr, buf, l, 0); + cpu_physical_memory_read(addr, buf, l); } else { env = mon_get_cpu(); if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) { @@ -1605,7 +1605,7 @@ static int do_physical_memory_save(Monitor *mon, const QDict *qdict, l = sizeof(buf); if (l > size) l = size; - cpu_physical_memory_rw(addr, buf, l, 0); + cpu_physical_memory_read(addr, buf, l); if (fwrite(buf, 1, l, f) != l) { monitor_printf(mon, "fwrite() error in do_physical_memory_save\n"); goto exit; @@ -1625,17 +1625,16 @@ exit: static void do_sum(Monitor *mon, const QDict *qdict) { uint32_t addr; - uint8_t buf[1]; uint16_t sum; uint32_t start = qdict_get_int(qdict, "start"); uint32_t size = qdict_get_int(qdict, "size"); sum = 0; for(addr = start; addr < (start + size); addr++) { - cpu_physical_memory_rw(addr, buf, 1, 0); + uint8_t val = ldub_phys(addr); /* BSD sum algorithm ('sum' Unix command) */ sum = (sum >> 1) | (sum << 15); - sum += buf[0]; + sum += val; } monitor_printf(mon, "%05d\n", sum); } @@ -2026,7 +2025,7 @@ static void tlb_info_32(Monitor *mon, CPUState *env) pgd = env->cr[3] & ~0xfff; for(l1 = 0; l1 < 1024; l1++) { - cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + cpu_physical_memory_read(pgd + l1 * 4, &pde, 4); pde = le32_to_cpu(pde); if (pde & PG_PRESENT_MASK) { if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { @@ -2034,8 +2033,7 @@ static void tlb_info_32(Monitor *mon, CPUState *env) print_pte(mon, (l1 << 22), pde, ~((1 << 21) - 1)); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, - (uint8_t *)&pte, 4); + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4); pte = le32_to_cpu(pte); if (pte & PG_PRESENT_MASK) { print_pte(mon, (l1 << 22) + (l2 << 12), @@ -2056,13 +2054,12 @@ static void tlb_info_pae32(Monitor *mon, CPUState *env) pdp_addr = env->cr[3] & ~0x1f; for (l1 = 0; l1 < 4; l1++) { - cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8); + cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); if (pdpe & PG_PRESENT_MASK) { pd_addr = pdpe & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pd_addr + l2 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8); pde = le64_to_cpu(pde); if (pde & PG_PRESENT_MASK) { if (pde & PG_PSE_MASK) { @@ -2072,8 +2069,7 @@ static void tlb_info_pae32(Monitor *mon, CPUState *env) } else { pt_addr = pde & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pt_addr + l3 * 8, - (uint8_t *)&pte, 8); + cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8); pte = le64_to_cpu(pte); if (pte & PG_PRESENT_MASK) { print_pte(mon, (l1 << 30 ) + (l2 << 21) @@ -2098,13 +2094,12 @@ static void tlb_info_64(Monitor *mon, CPUState *env) pml4_addr = env->cr[3] & 0x3fffffffff000ULL; for (l1 = 0; l1 < 512; l1++) { - cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8); + cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); pml4e = le64_to_cpu(pml4e); if (pml4e & PG_PRESENT_MASK) { pdp_addr = pml4e & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe, - 8); + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); if (pdpe & PG_PRESENT_MASK) { if (pdpe & PG_PSE_MASK) { @@ -2114,8 +2109,7 @@ static void tlb_info_64(Monitor *mon, CPUState *env) } else { pd_addr = pdpe & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pd_addr + l3 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); pde = le64_to_cpu(pde); if (pde & PG_PRESENT_MASK) { if (pde & PG_PSE_MASK) { @@ -2128,8 +2122,7 @@ static void tlb_info_64(Monitor *mon, CPUState *env) for (l4 = 0; l4 < 512; l4++) { cpu_physical_memory_read(pt_addr + l4 * 8, - (uint8_t *)&pte, - 8); + &pte, 8); pte = le64_to_cpu(pte); if (pte & PG_PRESENT_MASK) { print_pte(mon, (l1 << 39) + @@ -2207,7 +2200,7 @@ static void mem_info_32(Monitor *mon, CPUState *env) last_prot = 0; start = -1; for(l1 = 0; l1 < 1024; l1++) { - cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + cpu_physical_memory_read(pgd + l1 * 4, &pde, 4); pde = le32_to_cpu(pde); end = l1 << 22; if (pde & PG_PRESENT_MASK) { @@ -2216,8 +2209,7 @@ static void mem_info_32(Monitor *mon, CPUState *env) mem_print(mon, &start, &last_prot, end, prot); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, - (uint8_t *)&pte, 4); + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4); pte = le32_to_cpu(pte); end = (l1 << 22) + (l2 << 12); if (pte & PG_PRESENT_MASK) { @@ -2246,14 +2238,13 @@ static void mem_info_pae32(Monitor *mon, CPUState *env) last_prot = 0; start = -1; for (l1 = 0; l1 < 4; l1++) { - cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8); + cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); end = l1 << 30; if (pdpe & PG_PRESENT_MASK) { pd_addr = pdpe & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pd_addr + l2 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8); pde = le64_to_cpu(pde); end = (l1 << 30) + (l2 << 21); if (pde & PG_PRESENT_MASK) { @@ -2264,8 +2255,7 @@ static void mem_info_pae32(Monitor *mon, CPUState *env) } else { pt_addr = pde & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pt_addr + l3 * 8, - (uint8_t *)&pte, 8); + cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8); pte = le64_to_cpu(pte); end = (l1 << 30) + (l2 << 21) + (l3 << 12); if (pte & PG_PRESENT_MASK) { @@ -2302,14 +2292,13 @@ static void mem_info_64(Monitor *mon, CPUState *env) last_prot = 0; start = -1; for (l1 = 0; l1 < 512; l1++) { - cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8); + cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); pml4e = le64_to_cpu(pml4e); end = l1 << 39; if (pml4e & PG_PRESENT_MASK) { pdp_addr = pml4e & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe, - 8); + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); end = (l1 << 39) + (l2 << 30); if (pdpe & PG_PRESENT_MASK) { @@ -2320,8 +2309,7 @@ static void mem_info_64(Monitor *mon, CPUState *env) } else { pd_addr = pdpe & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pd_addr + l3 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); pde = le64_to_cpu(pde); end = (l1 << 39) + (l2 << 30) + (l3 << 21); if (pde & PG_PRESENT_MASK) { @@ -2334,8 +2322,7 @@ static void mem_info_64(Monitor *mon, CPUState *env) for (l4 = 0; l4 < 512; l4++) { cpu_physical_memory_read(pt_addr + l4 * 8, - (uint8_t *)&pte, - 8); + &pte, 8); pte = le64_to_cpu(pte); end = (l1 << 39) + (l2 << 30) + (l3 << 21) + (l4 << 12); @@ -32,7 +32,6 @@ #include "net/vde.h" #include "net/util.h" #include "monitor.h" -#include "sysemu.h" #include "qemu-common.h" #include "qemu_socket.h" #include "hw/qdev.h" @@ -24,9 +24,9 @@ #include "dump.h" #include "qemu-common.h" -#include "sysemu.h" #include "qemu-error.h" #include "qemu-log.h" +#include "qemu-timer.h" typedef struct DumpState { VLANClientState nc; diff --git a/net/slirp.c b/net/slirp.c index b41c60a..e387a11 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -30,7 +30,6 @@ #endif #include "net.h" #include "monitor.h" -#include "sysemu.h" #include "qemu_socket.h" #include "slirp/libslirp.h" @@ -31,7 +31,6 @@ #include "qemu-char.h" #include "qemu-common.h" #include "qemu-option.h" -#include "sysemu.h" typedef struct VDEState { VLANClientState nc; @@ -46,7 +46,6 @@ extern int madvise(caddr_t, size_t, int); #include "qemu-common.h" #include "trace.h" -#include "sysemu.h" #include "qemu_socket.h" int qemu_madvise(void *addr, size_t len, int advice) diff --git a/qemu-common.h b/qemu-common.h index 82e27c1..f9f705d 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -12,6 +12,7 @@ #endif #define QEMU_BUILD_BUG_ON(x) typedef char __build_bug_on__##__LINE__[(x)?-1:1]; +#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) typedef struct QEMUTimer QEMUTimer; typedef struct QEMUFile QEMUFile; @@ -39,6 +40,14 @@ typedef struct Monitor Monitor; #include <sys/time.h> #include <assert.h> +#ifdef _WIN32 +#include "qemu-os-win32.h" +#endif + +#ifdef CONFIG_POSIX +#include "qemu-os-posix.h" +#endif + #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif @@ -298,6 +307,7 @@ void qemu_notify_event(void); void qemu_cpu_kick(void *env); void qemu_cpu_kick_self(void); int qemu_cpu_is_self(void *env); +bool all_cpu_threads_idle(void); /* work queue */ struct qemu_work_item { @@ -338,6 +348,16 @@ void qemu_progress_init(int enabled, float min_skip); void qemu_progress_end(void); void qemu_progress_print(float percent, int max); +#define QEMU_FILE_TYPE_BIOS 0 +#define QEMU_FILE_TYPE_KEYMAP 1 +char *qemu_find_file(int type, const char *name); + +/* OS specific functions */ +void os_setup_early_signal_handling(void); +char *os_find_datadir(const char *argv0); +void os_parse_cmd_args(int index, const char *optarg); +void os_pidfile_error(void); + /* Convert a byte between binary and BCD. */ static inline uint8_t to_bcd(uint8_t val) { diff --git a/qemu-config.c b/qemu-config.c index 323d3c2..14d3419 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -2,7 +2,6 @@ #include "qemu-error.h" #include "qemu-option.h" #include "qemu-config.h" -#include "sysemu.h" #include "hw/qdev.h" static QemuOptsList qemu_drive_opts = { diff --git a/qemu-error.c b/qemu-error.c index 5a35e7c1..41c191d 100644 --- a/qemu-error.c +++ b/qemu-error.c @@ -12,7 +12,6 @@ #include <stdio.h> #include "monitor.h" -#include "sysemu.h" /* * Print to current monitor if we have one, else to stderr. diff --git a/qemu-options.hx b/qemu-options.hx index ef60730..677c550 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -937,8 +937,8 @@ a lot of bandwidth at the expense of quality. Disable adaptive encodings. Adaptive encodings are enabled by default. An adaptive encoding will try to detect frequently updated screen regions, and send updates in these regions using a lossy encoding (like JPEG). -This can be really helpfull to save bandwidth when playing videos. Disabling -adaptive encodings allow to restore the original static behavior of encodings +This can be really helpful to save bandwidth when playing videos. Disabling +adaptive encodings allows to restore the original static behavior of encodings like Tight. @end table diff --git a/qemu-os-win32.h b/qemu-os-win32.h index 1a07e5e..ed2753d 100644 --- a/qemu-os-win32.h +++ b/qemu-os-win32.h @@ -26,6 +26,9 @@ #ifndef QEMU_OS_WIN32_H #define QEMU_OS_WIN32_H +#include <windows.h> +#include <winsock2.h> + /* Polling handling */ /* return TRUE if no sleep should be done afterwards */ diff --git a/qemu-timer.c b/qemu-timer.c index 50f1943..b8c0c88 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -110,9 +110,12 @@ static int64_t cpu_get_clock(void) } } +#ifndef CONFIG_IOTHREAD static int64_t qemu_icount_delta(void) { - if (use_icount == 1) { + if (!use_icount) { + return 5000 * (int64_t) 1000000; + } else if (use_icount == 1) { /* When not using an adaptive execution frequency we tend to get badly out of sync with real time, so just delay for a reasonable amount of time. */ @@ -121,6 +124,7 @@ static int64_t qemu_icount_delta(void) return cpu_get_icount() - cpu_get_clock(); } } +#endif /* enable cpu_get_ticks() */ void cpu_enable_ticks(void) @@ -153,6 +157,8 @@ void cpu_disable_ticks(void) struct QEMUClock { int type; int enabled; + + QEMUTimer *warp_timer; }; struct QEMUTimer { @@ -386,6 +392,90 @@ void qemu_clock_enable(QEMUClock *clock, int enabled) clock->enabled = enabled; } +static int64_t vm_clock_warp_start; + +static void icount_warp_rt(void *opaque) +{ + if (vm_clock_warp_start == -1) { + return; + } + + if (vm_running) { + int64_t clock = qemu_get_clock_ns(rt_clock); + int64_t warp_delta = clock - vm_clock_warp_start; + if (use_icount == 1) { + qemu_icount_bias += warp_delta; + } else { + /* + * In adaptive mode, do not let the vm_clock run too + * far ahead of real time. + */ + int64_t cur_time = cpu_get_clock(); + int64_t cur_icount = qemu_get_clock_ns(vm_clock); + int64_t delta = cur_time - cur_icount; + qemu_icount_bias += MIN(warp_delta, delta); + } + if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], + qemu_get_clock_ns(vm_clock))) { + qemu_notify_event(); + } + } + vm_clock_warp_start = -1; +} + +void qemu_clock_warp(QEMUClock *clock) +{ + int64_t deadline; + + if (!clock->warp_timer) { + return; + } + + /* + * There are too many global variables to make the "warp" behavior + * applicable to other clocks. But a clock argument removes the + * need for if statements all over the place. + */ + assert(clock == vm_clock); + + /* + * If the CPUs have been sleeping, advance the vm_clock timer now. This + * ensures that the deadline for the timer is computed correctly below. + * This also makes sure that the insn counter is synchronized before the + * CPU starts running, in case the CPU is woken by an event other than + * the earliest vm_clock timer. + */ + icount_warp_rt(NULL); + if (!all_cpu_threads_idle() || !active_timers[clock->type]) { + qemu_del_timer(clock->warp_timer); + return; + } + + vm_clock_warp_start = qemu_get_clock_ns(rt_clock); + deadline = qemu_next_icount_deadline(); + if (deadline > 0) { + /* + * Ensure the vm_clock proceeds even when the virtual CPU goes to + * sleep. Otherwise, the CPU might be waiting for a future timer + * interrupt to wake it up, but the interrupt never comes because + * the vCPU isn't running any insns and thus doesn't advance the + * vm_clock. + * + * An extreme solution for this problem would be to never let VCPUs + * sleep in icount mode if there is a pending vm_clock timer; rather + * time could just advance to the next vm_clock event. Instead, we + * do stop VCPUs and only advance vm_clock after some "real" time, + * (related to the time left until the next event) has passed. This + * rt_clock timer will do this. This avoids that the warps are too + * visible externally---for example, you will not be sending network + * packets continously instead of every 100ms. + */ + qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline); + } else { + qemu_notify_event(); + } +} + QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, QEMUTimerCB *cb, void *opaque) { @@ -454,8 +544,10 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) qemu_rearm_alarm_timer(alarm_timer); } /* Interrupt execution to force deadline recalculation. */ - if (use_icount) + qemu_clock_warp(ts->clock); + if (use_icount) { qemu_notify_event(); + } } } @@ -576,6 +668,10 @@ void configure_icount(const char *option) if (!option) return; +#ifdef CONFIG_IOTHREAD + vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL); +#endif + if (strcmp(option, "auto") != 0) { icount_time_shift = strtol(option, NULL, 0); use_icount = 1; @@ -669,21 +765,16 @@ static void host_alarm_handler(int host_signum) } } -int64_t qemu_next_deadline(void) +int64_t qemu_next_icount_deadline(void) { /* To avoid problems with overflow limit this to 2^32. */ int64_t delta = INT32_MAX; + assert(use_icount); if (active_timers[QEMU_CLOCK_VIRTUAL]) { delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - qemu_get_clock_ns(vm_clock); } - if (active_timers[QEMU_CLOCK_HOST]) { - int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - - qemu_get_clock_ns(host_clock); - if (hdelta < delta) - delta = hdelta; - } if (delta < 0) delta = 0; @@ -1055,39 +1146,41 @@ void quit_timers(void) int qemu_calculate_timeout(void) { +#ifndef CONFIG_IOTHREAD int timeout; - int64_t add; - int64_t delta; - - /* When using icount, making forward progress with qemu_icount when the - guest CPU is idle is critical. We only use the static io-thread timeout - for non icount runs. */ - if (!use_icount || !vm_running) { - return 5000; - } - /* Advance virtual time to the next event. */ - delta = qemu_icount_delta(); - if (delta > 0) { - /* If virtual time is ahead of real time then just - wait for IO. */ - timeout = (delta + 999999) / 1000000; - } else { - /* Wait for either IO to occur or the next - timer event. */ - add = qemu_next_deadline(); - /* We advance the timer before checking for IO. - Limit the amount we advance so that early IO - activity won't get the guest too far ahead. */ - if (add > 10000000) - add = 10000000; - delta += add; - qemu_icount += qemu_icount_round (add); - timeout = delta / 1000000; - if (timeout < 0) - timeout = 0; + if (!vm_running) + timeout = 5000; + else { + /* XXX: use timeout computed from timers */ + int64_t add; + int64_t delta; + /* Advance virtual time to the next event. */ + delta = qemu_icount_delta(); + if (delta > 0) { + /* If virtual time is ahead of real time then just + wait for IO. */ + timeout = (delta + 999999) / 1000000; + } else { + /* Wait for either IO to occur or the next + timer event. */ + add = qemu_next_icount_deadline(); + /* We advance the timer before checking for IO. + Limit the amount we advance so that early IO + activity won't get the guest too far ahead. */ + if (add > 10000000) + add = 10000000; + delta += add; + qemu_icount += qemu_icount_round (add); + timeout = delta / 1000000; + if (timeout < 0) + timeout = 0; + } } return timeout; +#else /* CONFIG_IOTHREAD */ + return 1000; +#endif } diff --git a/qemu-timer.h b/qemu-timer.h index 75d5675..2cacf65 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -39,6 +39,7 @@ extern QEMUClock *host_clock; int64_t qemu_get_clock_ns(QEMUClock *clock); void qemu_clock_enable(QEMUClock *clock, int enabled); +void qemu_clock_warp(QEMUClock *clock); QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, QEMUTimerCB *cb, void *opaque); @@ -50,7 +51,7 @@ int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); void qemu_run_all_timers(void); int qemu_alarm_pending(void); -int64_t qemu_next_deadline(void); +int64_t qemu_next_icount_deadline(void); void configure_alarms(char const *opt); void configure_icount(const char *option); int qemu_calculate_timeout(void); @@ -58,6 +59,10 @@ void init_clocks(void); int init_timer_alarm(void); void quit_timers(void); +int64_t cpu_get_ticks(void); +void cpu_enable_ticks(void); +void cpu_disable_ticks(void); + static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb, void *opaque) { @@ -139,8 +144,6 @@ uint64_t ptimer_get_count(ptimer_state *s); void ptimer_set_count(ptimer_state *s, uint64_t count); void ptimer_run(ptimer_state *s, int oneshot); void ptimer_stop(ptimer_state *s); -void qemu_put_ptimer(QEMUFile *f, ptimer_state *s); -void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); /* icount */ int64_t qemu_icount_round(int64_t count); diff --git a/qemu-tool.c b/qemu-tool.c index d45840d..f4a6ad0 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -15,7 +15,6 @@ #include "monitor.h" #include "qemu-timer.h" #include "qemu-log.h" -#include "sysemu.h" #include <sys/time.h> @@ -82,6 +82,7 @@ #include "migration.h" #include "qemu_socket.h" #include "qemu-queue.h" +#include "cpus.h" #define SELF_ANNOUNCE_ROUNDS 5 @@ -1007,7 +1008,7 @@ const VMStateInfo vmstate_info_buffer = { }; /* unused buffers: space that was used for some fields that are - not usefull anymore */ + not useful anymore */ static int get_unused_buffer(QEMUFile *f, void *pv, size_t size) { @@ -8,22 +8,9 @@ #include "qemu-timer.h" #include "notify.h" -#ifdef _WIN32 -#include <windows.h> -#include "qemu-os-win32.h" -#endif - -#ifdef CONFIG_POSIX -#include "qemu-os-posix.h" -#endif - /* vl.c */ extern const char *bios_name; -#define QEMU_FILE_TYPE_BIOS 0 -#define QEMU_FILE_TYPE_KEYMAP 1 -char *qemu_find_file(int type, const char *name); - extern int vm_running; extern const char *qemu_name; extern uint8_t qemu_uuid[]; @@ -50,14 +37,6 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); void vm_start(void); void vm_stop(int reason); -uint64_t ram_bytes_remaining(void); -uint64_t ram_bytes_transferred(void); -uint64_t ram_bytes_total(void); - -int64_t cpu_get_ticks(void); -void cpu_enable_ticks(void); -void cpu_disable_ticks(void); - void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); @@ -81,10 +60,6 @@ int load_vmstate(const char *name); void do_delvm(Monitor *mon, const QDict *qdict); void do_info_snapshots(Monitor *mon); -void cpu_synchronize_all_states(void); -void cpu_synchronize_all_post_reset(void); -void cpu_synchronize_all_post_init(void); - void qemu_announce_self(void); void main_loop_wait(int nonblocking); @@ -100,12 +75,6 @@ int qemu_loadvm_state(QEMUFile *f); /* SLIRP */ void do_info_slirp(Monitor *mon); -/* OS specific functions */ -void os_setup_early_signal_handling(void); -char *os_find_datadir(const char *argv0); -void os_parse_cmd_args(int index, const char *optarg); -void os_pidfile_error(void); - typedef enum DisplayType { DT_DEFAULT, @@ -116,7 +85,6 @@ typedef enum DisplayType } DisplayType; extern int autostart; -extern int incoming_expected; extern int bios_size; typedef enum { @@ -191,8 +159,6 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; -#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) - void do_usb_add(Monitor *mon, const QDict *qdict); void do_usb_del(Monitor *mon, const QDict *qdict); void usb_info(Monitor *mon); diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 6c2ae20..4ccb10b 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -904,10 +904,11 @@ uint64_t helper_cmptun (uint64_t a, uint64_t b) fa = t_to_float64(a); fb = t_to_float64(b); - if (float64_is_quiet_nan(fa) || float64_is_quiet_nan(fb)) + if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { return 0x4000000000000000ULL; - else + } else { return 0; + } } uint64_t helper_cmpteq(uint64_t a, uint64_t b) @@ -917,7 +918,7 @@ uint64_t helper_cmpteq(uint64_t a, uint64_t b) fa = t_to_float64(a); fb = t_to_float64(b); - if (float64_eq(fa, fb, &FP_STATUS)) + if (float64_eq_quiet(fa, fb, &FP_STATUS)) return 0x4000000000000000ULL; else return 0; @@ -956,7 +957,7 @@ uint64_t helper_cmpgeq(uint64_t a, uint64_t b) fa = g_to_float64(a); fb = g_to_float64(b); - if (float64_eq(fa, fb, &FP_STATUS)) + if (float64_eq_quiet(fa, fb, &FP_STATUS)) return 0x4000000000000000ULL; else return 0; @@ -1373,7 +1374,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (likely(tb)) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } /* Exception index and error code are already set */ diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 3a1c625..456ba51 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -398,7 +398,7 @@ static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp) } else if (use_goto_tb(ctx, dest)) { tcg_gen_goto_tb(0); tcg_gen_movi_i64(cpu_pc, dest); - tcg_gen_exit_tb((long)ctx->tb); + tcg_gen_exit_tb((tcg_target_long)ctx->tb); return EXIT_GOTO_TB; } else { tcg_gen_movi_i64(cpu_pc, dest); @@ -417,12 +417,12 @@ static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond, tcg_gen_goto_tb(0); tcg_gen_movi_i64(cpu_pc, ctx->pc); - tcg_gen_exit_tb((long)ctx->tb); + tcg_gen_exit_tb((tcg_target_long)ctx->tb); gen_set_label(lab_true); tcg_gen_goto_tb(1); tcg_gen_movi_i64(cpu_pc, dest); - tcg_gen_exit_tb((long)ctx->tb + 1); + tcg_gen_exit_tb((tcg_target_long)ctx->tb + 1); return EXIT_GOTO_TB; } else { @@ -3367,8 +3367,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) return env; } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1ae7982..d5af644 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -360,7 +360,10 @@ enum arm_features { ARM_FEATURE_M, /* Microcontroller profile. */ ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */ ARM_FEATURE_THUMB2EE, - ARM_FEATURE_V7MP /* v7 Multiprocessing Extensions */ + ARM_FEATURE_V7MP, /* v7 Multiprocessing Extensions */ + ARM_FEATURE_V4T, + ARM_FEATURE_V5, + ARM_FEATURE_STRONGARM, }; static inline int arm_feature(CPUARMState *env, int feature) @@ -391,6 +394,8 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define ARM_CPUID_ARM946 0x41059461 #define ARM_CPUID_TI915T 0x54029152 #define ARM_CPUID_TI925T 0x54029252 +#define ARM_CPUID_SA1100 0x4401A11B +#define ARM_CPUID_SA1110 0x6901B119 #define ARM_CPUID_PXA250 0x69052100 #define ARM_CPUID_PXA255 0x69052d00 #define ARM_CPUID_PXA260 0x69052903 diff --git a/target-arm/helper.c b/target-arm/helper.c index 6788a4c..62ae72e 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5,7 +5,7 @@ #include "cpu.h" #include "exec-all.h" #include "gdbstub.h" -#include "helpers.h" +#include "helper.h" #include "qemu-common.h" #include "host-utils.h" #if !defined(CONFIG_USER_ONLY) @@ -48,17 +48,23 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cpuid = id; switch (id) { case ARM_CPUID_ARM926: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_VFP); env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; env->cp15.c0_cachetype = 0x1dd20d2; env->cp15.c1_sys = 0x00090078; break; case ARM_CPUID_ARM946: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_MPU); env->cp15.c0_cachetype = 0x0f004006; env->cp15.c1_sys = 0x00000078; break; case ARM_CPUID_ARM1026: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; @@ -67,6 +73,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) break; case ARM_CPUID_ARM1136_R2: case ARM_CPUID_ARM1136: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); @@ -79,6 +87,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c1_sys = 0x00050078; break; case ARM_CPUID_ARM11MPCORE: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_VFP); @@ -91,6 +101,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0x1dd20d2; break; case ARM_CPUID_CORTEXA8: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_V7); @@ -113,6 +125,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c1_sys = 0x00c50078; break; case ARM_CPUID_CORTEXA9: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_V7); @@ -140,6 +154,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c1_sys = 0x00c50078; break; case ARM_CPUID_CORTEXM3: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_THUMB2); set_feature(env, ARM_FEATURE_V7); @@ -147,6 +163,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_DIV); break; case ARM_CPUID_ANY: /* For userspace emulation. */ + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_V7); @@ -161,6 +179,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) break; case ARM_CPUID_TI915T: case ARM_CPUID_TI925T: + set_feature(env, ARM_FEATURE_V4T); set_feature(env, ARM_FEATURE_OMAPCP); env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */ env->cp15.c0_cachetype = 0x5109149; @@ -173,6 +192,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) case ARM_CPUID_PXA260: case ARM_CPUID_PXA261: case ARM_CPUID_PXA262: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ env->cp15.c0_cachetype = 0xd172172; @@ -184,6 +205,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) case ARM_CPUID_PXA270_B1: case ARM_CPUID_PXA270_C0: case ARM_CPUID_PXA270_C5: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ set_feature(env, ARM_FEATURE_IWMMXT); @@ -191,6 +214,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0xd172172; env->cp15.c1_sys = 0x00000078; break; + case ARM_CPUID_SA1100: + case ARM_CPUID_SA1110: + set_feature(env, ARM_FEATURE_STRONGARM); + env->cp15.c1_sys = 0x00000070; + break; default: cpu_abort(env, "Bad CPU ID: %x\n", id); break; @@ -246,6 +274,10 @@ void cpu_reset(CPUARMState *env) set_flush_to_zero(1, &env->vfp.standard_fp_status); set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status); set_default_nan_mode(1, &env->vfp.standard_fp_status); + set_float_detect_tininess(float_tininess_before_rounding, + &env->vfp.fp_status); + set_float_detect_tininess(float_tininess_before_rounding, + &env->vfp.standard_fp_status); tlb_flush(env, 1); } @@ -351,6 +383,8 @@ static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_CORTEXA9, "cortex-a9"}, { ARM_CPUID_TI925T, "ti925t" }, { ARM_CPUID_PXA250, "pxa250" }, + { ARM_CPUID_SA1100, "sa1100" }, + { ARM_CPUID_SA1110, "sa1110" }, { ARM_CPUID_PXA255, "pxa255" }, { ARM_CPUID_PXA260, "pxa260" }, { ARM_CPUID_PXA261, "pxa261" }, @@ -856,7 +890,11 @@ void do_interrupt(CPUARMState *env) /* Switch to the new mode, and to the correct instruction set. */ env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode; env->uncached_cpsr |= mask; - env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0; + /* this is a lie, as the was no c1_sys on V4T/V5, but who cares + * and we should just guard the thumb mode on V4 */ + if (arm_feature(env, ARM_FEATURE_V4T)) { + env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0; + } env->regs[14] = env->regs[15] + offset; env->regs[15] = addr; env->interrupt_request |= CPU_INTERRUPT_EXITTB; @@ -1347,7 +1385,7 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) /* This may enable/disable the MMU, so do a TLB flush. */ tlb_flush(env, 1); break; - case 1: /* Auxiliary cotrol register. */ + case 1: /* Auxiliary control register. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { env->cp15.c1_xscaleauxcr = val; break; @@ -1522,6 +1560,8 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; + if (arm_feature(env, ARM_FEATURE_STRONGARM)) + break; /* Ignore ReadBuffer access */ switch (crm) { case 0: /* Cache lockdown. */ switch (op1) { @@ -2511,6 +2551,7 @@ float64 VFP_HELPER(sito, d)(uint32_t x, CPUState *env) uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_uint32(x, &env->vfp.fp_status); @@ -2519,6 +2560,7 @@ uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_uint32(x, &env->vfp.fp_status); @@ -2527,6 +2569,7 @@ uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env) uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_int32(x, &env->vfp.fp_status); @@ -2535,6 +2578,7 @@ uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_int32(x, &env->vfp.fp_status); @@ -2543,6 +2587,7 @@ uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env) uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_uint32_round_to_zero(x, &env->vfp.fp_status); @@ -2551,6 +2596,7 @@ uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_uint32_round_to_zero(x, &env->vfp.fp_status); @@ -2559,6 +2605,7 @@ uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env) uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_int32_round_to_zero(x, &env->vfp.fp_status); @@ -2567,6 +2614,7 @@ uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(tosiz, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_int32_round_to_zero(x, &env->vfp.fp_status); @@ -2605,6 +2653,7 @@ uint##fsz##_t VFP_HELPER(to##name, p)(float##fsz x, uint32_t shift, \ { \ float##fsz tmp; \ if (float##fsz##_is_any_nan(x)) { \ + float_raise(float_flag_invalid, &env->vfp.fp_status); \ return 0; \ } \ tmp = float##fsz##_scalbn(x, shift, &env->vfp.fp_status); \ diff --git a/target-arm/helpers.h b/target-arm/helper.h index ae701e8..ae701e8 100644 --- a/target-arm/helpers.h +++ b/target-arm/helper.h diff --git a/target-arm/iwmmxt_helper.c b/target-arm/iwmmxt_helper.c index 3941f1f..ebe6eb9 100644 --- a/target-arm/iwmmxt_helper.c +++ b/target-arm/iwmmxt_helper.c @@ -24,7 +24,7 @@ #include "cpu.h" #include "exec.h" -#include "helpers.h" +#include "helper.h" /* iwMMXt macros extracted from GNU gdb. */ diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index c3ac96a..f5b173a 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -11,7 +11,7 @@ #include "cpu.h" #include "exec.h" -#include "helpers.h" +#include "helper.h" #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) @@ -1514,9 +1514,13 @@ uint64_t HELPER(neon_addl_saturate_s64)(uint64_t a, uint64_t b) return result; } -#define DO_ABD(dest, x, y, type) do { \ - type tmp_x = x; \ - type tmp_y = y; \ +/* We have to do the arithmetic in a larger type than + * the input type, because for example with a signed 32 bit + * op the absolute difference can overflow a signed 32 bit value. + */ +#define DO_ABD(dest, x, y, intype, arithtype) do { \ + arithtype tmp_x = (intype)(x); \ + arithtype tmp_y = (intype)(y); \ dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \ } while(0) @@ -1524,12 +1528,12 @@ uint64_t HELPER(neon_abdl_u16)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, uint8_t); - DO_ABD(tmp, a >> 8, b >> 8, uint8_t); + DO_ABD(result, a, b, uint8_t, uint32_t); + DO_ABD(tmp, a >> 8, b >> 8, uint8_t, uint32_t); result |= tmp << 16; - DO_ABD(tmp, a >> 16, b >> 16, uint8_t); + DO_ABD(tmp, a >> 16, b >> 16, uint8_t, uint32_t); result |= tmp << 32; - DO_ABD(tmp, a >> 24, b >> 24, uint8_t); + DO_ABD(tmp, a >> 24, b >> 24, uint8_t, uint32_t); result |= tmp << 48; return result; } @@ -1538,12 +1542,12 @@ uint64_t HELPER(neon_abdl_s16)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, int8_t); - DO_ABD(tmp, a >> 8, b >> 8, int8_t); + DO_ABD(result, a, b, int8_t, int32_t); + DO_ABD(tmp, a >> 8, b >> 8, int8_t, int32_t); result |= tmp << 16; - DO_ABD(tmp, a >> 16, b >> 16, int8_t); + DO_ABD(tmp, a >> 16, b >> 16, int8_t, int32_t); result |= tmp << 32; - DO_ABD(tmp, a >> 24, b >> 24, int8_t); + DO_ABD(tmp, a >> 24, b >> 24, int8_t, int32_t); result |= tmp << 48; return result; } @@ -1552,8 +1556,8 @@ uint64_t HELPER(neon_abdl_u32)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, uint16_t); - DO_ABD(tmp, a >> 16, b >> 16, uint16_t); + DO_ABD(result, a, b, uint16_t, uint32_t); + DO_ABD(tmp, a >> 16, b >> 16, uint16_t, uint32_t); return result | (tmp << 32); } @@ -1561,22 +1565,22 @@ uint64_t HELPER(neon_abdl_s32)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, int16_t); - DO_ABD(tmp, a >> 16, b >> 16, int16_t); + DO_ABD(result, a, b, int16_t, int32_t); + DO_ABD(tmp, a >> 16, b >> 16, int16_t, int32_t); return result | (tmp << 32); } uint64_t HELPER(neon_abdl_u64)(uint32_t a, uint32_t b) { uint64_t result; - DO_ABD(result, a, b, uint32_t); + DO_ABD(result, a, b, uint32_t, uint64_t); return result; } uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b) { uint64_t result; - DO_ABD(result, a, b, int32_t); + DO_ABD(result, a, b, int32_t, int64_t); return result; } #undef DO_ABD diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 3de2610..8334fbc 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -17,7 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "exec.h" -#include "helpers.h" +#include "helper.h" #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) @@ -90,7 +90,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } raise_exception(env->exception_index); diff --git a/target-arm/translate.c b/target-arm/translate.c index c6cb39a..e1bda57 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -30,10 +30,14 @@ #include "tcg-op.h" #include "qemu-log.h" -#include "helpers.h" +#include "helper.h" #define GEN_HELPER 1 -#include "helpers.h" +#include "helper.h" +#define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T) +#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5) +/* currently all emulated v5 cores are also v5TE, so don't bother */ +#define ENABLE_ARCH_5TE arm_feature(env, ARM_FEATURE_V5) #define ENABLE_ARCH_5J 0 #define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6) #define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K) @@ -125,7 +129,7 @@ void arm_translate_init(void) #endif #define GEN_HELPER 2 -#include "helpers.h" +#include "helper.h" } static inline TCGv load_cpu_offset(int offset) @@ -750,6 +754,20 @@ static inline void store_reg_bx(CPUState *env, DisasContext *s, } } +/* Variant of store_reg which uses branch&exchange logic when storing + * to r15 in ARM architecture v5T and above. This is used for storing + * the results of a LDR/LDM/POP into r15, and corresponds to the cases + * in the ARM ARM which use the LoadWritePC() pseudocode function. */ +static inline void store_reg_from_load(CPUState *env, DisasContext *s, + int reg, TCGv var) +{ + if (reg == 15 && ENABLE_ARCH_5) { + gen_bx(s, var); + } else { + store_reg(s, reg, var); + } +} + static inline TCGv gen_ld8s(TCGv addr, int index) { TCGv tmp = tcg_temp_new_i32(); @@ -3387,7 +3405,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); gen_set_pc_im(dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { gen_set_pc_im(dest); tcg_gen_exit_tb(0); @@ -3436,6 +3454,10 @@ static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) { /* Mask out undefined bits. */ mask &= ~CPSR_RESERVED; + if (!arm_feature(env, ARM_FEATURE_V4T)) + mask &= ~CPSR_T; + if (!arm_feature(env, ARM_FEATURE_V5)) + mask &= ~CPSR_Q; /* V5TE in reality*/ if (!arm_feature(env, ARM_FEATURE_V6)) mask &= ~(CPSR_E | CPSR_GE); if (!arm_feature(env, ARM_FEATURE_THUMB2)) @@ -3536,15 +3558,14 @@ static void gen_nop_hint(DisasContext *s, int val) #define CPU_V001 cpu_V0, cpu_V0, cpu_V1 -static inline int gen_neon_add(int size, TCGv t0, TCGv t1) +static inline void gen_neon_add(int size, TCGv t0, TCGv t1) { switch (size) { case 0: gen_helper_neon_add_u8(t0, t0, t1); break; case 1: gen_helper_neon_add_u16(t0, t0, t1); break; case 2: tcg_gen_add_i32(t0, t0, t1); break; - default: return 1; + default: abort(); } - return 0; } static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1) @@ -3641,7 +3662,7 @@ static inline TCGv neon_get_scalar(int size, int reg) static int gen_neon_unzip(int rd, int rm, int size, int q) { TCGv tmp, tmp2; - if (size == 3 || (!q && size == 2)) { + if (!q && size == 2) { return 1; } tmp = tcg_const_i32(rd); @@ -3680,7 +3701,7 @@ static int gen_neon_unzip(int rd, int rm, int size, int q) static int gen_neon_zip(int rd, int rm, int size, int q) { TCGv tmp, tmp2; - if (size == 3 || (!q && size == 2)) { + if (!q && size == 2) { return 1; } tmp = tcg_const_i32(rd); @@ -4223,6 +4244,181 @@ static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src) } } +/* Symbolic constants for op fields for Neon 3-register same-length. + * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B + * table A7-9. + */ +#define NEON_3R_VHADD 0 +#define NEON_3R_VQADD 1 +#define NEON_3R_VRHADD 2 +#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */ +#define NEON_3R_VHSUB 4 +#define NEON_3R_VQSUB 5 +#define NEON_3R_VCGT 6 +#define NEON_3R_VCGE 7 +#define NEON_3R_VSHL 8 +#define NEON_3R_VQSHL 9 +#define NEON_3R_VRSHL 10 +#define NEON_3R_VQRSHL 11 +#define NEON_3R_VMAX 12 +#define NEON_3R_VMIN 13 +#define NEON_3R_VABD 14 +#define NEON_3R_VABA 15 +#define NEON_3R_VADD_VSUB 16 +#define NEON_3R_VTST_VCEQ 17 +#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */ +#define NEON_3R_VMUL 19 +#define NEON_3R_VPMAX 20 +#define NEON_3R_VPMIN 21 +#define NEON_3R_VQDMULH_VQRDMULH 22 +#define NEON_3R_VPADD 23 +#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */ +#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */ +#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */ +#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */ +#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */ +#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */ + +static const uint8_t neon_3r_sizes[] = { + [NEON_3R_VHADD] = 0x7, + [NEON_3R_VQADD] = 0xf, + [NEON_3R_VRHADD] = 0x7, + [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */ + [NEON_3R_VHSUB] = 0x7, + [NEON_3R_VQSUB] = 0xf, + [NEON_3R_VCGT] = 0x7, + [NEON_3R_VCGE] = 0x7, + [NEON_3R_VSHL] = 0xf, + [NEON_3R_VQSHL] = 0xf, + [NEON_3R_VRSHL] = 0xf, + [NEON_3R_VQRSHL] = 0xf, + [NEON_3R_VMAX] = 0x7, + [NEON_3R_VMIN] = 0x7, + [NEON_3R_VABD] = 0x7, + [NEON_3R_VABA] = 0x7, + [NEON_3R_VADD_VSUB] = 0xf, + [NEON_3R_VTST_VCEQ] = 0x7, + [NEON_3R_VML] = 0x7, + [NEON_3R_VMUL] = 0x7, + [NEON_3R_VPMAX] = 0x7, + [NEON_3R_VPMIN] = 0x7, + [NEON_3R_VQDMULH_VQRDMULH] = 0x6, + [NEON_3R_VPADD] = 0x7, + [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */ +}; + +/* Symbolic constants for op fields for Neon 2-register miscellaneous. + * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B + * table A7-13. + */ +#define NEON_2RM_VREV64 0 +#define NEON_2RM_VREV32 1 +#define NEON_2RM_VREV16 2 +#define NEON_2RM_VPADDL 4 +#define NEON_2RM_VPADDL_U 5 +#define NEON_2RM_VCLS 8 +#define NEON_2RM_VCLZ 9 +#define NEON_2RM_VCNT 10 +#define NEON_2RM_VMVN 11 +#define NEON_2RM_VPADAL 12 +#define NEON_2RM_VPADAL_U 13 +#define NEON_2RM_VQABS 14 +#define NEON_2RM_VQNEG 15 +#define NEON_2RM_VCGT0 16 +#define NEON_2RM_VCGE0 17 +#define NEON_2RM_VCEQ0 18 +#define NEON_2RM_VCLE0 19 +#define NEON_2RM_VCLT0 20 +#define NEON_2RM_VABS 22 +#define NEON_2RM_VNEG 23 +#define NEON_2RM_VCGT0_F 24 +#define NEON_2RM_VCGE0_F 25 +#define NEON_2RM_VCEQ0_F 26 +#define NEON_2RM_VCLE0_F 27 +#define NEON_2RM_VCLT0_F 28 +#define NEON_2RM_VABS_F 30 +#define NEON_2RM_VNEG_F 31 +#define NEON_2RM_VSWP 32 +#define NEON_2RM_VTRN 33 +#define NEON_2RM_VUZP 34 +#define NEON_2RM_VZIP 35 +#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */ +#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */ +#define NEON_2RM_VSHLL 38 +#define NEON_2RM_VCVT_F16_F32 44 +#define NEON_2RM_VCVT_F32_F16 46 +#define NEON_2RM_VRECPE 56 +#define NEON_2RM_VRSQRTE 57 +#define NEON_2RM_VRECPE_F 58 +#define NEON_2RM_VRSQRTE_F 59 +#define NEON_2RM_VCVT_FS 60 +#define NEON_2RM_VCVT_FU 61 +#define NEON_2RM_VCVT_SF 62 +#define NEON_2RM_VCVT_UF 63 + +static int neon_2rm_is_float_op(int op) +{ + /* Return true if this neon 2reg-misc op is float-to-float */ + return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F || + op >= NEON_2RM_VRECPE_F); +} + +/* Each entry in this array has bit n set if the insn allows + * size value n (otherwise it will UNDEF). Since unallocated + * op values will have no bits set they always UNDEF. + */ +static const uint8_t neon_2rm_sizes[] = { + [NEON_2RM_VREV64] = 0x7, + [NEON_2RM_VREV32] = 0x3, + [NEON_2RM_VREV16] = 0x1, + [NEON_2RM_VPADDL] = 0x7, + [NEON_2RM_VPADDL_U] = 0x7, + [NEON_2RM_VCLS] = 0x7, + [NEON_2RM_VCLZ] = 0x7, + [NEON_2RM_VCNT] = 0x1, + [NEON_2RM_VMVN] = 0x1, + [NEON_2RM_VPADAL] = 0x7, + [NEON_2RM_VPADAL_U] = 0x7, + [NEON_2RM_VQABS] = 0x7, + [NEON_2RM_VQNEG] = 0x7, + [NEON_2RM_VCGT0] = 0x7, + [NEON_2RM_VCGE0] = 0x7, + [NEON_2RM_VCEQ0] = 0x7, + [NEON_2RM_VCLE0] = 0x7, + [NEON_2RM_VCLT0] = 0x7, + [NEON_2RM_VABS] = 0x7, + [NEON_2RM_VNEG] = 0x7, + [NEON_2RM_VCGT0_F] = 0x4, + [NEON_2RM_VCGE0_F] = 0x4, + [NEON_2RM_VCEQ0_F] = 0x4, + [NEON_2RM_VCLE0_F] = 0x4, + [NEON_2RM_VCLT0_F] = 0x4, + [NEON_2RM_VABS_F] = 0x4, + [NEON_2RM_VNEG_F] = 0x4, + [NEON_2RM_VSWP] = 0x1, + [NEON_2RM_VTRN] = 0x7, + [NEON_2RM_VUZP] = 0x7, + [NEON_2RM_VZIP] = 0x7, + [NEON_2RM_VMOVN] = 0x7, + [NEON_2RM_VQMOVN] = 0x7, + [NEON_2RM_VSHLL] = 0x7, + [NEON_2RM_VCVT_F16_F32] = 0x2, + [NEON_2RM_VCVT_F32_F16] = 0x2, + [NEON_2RM_VRECPE] = 0x4, + [NEON_2RM_VRSQRTE] = 0x4, + [NEON_2RM_VRECPE_F] = 0x4, + [NEON_2RM_VRSQRTE_F] = 0x4, + [NEON_2RM_VCVT_FS] = 0x4, + [NEON_2RM_VCVT_FU] = 0x4, + [NEON_2RM_VCVT_SF] = 0x4, + [NEON_2RM_VCVT_UF] = 0x4, +}; + /* Translate a NEON data processing instruction. Return nonzero if the instruction is invalid. We process data in a mixture of 32-bit and 64-bit chunks. @@ -4239,7 +4435,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) int count; int pairwise; int u; - int n; uint32_t imm, mask; TCGv tmp, tmp2, tmp3, tmp4, tmp5; TCGv_i64 tmp64; @@ -4255,56 +4450,65 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if ((insn & (1 << 23)) == 0) { /* Three register same length. */ op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); - if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9 - || op == 10 || op == 11 || op == 16)) { - /* 64-bit element instructions. */ + /* Catch invalid op and bad size combinations: UNDEF */ + if ((neon_3r_sizes[op] & (1 << size)) == 0) { + return 1; + } + /* All insns of this form UNDEF for either this condition or the + * superset of cases "Q==1"; we catch the latter later. + */ + if (q && ((rd | rn | rm) & 1)) { + return 1; + } + if (size == 3 && op != NEON_3R_LOGIC) { + /* 64-bit element instructions. */ for (pass = 0; pass < (q ? 2 : 1); pass++) { neon_load_reg64(cpu_V0, rn + pass); neon_load_reg64(cpu_V1, rm + pass); switch (op) { - case 1: /* VQADD */ + case NEON_3R_VQADD: if (u) { gen_helper_neon_qadd_u64(cpu_V0, cpu_V0, cpu_V1); } else { gen_helper_neon_qadd_s64(cpu_V0, cpu_V0, cpu_V1); } break; - case 5: /* VQSUB */ + case NEON_3R_VQSUB: if (u) { gen_helper_neon_qsub_u64(cpu_V0, cpu_V0, cpu_V1); } else { gen_helper_neon_qsub_s64(cpu_V0, cpu_V0, cpu_V1); } break; - case 8: /* VSHL */ + case NEON_3R_VSHL: if (u) { gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 9: /* VQSHL */ + case NEON_3R_VQSHL: if (u) { gen_helper_neon_qshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_qshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 10: /* VRSHL */ + case NEON_3R_VRSHL: if (u) { gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 11: /* VQRSHL */ + case NEON_3R_VQRSHL: if (u) { gen_helper_neon_qrshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_qrshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 16: + case NEON_3R_VADD_VSUB: if (u) { tcg_gen_sub_i64(CPU_V001); } else { @@ -4318,50 +4522,76 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } return 0; } + pairwise = 0; switch (op) { - case 8: /* VSHL */ - case 9: /* VQSHL */ - case 10: /* VRSHL */ - case 11: /* VQRSHL */ + case NEON_3R_VSHL: + case NEON_3R_VQSHL: + case NEON_3R_VRSHL: + case NEON_3R_VQRSHL: { int rtmp; /* Shift instruction operands are reversed. */ rtmp = rn; rn = rm; rm = rtmp; - pairwise = 0; } break; - case 20: /* VPMAX */ - case 21: /* VPMIN */ - case 23: /* VPADD */ + case NEON_3R_VPADD: + if (u) { + return 1; + } + /* Fall through */ + case NEON_3R_VPMAX: + case NEON_3R_VPMIN: pairwise = 1; break; - case 26: /* VPADD (float) */ - pairwise = (u && size < 2); + case NEON_3R_FLOAT_ARITH: + pairwise = (u && size < 2); /* if VPADD (float) */ + break; + case NEON_3R_FLOAT_MINMAX: + pairwise = u; /* if VPMIN/VPMAX (float) */ + break; + case NEON_3R_FLOAT_CMP: + if (!u && size) { + /* no encoding for U=0 C=1x */ + return 1; + } + break; + case NEON_3R_FLOAT_ACMP: + if (!u) { + return 1; + } + break; + case NEON_3R_VRECPS_VRSQRTS: + if (u) { + return 1; + } break; - case 30: /* VPMIN/VPMAX (float) */ - pairwise = u; + case NEON_3R_VMUL: + if (u && (size != 0)) { + /* UNDEF on invalid size for polynomial subcase */ + return 1; + } break; default: - pairwise = 0; break; } + if (pairwise && q) { + /* All the pairwise insns UNDEF if Q is set */ + return 1; + } + for (pass = 0; pass < (q ? 4 : 2); pass++) { if (pairwise) { /* Pairwise. */ - if (q) - n = (pass & 1) * 2; - else - n = 0; - if (pass < q + 1) { - tmp = neon_load_reg(rn, n); - tmp2 = neon_load_reg(rn, n + 1); + if (pass < 1) { + tmp = neon_load_reg(rn, 0); + tmp2 = neon_load_reg(rn, 1); } else { - tmp = neon_load_reg(rm, n); - tmp2 = neon_load_reg(rm, n + 1); + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); } } else { /* Elementwise. */ @@ -4369,16 +4599,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case 0: /* VHADD */ + case NEON_3R_VHADD: GEN_NEON_INTEGER_OP(hadd); break; - case 1: /* VQADD */ + case NEON_3R_VQADD: GEN_NEON_INTEGER_OP(qadd); break; - case 2: /* VRHADD */ + case NEON_3R_VRHADD: GEN_NEON_INTEGER_OP(rhadd); break; - case 3: /* Logic ops. */ + case NEON_3R_LOGIC: /* Logic ops. */ switch ((u << 2) | size) { case 0: /* VAND */ tcg_gen_and_i32(tmp, tmp, tmp2); @@ -4412,81 +4642,80 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; } break; - case 4: /* VHSUB */ + case NEON_3R_VHSUB: GEN_NEON_INTEGER_OP(hsub); break; - case 5: /* VQSUB */ + case NEON_3R_VQSUB: GEN_NEON_INTEGER_OP(qsub); break; - case 6: /* VCGT */ + case NEON_3R_VCGT: GEN_NEON_INTEGER_OP(cgt); break; - case 7: /* VCGE */ + case NEON_3R_VCGE: GEN_NEON_INTEGER_OP(cge); break; - case 8: /* VSHL */ + case NEON_3R_VSHL: GEN_NEON_INTEGER_OP(shl); break; - case 9: /* VQSHL */ + case NEON_3R_VQSHL: GEN_NEON_INTEGER_OP(qshl); break; - case 10: /* VRSHL */ + case NEON_3R_VRSHL: GEN_NEON_INTEGER_OP(rshl); break; - case 11: /* VQRSHL */ + case NEON_3R_VQRSHL: GEN_NEON_INTEGER_OP(qrshl); break; - case 12: /* VMAX */ + case NEON_3R_VMAX: GEN_NEON_INTEGER_OP(max); break; - case 13: /* VMIN */ + case NEON_3R_VMIN: GEN_NEON_INTEGER_OP(min); break; - case 14: /* VABD */ + case NEON_3R_VABD: GEN_NEON_INTEGER_OP(abd); break; - case 15: /* VABA */ + case NEON_3R_VABA: GEN_NEON_INTEGER_OP(abd); tcg_temp_free_i32(tmp2); tmp2 = neon_load_reg(rd, pass); gen_neon_add(size, tmp, tmp2); break; - case 16: + case NEON_3R_VADD_VSUB: if (!u) { /* VADD */ - if (gen_neon_add(size, tmp, tmp2)) - return 1; + gen_neon_add(size, tmp, tmp2); } else { /* VSUB */ switch (size) { case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 17: + case NEON_3R_VTST_VCEQ: if (!u) { /* VTST */ switch (size) { case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } else { /* VCEQ */ switch (size) { case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 18: /* Multiply. */ + case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */ switch (size) { case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free_i32(tmp2); tmp2 = neon_load_reg(rd, pass); @@ -4496,7 +4725,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_neon_add(size, tmp, tmp2); } break; - case 19: /* VMUL */ + case NEON_3R_VMUL: if (u) { /* polynomial */ gen_helper_neon_mul_p8(tmp, tmp, tmp2); } else { /* Integer */ @@ -4504,42 +4733,40 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 20: /* VPMAX */ + case NEON_3R_VPMAX: GEN_NEON_INTEGER_OP(pmax); break; - case 21: /* VPMIN */ + case NEON_3R_VPMIN: GEN_NEON_INTEGER_OP(pmin); break; - case 22: /* Hultiply high. */ + case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high. */ if (!u) { /* VQDMULH */ switch (size) { case 1: gen_helper_neon_qdmulh_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_qdmulh_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } - } else { /* VQRDHMUL */ + } else { /* VQRDMULH */ switch (size) { case 1: gen_helper_neon_qrdmulh_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 23: /* VPADD */ - if (u) - return 1; + case NEON_3R_VPADD: switch (size) { case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } break; - case 26: /* Floating point arithnetic. */ + case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */ switch ((u << 2) | size) { case 0: /* VADD */ gen_helper_neon_add_f32(tmp, tmp, tmp2); @@ -4554,10 +4781,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_abd_f32(tmp, tmp, tmp2); break; default: - return 1; + abort(); } break; - case 27: /* Float multiply. */ + case NEON_3R_FLOAT_MULTIPLY: gen_helper_neon_mul_f32(tmp, tmp, tmp2); if (!u) { tcg_temp_free_i32(tmp2); @@ -4569,7 +4796,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } break; - case 28: /* Float compare. */ + case NEON_3R_FLOAT_CMP: if (!u) { gen_helper_neon_ceq_f32(tmp, tmp, tmp2); } else { @@ -4579,21 +4806,19 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_cgt_f32(tmp, tmp, tmp2); } break; - case 29: /* Float compare absolute. */ - if (!u) - return 1; + case NEON_3R_FLOAT_ACMP: if (size == 0) gen_helper_neon_acge_f32(tmp, tmp, tmp2); else gen_helper_neon_acgt_f32(tmp, tmp, tmp2); break; - case 30: /* Float min/max. */ + case NEON_3R_FLOAT_MINMAX: if (size == 0) gen_helper_neon_max_f32(tmp, tmp, tmp2); else gen_helper_neon_min_f32(tmp, tmp, tmp2); break; - case 31: + case NEON_3R_VRECPS_VRSQRTS: if (size == 0) gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env); else @@ -4626,7 +4851,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Two registers and shift. */ op = (insn >> 8) & 0xf; if (insn & (1 << 7)) { - /* 64-bit shift. */ + /* 64-bit shift. */ + if (op > 7) { + return 1; + } size = 3; } else { size = 2; @@ -4639,6 +4867,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if (op < 8) { /* Shift by immediate: VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */ + if (q && ((rd | rm) & 1)) { + return 1; + } + if (!u && (op == 4 || op == 6)) { + return 1; + } /* Right shifts are encoded as N - shift, where N is the element size in bits. */ if (op <= 4) @@ -4686,20 +4920,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1); break; case 4: /* VSRI */ - if (!u) - return 1; - gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); - break; case 5: /* VSHL, VSLI */ gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); break; case 6: /* VQSHLU */ - if (u) { - gen_helper_neon_qshlu_s64(cpu_V0, - cpu_V0, cpu_V1); - } else { - return 1; - } + gen_helper_neon_qshlu_s64(cpu_V0, cpu_V0, cpu_V1); break; case 7: /* VQSHL */ if (u) { @@ -4747,22 +4972,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) GEN_NEON_INTEGER_OP(rshl); break; case 4: /* VSRI */ - if (!u) - return 1; - GEN_NEON_INTEGER_OP(shl); - break; case 5: /* VSHL, VSLI */ switch (size) { case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } break; case 6: /* VQSHLU */ - if (!u) { - return 1; - } switch (size) { case 0: gen_helper_neon_qshlu_s8(tmp, tmp, tmp2); @@ -4774,7 +4992,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_qshlu_s32(tmp, tmp, tmp2); break; default: - return 1; + abort(); } break; case 7: /* VQSHL */ @@ -4832,7 +5050,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Shift by immediate and narrow: VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ int input_unsigned = (op == 8) ? !u : u; - + if (rm & 1) { + return 1; + } shift = shift - (1 << (size + 3)); size++; if (size == 3) { @@ -4900,9 +5120,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp2); } } else if (op == 10) { - /* VSHLL */ - if (q || size == 3) + /* VSHLL, VMOVL */ + if (q || (rd & 1)) { return 1; + } tmp = neon_load_reg(rm, 0); tmp2 = neon_load_reg(rm, 1); for (pass = 0; pass < 2; pass++) { @@ -4943,6 +5164,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else if (op >= 14) { /* VCVT fixed-point. */ + if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) { + return 1; + } /* We have already masked out the must-be-1 top bit of imm6, * hence this 32-shift where the ARM ARM has 64-imm6. */ @@ -4967,11 +5191,18 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else { /* (insn & 0x00380080) == 0 */ int invert; + if (q && (rd & 1)) { + return 1; + } op = (insn >> 8) & 0xf; /* One register and immediate. */ imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf); invert = (insn & (1 << 5)) != 0; + /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. + * We choose to not special-case this and will behave as if a + * valid constant encoding of 0 had been given. + */ switch (op) { case 0: case 1: /* no-op */ @@ -5003,6 +5234,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) imm = ~imm; break; case 15: + if (invert) { + return 1; + } imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); break; @@ -5024,6 +5258,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* VMOV, VMVN. */ tmp = tcg_temp_new_i32(); if (op == 14 && invert) { + int n; uint32_t val; val = 0; for (n = 0; n < 4; n++) { @@ -5046,31 +5281,47 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) int src1_wide; int src2_wide; int prewiden; - /* prewiden, src1_wide, src2_wide */ - static const int neon_3reg_wide[16][3] = { - {1, 0, 0}, /* VADDL */ - {1, 1, 0}, /* VADDW */ - {1, 0, 0}, /* VSUBL */ - {1, 1, 0}, /* VSUBW */ - {0, 1, 1}, /* VADDHN */ - {0, 0, 0}, /* VABAL */ - {0, 1, 1}, /* VSUBHN */ - {0, 0, 0}, /* VABDL */ - {0, 0, 0}, /* VMLAL */ - {0, 0, 0}, /* VQDMLAL */ - {0, 0, 0}, /* VMLSL */ - {0, 0, 0}, /* VQDMLSL */ - {0, 0, 0}, /* Integer VMULL */ - {0, 0, 0}, /* VQDMULL */ - {0, 0, 0} /* Polynomial VMULL */ + /* undefreq: bit 0 : UNDEF if size != 0 + * bit 1 : UNDEF if size == 0 + * bit 2 : UNDEF if U == 1 + * Note that [1:0] set implies 'always UNDEF' + */ + int undefreq; + /* prewiden, src1_wide, src2_wide, undefreq */ + static const int neon_3reg_wide[16][4] = { + {1, 0, 0, 0}, /* VADDL */ + {1, 1, 0, 0}, /* VADDW */ + {1, 0, 0, 0}, /* VSUBL */ + {1, 1, 0, 0}, /* VSUBW */ + {0, 1, 1, 0}, /* VADDHN */ + {0, 0, 0, 0}, /* VABAL */ + {0, 1, 1, 0}, /* VSUBHN */ + {0, 0, 0, 0}, /* VABDL */ + {0, 0, 0, 0}, /* VMLAL */ + {0, 0, 0, 6}, /* VQDMLAL */ + {0, 0, 0, 0}, /* VMLSL */ + {0, 0, 0, 6}, /* VQDMLSL */ + {0, 0, 0, 0}, /* Integer VMULL */ + {0, 0, 0, 2}, /* VQDMULL */ + {0, 0, 0, 5}, /* Polynomial VMULL */ + {0, 0, 0, 3}, /* Reserved: always UNDEF */ }; prewiden = neon_3reg_wide[op][0]; src1_wide = neon_3reg_wide[op][1]; src2_wide = neon_3reg_wide[op][2]; + undefreq = neon_3reg_wide[op][3]; - if (size == 0 && (op == 9 || op == 11 || op == 13)) + if (((undefreq & 1) && (size != 0)) || + ((undefreq & 2) && (size == 0)) || + ((undefreq & 4) && u)) { + return 1; + } + if ((src1_wide && (rn & 1)) || + (src2_wide && (rm & 1)) || + (!src2_wide && (rd & 1))) { return 1; + } /* Avoid overlapping operands. Wide source operands are always aligned so will never overlap with wide @@ -5151,8 +5402,8 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp2); tcg_temp_free_i32(tmp); break; - default: /* 15 is RESERVED. */ - return 1; + default: /* 15 is RESERVED: caught earlier */ + abort(); } if (op == 13) { /* VQDMULL */ @@ -5224,16 +5475,29 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } } else { - /* Two registers and a scalar. */ + /* Two registers and a scalar. NB that for ops of this form + * the ARM ARM labels bit 24 as Q, but it is in our variable + * 'u', not 'q'. + */ + if (size == 0) { + return 1; + } switch (op) { - case 0: /* Integer VMLA scalar */ case 1: /* Float VMLA scalar */ - case 4: /* Integer VMLS scalar */ case 5: /* Floating point VMLS scalar */ - case 8: /* Integer VMUL scalar */ case 9: /* Floating point VMUL scalar */ + if (size == 1) { + return 1; + } + /* fall through */ + case 0: /* Integer VMLA scalar */ + case 4: /* Integer VMLS scalar */ + case 8: /* Integer VMUL scalar */ case 12: /* VQDMULH scalar */ case 13: /* VQRDMULH scalar */ + if (u && ((rd | rn) & 1)) { + return 1; + } tmp = neon_get_scalar(size, rm); neon_store_scratch(0, tmp); for (pass = 0; pass < (u ? 4 : 2); pass++) { @@ -5258,7 +5522,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } tcg_temp_free_i32(tmp2); @@ -5286,15 +5550,19 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg(rd, pass, tmp); } break; - case 2: /* VMLAL sclar */ case 3: /* VQDMLAL scalar */ - case 6: /* VMLSL scalar */ case 7: /* VQDMLSL scalar */ - case 10: /* VMULL scalar */ case 11: /* VQDMULL scalar */ - if (size == 0 && (op == 3 || op == 7 || op == 11)) + if (u == 1) { return 1; - + } + /* fall through */ + case 2: /* VMLAL sclar */ + case 6: /* VMLSL scalar */ + case 10: /* VMULL scalar */ + if (rd & 1) { + return 1; + } tmp2 = neon_get_scalar(size, rm); /* We need a copy of tmp2 because gen_neon_mull * deletes it during pass 0. */ @@ -5353,6 +5621,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if (imm > 7 && !q) return 1; + if (q && ((rd | rn | rm) & 1)) { + return 1; + } + if (imm == 0) { neon_load_reg64(cpu_V0, rn); if (q) { @@ -5401,10 +5673,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Two register misc. */ op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); size = (insn >> 18) & 3; + /* UNDEF for unknown op values and bad op-size combinations */ + if ((neon_2rm_sizes[op] & (1 << size)) == 0) { + return 1; + } + if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) && + q && ((rm | rd) & 1)) { + return 1; + } switch (op) { - case 0: /* VREV64 */ - if (size == 3) - return 1; + case NEON_2RM_VREV64: for (pass = 0; pass < (q ? 2 : 1); pass++) { tmp = neon_load_reg(rm, pass * 2); tmp2 = neon_load_reg(rm, pass * 2 + 1); @@ -5427,10 +5705,8 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } break; - case 4: case 5: /* VPADDL */ - case 12: case 13: /* VPADAL */ - if (size == 3) - return 1; + case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: + case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: for (pass = 0; pass < q + 1; pass++) { tmp = neon_load_reg(rm, pass * 2); gen_neon_widen(cpu_V0, tmp, size, op & 1); @@ -5442,7 +5718,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 2: tcg_gen_add_i64(CPU_V001); break; default: abort(); } - if (op >= 12) { + if (op >= NEON_2RM_VPADAL) { /* Accumulate. */ neon_load_reg64(cpu_V1, rd + pass); gen_neon_addl(size); @@ -5450,8 +5726,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg64(cpu_V0, rd + pass); } break; - case 33: /* VTRN */ + case NEON_2RM_VTRN: if (size == 2) { + int n; for (n = 0; n < (q ? 4 : 2); n += 2) { tmp = neon_load_reg(rm, n); tmp2 = neon_load_reg(rd, n + 1); @@ -5462,24 +5739,27 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) goto elementwise; } break; - case 34: /* VUZP */ + case NEON_2RM_VUZP: if (gen_neon_unzip(rd, rm, size, q)) { return 1; } break; - case 35: /* VZIP */ + case NEON_2RM_VZIP: if (gen_neon_zip(rd, rm, size, q)) { return 1; } break; - case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */ - if (size == 3) + case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: + /* also VQMOVUN; op field and mnemonics don't line up */ + if (rm & 1) { return 1; + } TCGV_UNUSED(tmp2); for (pass = 0; pass < 2; pass++) { neon_load_reg64(cpu_V0, rm + pass); tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == 36, q, size, tmp, cpu_V0); + gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size, + tmp, cpu_V0); if (pass == 0) { tmp2 = tmp; } else { @@ -5488,9 +5768,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } break; - case 38: /* VSHLL */ - if (q || size == 3) + case NEON_2RM_VSHLL: + if (q || (rd & 1)) { return 1; + } tmp = neon_load_reg(rm, 0); tmp2 = neon_load_reg(rm, 1); for (pass = 0; pass < 2; pass++) { @@ -5501,9 +5782,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg64(cpu_V0, rd + pass); } break; - case 44: /* VCVT.F16.F32 */ - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; + case NEON_2RM_VCVT_F16_F32: + if (!arm_feature(env, ARM_FEATURE_VFP_FP16) || + q || (rm & 1)) { + return 1; + } tmp = tcg_temp_new_i32(); tmp2 = tcg_temp_new_i32(); tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0)); @@ -5523,9 +5806,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg(rd, 1, tmp2); tcg_temp_free_i32(tmp); break; - case 46: /* VCVT.F32.F16 */ - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; + case NEON_2RM_VCVT_F32_F16: + if (!arm_feature(env, ARM_FEATURE_VFP_FP16) || + q || (rd & 1)) { + return 1; + } tmp3 = tcg_temp_new_i32(); tmp = neon_load_reg(rm, 0); tmp2 = neon_load_reg(rm, 1); @@ -5548,7 +5833,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) default: elementwise: for (pass = 0; pass < (q ? 4 : 2); pass++) { - if (op == 30 || op == 31 || op >= 58) { + if (neon_2rm_is_float_op(op)) { tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); TCGV_UNUSED(tmp); @@ -5556,183 +5841,178 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tmp = neon_load_reg(rm, pass); } switch (op) { - case 1: /* VREV32 */ + case NEON_2RM_VREV32: switch (size) { case 0: tcg_gen_bswap32_i32(tmp, tmp); break; case 1: gen_swap_half(tmp); break; - default: return 1; + default: abort(); } break; - case 2: /* VREV16 */ - if (size != 0) - return 1; + case NEON_2RM_VREV16: gen_rev16(tmp); break; - case 8: /* CLS */ + case NEON_2RM_VCLS: switch (size) { case 0: gen_helper_neon_cls_s8(tmp, tmp); break; case 1: gen_helper_neon_cls_s16(tmp, tmp); break; case 2: gen_helper_neon_cls_s32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 9: /* CLZ */ + case NEON_2RM_VCLZ: switch (size) { case 0: gen_helper_neon_clz_u8(tmp, tmp); break; case 1: gen_helper_neon_clz_u16(tmp, tmp); break; case 2: gen_helper_clz(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 10: /* CNT */ - if (size != 0) - return 1; + case NEON_2RM_VCNT: gen_helper_neon_cnt_u8(tmp, tmp); break; - case 11: /* VNOT */ - if (size != 0) - return 1; + case NEON_2RM_VMVN: tcg_gen_not_i32(tmp, tmp); break; - case 14: /* VQABS */ + case NEON_2RM_VQABS: switch (size) { case 0: gen_helper_neon_qabs_s8(tmp, tmp); break; case 1: gen_helper_neon_qabs_s16(tmp, tmp); break; case 2: gen_helper_neon_qabs_s32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 15: /* VQNEG */ + case NEON_2RM_VQNEG: switch (size) { case 0: gen_helper_neon_qneg_s8(tmp, tmp); break; case 1: gen_helper_neon_qneg_s16(tmp, tmp); break; case 2: gen_helper_neon_qneg_s32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 16: case 19: /* VCGT #0, VCLE #0 */ + case NEON_2RM_VCGT0: case NEON_2RM_VCLE0: tmp2 = tcg_const_i32(0); switch(size) { case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free(tmp2); - if (op == 19) + if (op == NEON_2RM_VCLE0) { tcg_gen_not_i32(tmp, tmp); + } break; - case 17: case 20: /* VCGE #0, VCLT #0 */ + case NEON_2RM_VCGE0: case NEON_2RM_VCLT0: tmp2 = tcg_const_i32(0); switch(size) { case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free(tmp2); - if (op == 20) + if (op == NEON_2RM_VCLT0) { tcg_gen_not_i32(tmp, tmp); + } break; - case 18: /* VCEQ #0 */ + case NEON_2RM_VCEQ0: tmp2 = tcg_const_i32(0); switch(size) { case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free(tmp2); break; - case 22: /* VABS */ + case NEON_2RM_VABS: switch(size) { case 0: gen_helper_neon_abs_s8(tmp, tmp); break; case 1: gen_helper_neon_abs_s16(tmp, tmp); break; case 2: tcg_gen_abs_i32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 23: /* VNEG */ - if (size == 3) - return 1; + case NEON_2RM_VNEG: tmp2 = tcg_const_i32(0); gen_neon_rsb(size, tmp, tmp2); tcg_temp_free(tmp2); break; - case 24: /* Float VCGT #0 */ + case NEON_2RM_VCGT0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cgt_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); break; - case 25: /* Float VCGE #0 */ + case NEON_2RM_VCGE0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cge_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); break; - case 26: /* Float VCEQ #0 */ + case NEON_2RM_VCEQ0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_ceq_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); break; - case 27: /* Float VCLE #0 */ + case NEON_2RM_VCLE0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cge_f32(tmp, tmp2, tmp); tcg_temp_free(tmp2); break; - case 28: /* Float VCLT #0 */ + case NEON_2RM_VCLT0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cgt_f32(tmp, tmp2, tmp); tcg_temp_free(tmp2); break; - case 30: /* Float VABS */ + case NEON_2RM_VABS_F: gen_vfp_abs(0); break; - case 31: /* Float VNEG */ + case NEON_2RM_VNEG_F: gen_vfp_neg(0); break; - case 32: /* VSWP */ + case NEON_2RM_VSWP: tmp2 = neon_load_reg(rd, pass); neon_store_reg(rm, pass, tmp2); break; - case 33: /* VTRN */ + case NEON_2RM_VTRN: tmp2 = neon_load_reg(rd, pass); switch (size) { case 0: gen_neon_trn_u8(tmp, tmp2); break; case 1: gen_neon_trn_u16(tmp, tmp2); break; - case 2: abort(); - default: return 1; + default: abort(); } neon_store_reg(rm, pass, tmp2); break; - case 56: /* Integer VRECPE */ + case NEON_2RM_VRECPE: gen_helper_recpe_u32(tmp, tmp, cpu_env); break; - case 57: /* Integer VRSQRTE */ + case NEON_2RM_VRSQRTE: gen_helper_rsqrte_u32(tmp, tmp, cpu_env); break; - case 58: /* Float VRECPE */ + case NEON_2RM_VRECPE_F: gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env); break; - case 59: /* Float VRSQRTE */ + case NEON_2RM_VRSQRTE_F: gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env); break; - case 60: /* VCVT.F32.S32 */ + case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */ gen_vfp_sito(0); break; - case 61: /* VCVT.F32.U32 */ + case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */ gen_vfp_uito(0); break; - case 62: /* VCVT.S32.F32 */ + case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */ gen_vfp_tosiz(0); break; - case 63: /* VCVT.U32.F32 */ + case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */ gen_vfp_touiz(0); break; default: - /* Reserved: 21, 29, 39-56 */ - return 1; + /* Reserved op values were caught by the + * neon_2rm_sizes[] check earlier. + */ + abort(); } - if (op == 30 || op == 31 || op >= 58) { + if (neon_2rm_is_float_op(op)) { tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass)); } else { @@ -5743,7 +6023,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else if ((insn & (1 << 10)) == 0) { /* VTBL, VTBX. */ - n = ((insn >> 5) & 0x18) + 8; + int n = ((insn >> 8) & 3) + 1; + if ((rn + n) > 32) { + /* This is UNPREDICTABLE; we choose to UNDEF to avoid the + * helper function running off the end of the register file. + */ + return 1; + } + n <<= 3; if (insn & (1 << 6)) { tmp = neon_load_reg(rd, 0); } else { @@ -5770,6 +6057,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp); } else if ((insn & 0x380) == 0) { /* VDUP */ + if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) { + return 1; + } if (insn & (1 << 19)) { tmp = neon_load_reg(rm, 1); } else { @@ -6127,6 +6417,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; cond = insn >> 28; if (cond == 0xf){ + /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we + * choose to UNDEF. In ARMv5 and above the space is used + * for miscellaneous unconditional instructions. + */ + ARCH(5); + /* Unconditional instructions. */ if (((insn >> 25) & 7) == 1) { /* NEON Data processing. */ @@ -6155,6 +6451,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } } /* Otherwise PLD; v5TE+ */ + ARCH(5TE); return; } if (((insn & 0x0f70f000) == 0x0450f000) || @@ -6291,6 +6588,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) val += (offset << 2) | ((insn >> 23) & 2) | 1; /* pipeline offset */ val += 4; + /* protected by ARCH(5); above, near the start of uncond block */ gen_bx_im(s, val); return; } else if ((insn & 0x0e000f00) == 0x0c000100) { @@ -6302,6 +6600,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } } else if ((insn & 0x0fe00000) == 0x0c400000) { /* Coprocessor double register transfer. */ + ARCH(5TE); } else if ((insn & 0x0f000010) == 0x0e000010) { /* Additional coprocessor register transfer. */ } else if ((insn & 0x0ff10020) == 0x01000000) { @@ -6402,10 +6701,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0x1: if (op1 == 1) { /* branch/exchange thumb (bx). */ + ARCH(4T); tmp = load_reg(s, rm); gen_bx(s, tmp); } else if (op1 == 3) { /* clz */ + ARCH(5); rd = (insn >> 12) & 0xf; tmp = load_reg(s, rm); gen_helper_clz(tmp, tmp); @@ -6428,6 +6729,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (op1 != 1) goto illegal_op; + ARCH(5); /* branch link/exchange thumb (blx) */ tmp = load_reg(s, rm); tmp2 = tcg_temp_new_i32(); @@ -6436,6 +6738,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_bx(s, tmp); break; case 0x5: /* saturating add/subtract */ + ARCH(5TE); rd = (insn >> 12) & 0xf; rn = (insn >> 16) & 0xf; tmp = load_reg(s, rm); @@ -6457,12 +6760,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; } /* bkpt */ + ARCH(5); gen_exception_insn(s, 4, EXCP_BKPT); break; case 0x8: /* signed multiply */ case 0xa: case 0xc: case 0xe: + ARCH(5TE); rs = (insn >> 8) & 0xf; rn = (insn >> 12) & 0xf; rd = (insn >> 16) & 0xf; @@ -6858,6 +7163,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } load = 1; } else if (sh & 2) { + ARCH(5TE); /* doubleword */ if (sh & 1) { /* store */ @@ -7198,10 +7504,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } if (insn & (1 << 20)) { /* Complete the load. */ - if (rd == 15) - gen_bx(s, tmp); - else - store_reg(s, rd, tmp); + store_reg_from_load(env, s, rd, tmp); } break; case 0x08: @@ -7254,9 +7557,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (insn & (1 << 20)) { /* load */ tmp = gen_ld32(addr, IS_USER(s)); - if (i == 15) { - gen_bx(s, tmp); - } else if (user) { + if (user) { tmp2 = tcg_const_i32(i); gen_helper_set_user_reg(tmp2, tmp); tcg_temp_free_i32(tmp2); @@ -7265,7 +7566,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) loaded_var = tmp; loaded_base = 1; } else { - store_reg(s, i, tmp); + store_reg_from_load(env, s, i, tmp); } } else { /* store */ @@ -7465,6 +7766,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) 16-bit instructions to get correct prefetch abort behavior. */ insn = insn_hw1; if ((insn & (1 << 12)) == 0) { + ARCH(5); /* Second half of blx. */ offset = ((insn & 0x7ff) << 1); tmp = load_reg(s, 14); @@ -8061,6 +8363,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } else { /* blx */ offset &= ~(uint32_t)2; + /* thumb2 bx, no need to check */ gen_bx_im(s, offset); } } else if (((insn >> 23) & 7) == 7) { @@ -8642,11 +8945,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) case 3:/* branch [and link] exchange thumb register */ tmp = load_reg(s, rm); if (insn & (1 << 7)) { + ARCH(5); val = (uint32_t)s->pc | 1; tmp2 = tcg_temp_new_i32(); tcg_gen_movi_i32(tmp2, val); store_reg(s, 14, tmp2); } + /* already thumb, no need to check */ gen_bx(s, tmp); break; } @@ -9006,8 +9311,9 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) /* write back the new stack pointer */ store_reg(s, 13, addr); /* set the new PC value */ - if ((insn & 0x0900) == 0x0900) - gen_bx(s, tmp); + if ((insn & 0x0900) == 0x0900) { + store_reg_from_load(env, s, 15, tmp); + } break; case 1: case 3: case 9: case 11: /* czb */ @@ -9038,6 +9344,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) break; case 0xe: /* bkpt */ + ARCH(5); gen_exception_insn(s, 2, EXCP_BKPT); break; @@ -9244,8 +9551,8 @@ static inline void gen_intermediate_code_internal(CPUState *env, * This is handled in the same way as restoration of the * PC in these situations: we will be called again with search_pc=1 * and generate a mapping of the condexec bits for each PC in - * gen_opc_condexec_bits[]. gen_pc_load[] then uses this to restore - * the condexec bits. + * gen_opc_condexec_bits[]. restore_state_to_opc() then uses + * this to restore the condexec bits. * * Note that there are no instructions which can read the condexec * bits, and none which can write non-static values to them, so @@ -9510,8 +9817,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, #endif } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->regs[15] = gen_opc_pc[pc_pos]; env->condexec_bits = gen_opc_condexec_bits[pc_pos]; diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index be9eb06..34329e2 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -77,7 +77,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); /* Evaluate flags after retranslation. */ helper_top_evaluate_flags(); diff --git a/target-cris/translate.c b/target-cris/translate.c index b4648a0..e2607d6 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -596,7 +596,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(env_pc, dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(env_pc, dest); tcg_gen_exit_tb(0); @@ -3604,8 +3604,7 @@ void cpu_reset (CPUCRISState *env) #endif } -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-i386/exec.h b/target-i386/exec.h index 6f9f709..ee36a71 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -110,11 +110,24 @@ static inline void svm_check_intercept(uint32_t type) #define float64_to_floatx float64_to_floatx80 #define floatx_to_float32 floatx80_to_float32 #define floatx_to_float64 floatx80_to_float64 +#define floatx_add floatx80_add +#define floatx_div floatx80_div +#define floatx_mul floatx80_mul +#define floatx_sub floatx80_sub +#define floatx_sqrt floatx80_sqrt #define floatx_abs floatx80_abs #define floatx_chs floatx80_chs +#define floatx_scalbn floatx80_scalbn #define floatx_round_to_int floatx80_round_to_int #define floatx_compare floatx80_compare #define floatx_compare_quiet floatx80_compare_quiet +#define floatx_is_any_nan floatx80_is_any_nan +#define floatx_is_neg floatx80_is_neg +#define floatx_is_zero floatx80_is_zero +#define floatx_zero floatx80_zero +#define floatx_one floatx80_one +#define floatx_ln2 floatx80_ln2 +#define floatx_pi floatx80_pi #else #define floatx_to_int32 float64_to_int32 #define floatx_to_int64 float64_to_int64 @@ -126,11 +139,24 @@ static inline void svm_check_intercept(uint32_t type) #define float64_to_floatx(x, e) (x) #define floatx_to_float32 float64_to_float32 #define floatx_to_float64(x, e) (x) +#define floatx_add float64_add +#define floatx_div float64_div +#define floatx_mul float64_mul +#define floatx_sub float64_sub +#define floatx_sqrt float64_sqrt #define floatx_abs float64_abs #define floatx_chs float64_chs +#define floatx_scalbn float64_scalbn #define floatx_round_to_int float64_round_to_int #define floatx_compare float64_compare #define floatx_compare_quiet float64_compare_quiet +#define floatx_is_any_nan float64_is_any_nan +#define floatx_is_neg float64_is_neg +#define floatx_is_zero float64_is_zero +#define floatx_zero float64_zero +#define floatx_one float64_one +#define floatx_ln2 float64_ln2 +#define floatx_pi float64_pi #endif #define RC_MASK 0xc00 @@ -144,13 +170,7 @@ static inline void svm_check_intercept(uint32_t type) #ifdef USE_X86LDOUBLE /* only for x86 */ -typedef union { - long double d; - struct { - unsigned long long lower; - unsigned short upper; - } l; -} CPU86_LDoubleU; +typedef CPU_LDoubleU CPU86_LDoubleU; /* the following deal with x86 long double-precision numbers */ #define MAXEXPD 0x7fff @@ -162,24 +182,7 @@ typedef union { #else -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ -typedef union { - double d; -#if !defined(HOST_WORDS_BIGENDIAN) && !defined(__arm__) - struct { - uint32_t lower; - int32_t upper; - } l; -#else - struct { - int32_t upper; - uint32_t lower; - } l; -#endif -#ifndef __arm__ - int64_t ll; -#endif -} CPU86_LDoubleU; +typedef CPU_DoubleU CPU86_LDoubleU; /* the following deal with IEEE double-precision numbers */ #define MAXEXPD 0x7ff diff --git a/target-i386/helper.c b/target-i386/helper.c index d15fca5..89df997 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -404,16 +404,10 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, env->mxcsr); for(i=0;i<8;i++) { #if defined(USE_X86LDOUBLE) - union { - long double d; - struct { - uint64_t lower; - uint16_t upper; - } l; - } tmp; - tmp.d = env->fpregs[i].d; + CPU_LDoubleU u; + u.d = env->fpregs[i].d; cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", - i, tmp.l.lower, tmp.l.upper); + i, u.l.lower, u.l.upper); #else cpu_fprintf(f, "FPR%d=%016" PRIx64, i, env->fpregs[i].mmx.q); diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 43fbd0c..3c539f3 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include <math.h> #include "exec.h" #include "exec-all.h" #include "host-utils.h" @@ -94,15 +95,25 @@ static const uint8_t rclb_table[32] = { 6, 7, 8, 0, 1, 2, 3, 4, }; +#if defined(CONFIG_SOFTFLOAT) +# define floatx_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL ) +# define floatx_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL ) +# define floatx_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL ) +#else +# define floatx_lg2 (0.30102999566398119523L) +# define floatx_l2e (1.44269504088896340739L) +# define floatx_l2t (3.32192809488736234781L) +#endif + static const CPU86_LDouble f15rk[7] = { - 0.00000000000000000000L, - 1.00000000000000000000L, - 3.14159265358979323851L, /*pi*/ - 0.30102999566398119523L, /*lg2*/ - 0.69314718055994530943L, /*ln2*/ - 1.44269504088896340739L, /*l2e*/ - 3.32192809488736234781L, /*l2t*/ + floatx_zero, + floatx_one, + floatx_pi, + floatx_lg2, + floatx_ln2, + floatx_l2e, + floatx_l2t, }; /* broken thread support */ @@ -3431,6 +3442,28 @@ void helper_verw(target_ulong selector1) /* x87 FPU helpers */ +static inline double CPU86_LDouble_to_double(CPU86_LDouble a) +{ + union { + float64 f64; + double d; + } u; + + u.f64 = floatx_to_float64(a, &env->fp_status); + return u.d; +} + +static inline CPU86_LDouble double_to_CPU86_LDouble(double a) +{ + union { + float64 f64; + double d; + } u; + + u.d = a; + return float64_to_floatx(u.f64, &env->fp_status); +} + static void fpu_set_exception(int mask) { env->fpus |= mask; @@ -3440,9 +3473,10 @@ static void fpu_set_exception(int mask) static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) { - if (b == 0.0) + if (floatx_is_zero(b)) { fpu_set_exception(FPUS_ZE); - return a / b; + } + return floatx_div(a, b, &env->fp_status); } static void fpu_raise_exception(void) @@ -3711,22 +3745,22 @@ void helper_fucomi_ST0_FT0(void) void helper_fadd_ST0_FT0(void) { - ST0 += FT0; + ST0 = floatx_add(ST0, FT0, &env->fp_status); } void helper_fmul_ST0_FT0(void) { - ST0 *= FT0; + ST0 = floatx_mul(ST0, FT0, &env->fp_status); } void helper_fsub_ST0_FT0(void) { - ST0 -= FT0; + ST0 = floatx_sub(ST0, FT0, &env->fp_status); } void helper_fsubr_ST0_FT0(void) { - ST0 = FT0 - ST0; + ST0 = floatx_sub(FT0, ST0, &env->fp_status); } void helper_fdiv_ST0_FT0(void) @@ -3743,24 +3777,22 @@ void helper_fdivr_ST0_FT0(void) void helper_fadd_STN_ST0(int st_index) { - ST(st_index) += ST0; + ST(st_index) = floatx_add(ST(st_index), ST0, &env->fp_status); } void helper_fmul_STN_ST0(int st_index) { - ST(st_index) *= ST0; + ST(st_index) = floatx_mul(ST(st_index), ST0, &env->fp_status); } void helper_fsub_STN_ST0(int st_index) { - ST(st_index) -= ST0; + ST(st_index) = floatx_sub(ST(st_index), ST0, &env->fp_status); } void helper_fsubr_STN_ST0(int st_index) { - CPU86_LDouble *p; - p = &ST(st_index); - *p = ST0 - *p; + ST(st_index) = floatx_sub(ST0, ST(st_index), &env->fp_status); } void helper_fdiv_STN_ST0(int st_index) @@ -3922,9 +3954,10 @@ void helper_fbld_ST0(target_ulong ptr) v = ldub(ptr + i); val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); } - tmp = val; - if (ldub(ptr + 9) & 0x80) - tmp = -tmp; + tmp = int64_to_floatx(val, &env->fp_status); + if (ldub(ptr + 9) & 0x80) { + floatx_chs(tmp); + } fpush(); ST0 = tmp; } @@ -3959,17 +3992,19 @@ void helper_fbst_ST0(target_ulong ptr) void helper_f2xm1(void) { - ST0 = pow(2.0,ST0) - 1.0; + double val = CPU86_LDouble_to_double(ST0); + val = pow(2.0, val) - 1.0; + ST0 = double_to_CPU86_LDouble(val); } void helper_fyl2x(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if (fptemp>0.0){ - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ - ST1 *= fptemp; + fptemp = log(fptemp)/log(2.0); /* log2(ST) */ + fptemp *= CPU86_LDouble_to_double(ST1); + ST1 = double_to_CPU86_LDouble(fptemp); fpop(); } else { env->fpus &= (~0x4700); @@ -3979,15 +4014,15 @@ void helper_fyl2x(void) void helper_fptan(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = tan(fptemp); + fptemp = tan(fptemp); + ST0 = double_to_CPU86_LDouble(fptemp); fpush(); - ST0 = 1.0; + ST0 = floatx_one; env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg| < 2**52 only */ } @@ -3995,45 +4030,57 @@ void helper_fptan(void) void helper_fpatan(void) { - CPU86_LDouble fptemp, fpsrcop; + double fptemp, fpsrcop; - fpsrcop = ST1; - fptemp = ST0; - ST1 = atan2(fpsrcop,fptemp); + fpsrcop = CPU86_LDouble_to_double(ST1); + fptemp = CPU86_LDouble_to_double(ST0); + ST1 = double_to_CPU86_LDouble(atan2(fpsrcop, fptemp)); fpop(); } void helper_fxtract(void) { CPU86_LDoubleU temp; - unsigned int expdif; temp.d = ST0; - expdif = EXPD(temp) - EXPBIAS; - /*DP exponent bias*/ - ST0 = expdif; - fpush(); - BIASEXPONENT(temp); - ST0 = temp.d; + + if (floatx_is_zero(ST0)) { + /* Easy way to generate -inf and raising division by 0 exception */ + ST0 = floatx_div(floatx_chs(floatx_one), floatx_zero, &env->fp_status); + fpush(); + ST0 = temp.d; + } else { + int expdif; + + expdif = EXPD(temp) - EXPBIAS; + /*DP exponent bias*/ + ST0 = int32_to_floatx(expdif, &env->fp_status); + fpush(); + BIASEXPONENT(temp); + ST0 = temp.d; + } } void helper_fprem1(void) { - CPU86_LDouble dblq, fpsrcop, fptemp; + double st0, st1, dblq, fpsrcop, fptemp; CPU86_LDoubleU fpsrcop1, fptemp1; int expdif; signed long long int q; - if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { - ST0 = 0.0 / 0.0; /* NaN */ + st0 = CPU86_LDouble_to_double(ST0); + st1 = CPU86_LDouble_to_double(ST1); + + if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) { + ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ return; } - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; + fpsrcop = st0; + fptemp = st1; + fpsrcop1.d = ST0; + fptemp1.d = ST1; expdif = EXPD(fpsrcop1) - EXPD(fptemp1); if (expdif < 0) { @@ -4047,7 +4094,7 @@ void helper_fprem1(void) dblq = fpsrcop / fptemp; /* round dblq towards nearest integer */ dblq = rint(dblq); - ST0 = fpsrcop - fptemp * dblq; + st0 = fpsrcop - fptemp * dblq; /* convert dblq to q by truncating towards zero */ if (dblq < 0.0) @@ -4063,31 +4110,35 @@ void helper_fprem1(void) } else { env->fpus |= 0x400; /* C2 <-- 1 */ fptemp = pow(2.0, expdif - 50); - fpsrcop = (ST0 / ST1) / fptemp; + fpsrcop = (st0 / st1) / fptemp; /* fpsrcop = integer obtained by chopping */ fpsrcop = (fpsrcop < 0.0) ? -(floor(fabs(fpsrcop))) : floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); + st0 -= (st1 * fpsrcop * fptemp); } + ST0 = double_to_CPU86_LDouble(st0); } void helper_fprem(void) { - CPU86_LDouble dblq, fpsrcop, fptemp; + double st0, st1, dblq, fpsrcop, fptemp; CPU86_LDoubleU fpsrcop1, fptemp1; int expdif; signed long long int q; - if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { - ST0 = 0.0 / 0.0; /* NaN */ + st0 = CPU86_LDouble_to_double(ST0); + st1 = CPU86_LDouble_to_double(ST1); + + if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) { + ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ return; } - fpsrcop = (CPU86_LDouble)ST0; - fptemp = (CPU86_LDouble)ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; + fpsrcop = st0; + fptemp = st1; + fpsrcop1.d = ST0; + fptemp1.d = ST1; expdif = EXPD(fpsrcop1) - EXPD(fptemp1); if (expdif < 0) { @@ -4101,7 +4152,7 @@ void helper_fprem(void) dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/; /* round dblq towards zero */ dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); - ST0 = fpsrcop/*ST0*/ - fptemp * dblq; + st0 = fpsrcop/*ST0*/ - fptemp * dblq; /* convert dblq to q by truncating towards zero */ if (dblq < 0.0) @@ -4118,22 +4169,23 @@ void helper_fprem(void) int N = 32 + (expdif % 32); /* as per AMD docs */ env->fpus |= 0x400; /* C2 <-- 1 */ fptemp = pow(2.0, (double)(expdif - N)); - fpsrcop = (ST0 / ST1) / fptemp; + fpsrcop = (st0 / st1) / fptemp; /* fpsrcop = integer obtained by chopping */ fpsrcop = (fpsrcop < 0.0) ? -(floor(fabs(fpsrcop))) : floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); + st0 -= (st1 * fpsrcop * fptemp); } + ST0 = double_to_CPU86_LDouble(st0); } void helper_fyl2xp1(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if ((fptemp+1.0)>0.0) { fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ - ST1 *= fptemp; + fptemp *= CPU86_LDouble_to_double(ST1); + ST1 = double_to_CPU86_LDouble(fptemp); fpop(); } else { env->fpus &= (~0x4700); @@ -4143,27 +4195,23 @@ void helper_fyl2xp1(void) void helper_fsqrt(void) { - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp<0.0) { + if (floatx_is_neg(ST0)) { env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ env->fpus |= 0x400; } - ST0 = sqrt(fptemp); + ST0 = floatx_sqrt(ST0, &env->fp_status); } void helper_fsincos(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = sin(fptemp); + ST0 = double_to_CPU86_LDouble(sin(fptemp)); fpush(); - ST0 = cos(fptemp); + ST0 = double_to_CPU86_LDouble(cos(fptemp)); env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg| < 2**63 only */ } @@ -4176,18 +4224,22 @@ void helper_frndint(void) void helper_fscale(void) { - ST0 = ldexp (ST0, (int)(ST1)); + if (floatx_is_any_nan(ST1)) { + ST0 = ST1; + } else { + int n = floatx_to_int32_round_to_zero(ST1, &env->fp_status); + ST0 = floatx_scalbn(ST0, n, &env->fp_status); + } } void helper_fsin(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = sin(fptemp); + ST0 = double_to_CPU86_LDouble(sin(fptemp)); env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg| < 2**53 only */ } @@ -4195,13 +4247,12 @@ void helper_fsin(void) void helper_fcos(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = cos(fptemp); + ST0 = double_to_CPU86_LDouble(cos(fptemp)); env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg5 < 2**63 only */ } @@ -4783,16 +4834,6 @@ void helper_boundl(target_ulong a0, int v) } } -static float approx_rsqrt(float a) -{ - return 1.0 / sqrt(a); -} - -static float approx_rcp(float a) -{ - return 1.0 / a; -} - #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu @@ -4837,7 +4878,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } raise_exception_err(env->exception_index, env->error_code); diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 3232abd..703be99 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -778,28 +778,38 @@ int64_t helper_cvttsd2sq(XMMReg *s) void helper_rsqrtps(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); - d->XMM_S(1) = approx_rsqrt(s->XMM_S(1)); - d->XMM_S(2) = approx_rsqrt(s->XMM_S(2)); - d->XMM_S(3) = approx_rsqrt(s->XMM_S(3)); + d->XMM_S(0) = float32_div(float32_one, + float32_sqrt(s->XMM_S(0), &env->sse_status), + &env->sse_status); + d->XMM_S(1) = float32_div(float32_one, + float32_sqrt(s->XMM_S(1), &env->sse_status), + &env->sse_status); + d->XMM_S(2) = float32_div(float32_one, + float32_sqrt(s->XMM_S(2), &env->sse_status), + &env->sse_status); + d->XMM_S(3) = float32_div(float32_one, + float32_sqrt(s->XMM_S(3), &env->sse_status), + &env->sse_status); } void helper_rsqrtss(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); + d->XMM_S(0) = float32_div(float32_one, + float32_sqrt(s->XMM_S(0), &env->sse_status), + &env->sse_status); } void helper_rcpps(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rcp(s->XMM_S(0)); - d->XMM_S(1) = approx_rcp(s->XMM_S(1)); - d->XMM_S(2) = approx_rcp(s->XMM_S(2)); - d->XMM_S(3) = approx_rcp(s->XMM_S(3)); + d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status); + d->XMM_S(1) = float32_div(float32_one, s->XMM_S(1), &env->sse_status); + d->XMM_S(2) = float32_div(float32_one, s->XMM_S(2), &env->sse_status); + d->XMM_S(3) = float32_div(float32_one, s->XMM_S(3), &env->sse_status); } void helper_rcpss(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rcp(s->XMM_S(0)); + d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status); } static inline uint64_t helper_extrq(uint64_t src, int shift, int len) @@ -921,14 +931,14 @@ void helper_ ## name ## sd (Reg *d, Reg *s)\ d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ } -#define FPU_CMPEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? -1 : 0 +#define FPU_CMPEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? -1 : 0 #define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0 #define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0 -#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? - 1 : 0 -#define FPU_CMPNEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? 0 : -1 +#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? - 1 : 0 +#define FPU_CMPNEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1 -#define FPU_CMPORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? 0 : -1 +#define FPU_CMPORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? 0 : -1 SSE_HELPER_CMP(cmpeq, FPU_CMPEQ) SSE_HELPER_CMP(cmplt, FPU_CMPLT) @@ -1216,8 +1226,8 @@ void helper_pfadd(MMXReg *d, MMXReg *s) void helper_pfcmpeq(MMXReg *d, MMXReg *s) { - d->MMX_L(0) = float32_eq(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0; - d->MMX_L(1) = float32_eq(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0; + d->MMX_L(0) = float32_eq_quiet(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0; + d->MMX_L(1) = float32_eq_quiet(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0; } void helper_pfcmpge(MMXReg *d, MMXReg *s) @@ -1272,14 +1282,16 @@ void helper_pfpnacc(MMXReg *d, MMXReg *s) void helper_pfrcp(MMXReg *d, MMXReg *s) { - d->MMX_S(0) = approx_rcp(s->MMX_S(0)); + d->MMX_S(0) = float32_div(float32_one, s->MMX_S(0), &env->mmx_status); d->MMX_S(1) = d->MMX_S(0); } void helper_pfrsqrt(MMXReg *d, MMXReg *s) { d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff; - d->MMX_S(1) = approx_rsqrt(d->MMX_S(1)); + d->MMX_S(1) = float32_div(float32_one, + float32_sqrt(d->MMX_S(1), &env->mmx_status), + &env->mmx_status); d->MMX_L(1) |= s->MMX_L(0) & 0x80000000; d->MMX_L(0) = d->MMX_L(1); } diff --git a/target-i386/translate.c b/target-i386/translate.c index c008450..199302e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2274,7 +2274,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) /* jump to same page: we can use a direct jump */ tcg_gen_goto_tb(tb_num); gen_jmp_im(eip); - tcg_gen_exit_tb((long)tb + tb_num); + tcg_gen_exit_tb((tcg_target_long)tb + tb_num); } else { /* jump to another page: currently not optimized */ gen_jmp_im(eip); @@ -7890,8 +7890,7 @@ void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { int cc_op; #ifdef DEBUG_DISAS @@ -7903,8 +7902,8 @@ void gen_pc_load(CPUState *env, TranslationBlock *tb, qemu_log("0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]); } } - qemu_log("spc=0x%08lx pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", - searched_pc, pc_pos, gen_opc_pc[pc_pos] - tb->cs_base, + qemu_log("pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", + pc_pos, gen_opc_pc[pc_pos] - tb->cs_base, (uint32_t)tb->cs_base); } #endif diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index e84ba48..c72b1df 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -95,7 +95,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } cpu_loop_exit(); diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 666d5f4..51b4f5a 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -138,7 +138,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) likely(!dc->singlestep_enabled)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_pc, dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(cpu_pc, dest); if (dc->singlestep_enabled) { @@ -1212,8 +1212,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n\n"); } -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 0711107..9b13bdb 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -68,7 +68,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } cpu_loop_exit(); diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 6f72a2b..9e5578d 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -861,7 +861,7 @@ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(QREG_PC, dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { gen_jmp_im(s, dest); tcg_gen_exit_tb(0); @@ -3113,8 +3113,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 14d4d42..536222e 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -79,6 +79,8 @@ struct CPUMBState; #define ESR_DIZ (1<<11) /* Zone Protection */ #define ESR_S (1<<10) /* Store instruction */ +#define ESR_ESS_FSL_OFFSET 5 + #define ESR_EC_FSL 0 #define ESR_EC_UNALIGNED_DATA 1 #define ESR_EC_ILLEGAL_OP 2 @@ -91,6 +93,7 @@ struct CPUMBState; #define ESR_EC_INSN_STORAGE 9 #define ESR_EC_DATA_TLB 10 #define ESR_EC_INSN_TLB 11 +#define ESR_EC_MASK 31 /* Floating Point Status Register (FSR) Bits */ #define FSR_IO (1<<4) /* Invalid operation */ @@ -194,7 +197,7 @@ struct CPUMBState; #define PVR11_MMU_ITLB_SIZE 0x38000000 #define PVR11_MMU_DTLB_SIZE 0x07000000 #define PVR11_MMU_TLB_ACCESS 0x00C00000 -#define PVR11_MMU_ZONES 0x003C0000 +#define PVR11_MMU_ZONES 0x003E0000 /* MSR Reset value PVR mask */ #define PVR11_MSR_RESET_VALUE_MASK 0x000007FF @@ -211,6 +214,13 @@ struct CPUMBState; #define CC_EQ 0 #define NB_MMU_MODES 3 + +#define STREAM_EXCEPTION (1 << 0) +#define STREAM_ATOMIC (1 << 1) +#define STREAM_TEST (1 << 2) +#define STREAM_CONTROL (1 << 3) +#define STREAM_NONBLOCK (1 << 4) + typedef struct CPUMBState { uint32_t debug; uint32_t btaken; diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h index 1696b88..b92aa34 100644 --- a/target-microblaze/helper.h +++ b/target-microblaze/helper.h @@ -33,4 +33,7 @@ DEF_HELPER_2(mmu_write, void, i32, i32) DEF_HELPER_4(memalign, void, i32, i32, i32, i32) +DEF_HELPER_2(get, i32, i32, i32) +DEF_HELPER_3(put, void, i32, i32, i32) + #include "def-helper.h" diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h index 4a27476..401319e 100644 --- a/target-microblaze/microblaze-decode.h +++ b/target-microblaze/microblaze-decode.h @@ -50,3 +50,6 @@ #define DEC_BR {B8(00100110), B8(00110111)} #define DEC_BCC {B8(00100111), B8(00110111)} #define DEC_RTS {B8(00101101), B8(00111111)} + +#define DEC_STREAM {B8(00010011), B8(00110111)} + diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index d75a53c..c7b2f97 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -60,7 +60,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } cpu_loop_exit(); @@ -69,6 +69,41 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) } #endif +void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) +{ + int test = ctrl & STREAM_TEST; + int atomic = ctrl & STREAM_ATOMIC; + int control = ctrl & STREAM_CONTROL; + int nonblock = ctrl & STREAM_NONBLOCK; + int exception = ctrl & STREAM_EXCEPTION; + + qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n", + id, data, + test ? "t" : "", + nonblock ? "n" : "", + exception ? "e" : "", + control ? "c" : "", + atomic ? "a" : ""); +} + +uint32_t helper_get(uint32_t id, uint32_t ctrl) +{ + int test = ctrl & STREAM_TEST; + int atomic = ctrl & STREAM_ATOMIC; + int control = ctrl & STREAM_CONTROL; + int nonblock = ctrl & STREAM_NONBLOCK; + int exception = ctrl & STREAM_EXCEPTION; + + qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n", + id, + test ? "t" : "", + nonblock ? "n" : "", + exception ? "e" : "", + control ? "c" : "", + atomic ? "a" : ""); + return 0xdead0000 | id; +} + void helper_raise_exception(uint32_t index) { env->exception_index = index; @@ -303,7 +338,7 @@ uint32_t helper_fcmp_eq(uint32_t a, uint32_t b) set_float_exception_flags(0, &env->fp_status); fa.l = a; fb.l = b; - r = float32_eq(fa.f, fb.f, &env->fp_status); + r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); update_fpu_flags(flags & float_flag_invalid); @@ -349,7 +384,7 @@ uint32_t helper_fcmp_ne(uint32_t a, uint32_t b) fa.l = a; fb.l = b; set_float_exception_flags(0, &env->fp_status); - r = !float32_eq(fa.f, fb.f, &env->fp_status); + r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); update_fpu_flags(flags & float_flag_invalid); diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index b54b169..b47b92e 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -146,7 +146,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_SR[SR_PC], dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(cpu_SR[SR_PC], dest); tcg_gen_exit_tb(0); @@ -1476,6 +1476,42 @@ static void dec_null(DisasContext *dc) dc->abort_at_next_insn = 1; } +/* Insns connected to FSL or AXI stream attached devices. */ +static void dec_stream(DisasContext *dc) +{ + int mem_index = cpu_mmu_index(dc->env); + TCGv_i32 t_id, t_ctrl; + int ctrl; + + LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put", + dc->type_b ? "" : "d", dc->imm); + + if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + + t_id = tcg_temp_new(); + if (dc->type_b) { + tcg_gen_movi_tl(t_id, dc->imm & 0xf); + ctrl = dc->imm >> 10; + } else { + tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf); + ctrl = dc->imm >> 5; + } + + t_ctrl = tcg_const_tl(ctrl); + + if (dc->rd == 0) { + gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); + } else { + gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); + } + tcg_temp_free(t_id); + tcg_temp_free(t_ctrl); +} + static struct decoder_info { struct { uint32_t bits; @@ -1500,6 +1536,7 @@ static struct decoder_info { {DEC_MUL, dec_mul}, {DEC_DIV, dec_div}, {DEC_MSR, dec_msr}, + {DEC_STREAM, dec_stream}, {{0, 0}, dec_null} }; @@ -1903,8 +1940,7 @@ void cpu_reset (CPUState *env) #endif } -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->sregs[SR_PC] = gen_opc_pc[pc_pos]; } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index bd16ce3..b8e4991 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -54,7 +54,7 @@ static void do_restore_state (void *pc_ptr) tb = tb_find_pc (pc); if (tb) { - cpu_restore_state (tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } #endif @@ -1972,7 +1972,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } helper_raise_exception_err(env->exception_index, env->error_code); @@ -2077,22 +2077,27 @@ void helper_ctc1 (target_ulong arg1, uint32_t reg) helper_raise_exception(EXCP_FPE); } -static inline char ieee_ex_to_mips(char xcpt) +static inline int ieee_ex_to_mips(int xcpt) { - return (xcpt & float_flag_inexact) >> 5 | - (xcpt & float_flag_underflow) >> 3 | - (xcpt & float_flag_overflow) >> 1 | - (xcpt & float_flag_divbyzero) << 1 | - (xcpt & float_flag_invalid) << 4; -} - -static inline char mips_ex_to_ieee(char xcpt) -{ - return (xcpt & FP_INEXACT) << 5 | - (xcpt & FP_UNDERFLOW) << 3 | - (xcpt & FP_OVERFLOW) << 1 | - (xcpt & FP_DIV0) >> 1 | - (xcpt & FP_INVALID) >> 4; + int ret = 0; + if (xcpt) { + if (xcpt & float_flag_invalid) { + ret |= FP_INVALID; + } + if (xcpt & float_flag_overflow) { + ret |= FP_OVERFLOW; + } + if (xcpt & float_flag_underflow) { + ret |= FP_UNDERFLOW; + } + if (xcpt & float_flag_divbyzero) { + ret |= FP_DIV0; + } + if (xcpt & float_flag_inexact) { + ret |= FP_INEXACT; + } + } + return ret; } static inline void update_fcr31(void) @@ -2869,7 +2874,9 @@ uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1) #define FOP_COND_D(op, cond) \ void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ - int c = cond; \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + c = cond; \ update_fcr31(); \ if (c) \ SET_FP_COND(cc, env->active_fpu); \ @@ -2879,6 +2886,7 @@ void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ fdt0 = float64_abs(fdt0); \ fdt1 = float64_abs(fdt1); \ c = cond; \ @@ -2889,45 +2897,33 @@ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ CLEAR_FP_COND(cc, env->active_fpu); \ } -static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) -{ - if (float64_is_signaling_nan(a) || - float64_is_signaling_nan(b) || - (sig && (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)) { - return 1; - } else { - return 0; - } -} - /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0)) -FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) + * but float64_unordered_quiet() is still called. */ +FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)) +FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0)) -FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) + * but float64_unordered() is still called. */ +FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)) +FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) #define FOP_COND_S(op, cond) \ void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ { \ - int c = cond; \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + c = cond; \ update_fcr31(); \ if (c) \ SET_FP_COND(cc, env->active_fpu); \ @@ -2937,6 +2933,7 @@ void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ { \ int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ fst0 = float32_abs(fst0); \ fst1 = float32_abs(fst1); \ c = cond; \ @@ -2947,51 +2944,39 @@ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ CLEAR_FP_COND(cc, env->active_fpu); \ } -static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) -{ - if (float32_is_signaling_nan(a) || - float32_is_signaling_nan(b) || - (sig && (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)) { - return 1; - } else { - return 0; - } -} - /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0)) -FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) + * but float32_unordered_quiet() is still called. */ +FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)) +FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0)) -FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) + * but float32_unordered() is still called. */ +FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status)) +FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) #define FOP_COND_PS(op, condl, condh) \ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ - uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ - uint32_t fsth0 = float32_abs(fdt0 >> 32); \ - uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ - uint32_t fsth1 = float32_abs(fdt1 >> 32); \ - int cl = condl; \ - int ch = condh; \ - \ + uint32_t fst0, fsth0, fst1, fsth1; \ + int ch, cl; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + fst0 = fdt0 & 0XFFFFFFFF; \ + fsth0 = fdt0 >> 32; \ + fst1 = fdt1 & 0XFFFFFFFF; \ + fsth1 = fdt1 >> 32; \ + cl = condl; \ + ch = condh; \ update_fcr31(); \ if (cl) \ SET_FP_COND(cc, env->active_fpu); \ @@ -3004,13 +2989,14 @@ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ } \ void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ - uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ - uint32_t fsth0 = float32_abs(fdt0 >> 32); \ - uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ - uint32_t fsth1 = float32_abs(fdt1 >> 32); \ - int cl = condl; \ - int ch = condh; \ - \ + uint32_t fst0, fsth0, fst1, fsth1; \ + int ch, cl; \ + fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ + fsth0 = float32_abs(fdt0 >> 32); \ + fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ + fsth1 = float32_abs(fdt1 >> 32); \ + cl = condl; \ + ch = condh; \ update_fcr31(); \ if (cl) \ SET_FP_COND(cc, env->active_fpu); \ @@ -3023,38 +3009,38 @@ void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ } /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0), - (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0)) -FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) + * but float32_unordered_quiet() is still called. */ +FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0), + (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0)) +FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)) +FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0), - (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0)) -FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) + * but float32_unordered() is still called. */ +FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0), + (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0)) +FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)) +FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status), + float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status), + float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) diff --git a/target-mips/translate.c b/target-mips/translate.c index 0f93e2a..4eaa826 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2686,7 +2686,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); gen_save_pc(dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { gen_save_pc(dest); if (ctx->singlestep_enabled) { @@ -12737,8 +12737,7 @@ void cpu_reset (CPUMIPSState *env) env->exception_index = EXCP_NONE; } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->active_tc.PC = gen_opc_pc[pc_pos]; env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5882bec..d5db484 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1287,7 +1287,6 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1303,10 +1302,6 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) + farg3.d; -#endif } return farg1.ll; @@ -1332,7 +1327,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1348,10 +1342,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) - farg3.d; -#endif } return farg1.ll; } @@ -1376,7 +1366,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1392,10 +1381,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) + farg3.d; -#endif if (likely(!float64_is_any_nan(farg1.d))) { farg1.d = float64_chs(farg1.d); } @@ -1423,7 +1408,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1439,10 +1423,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) - farg3.d; -#endif if (likely(!float64_is_any_nan(farg1.d))) { farg1.d = float64_chs(farg1.d); } @@ -3363,7 +3343,7 @@ HELPER_SPE_VECTOR_ARITH(fsmul); HELPER_SPE_VECTOR_ARITH(fsdiv); /* Single-precision floating-point comparisons */ -static inline uint32_t efststlt(uint32_t op1, uint32_t op2) +static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; u1.l = op1; @@ -3371,7 +3351,7 @@ static inline uint32_t efststlt(uint32_t op1, uint32_t op2) return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; } -static inline uint32_t efststgt(uint32_t op1, uint32_t op2) +static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; u1.l = op1; @@ -3379,7 +3359,7 @@ static inline uint32_t efststgt(uint32_t op1, uint32_t op2) return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; } -static inline uint32_t efststeq(uint32_t op1, uint32_t op2) +static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; u1.l = op1; @@ -3387,22 +3367,22 @@ static inline uint32_t efststeq(uint32_t op1, uint32_t op2) return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; } -static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) +static inline uint32_t efststlt(uint32_t op1, uint32_t op2) { - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return efststlt(op1, op2); + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmplt(op1, op2); } -static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) +static inline uint32_t efststgt(uint32_t op1, uint32_t op2) { - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return efststgt(op1, op2); + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmpgt(op1, op2); } -static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) +static inline uint32_t efststeq(uint32_t op1, uint32_t op2) { - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return efststeq(op1, op2); + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmpeq(op1, op2); } #define HELPER_SINGLE_SPE_CMP(name) \ @@ -3698,7 +3678,7 @@ uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2) CPU_DoubleU u1, u2; u1.ll = op1; u2.ll = op2; - return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0; + return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; } uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2) @@ -3761,7 +3741,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (likely(tb)) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } helper_raise_exception_err(env->exception_index, env->error_code); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 090795b..a943dbc 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3347,7 +3347,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_nip, dest & ~3); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(cpu_nip, dest & ~3); if (unlikely(ctx->singlestep_enabled)) { @@ -9367,8 +9367,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->nip = gen_opc_pc[pc_pos]; } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index e47c372..a84b3ee 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -26,24 +26,35 @@ #define CPUState struct CPUS390XState #include "cpu-defs.h" +#define TARGET_PAGE_BITS 12 + +#define TARGET_PHYS_ADDR_SPACE_BITS 64 +#define TARGET_VIRT_ADDR_SPACE_BITS 64 + +#include "cpu-all.h" #include "softfloat.h" -#define NB_MMU_MODES 2 +#define NB_MMU_MODES 3 -typedef union FPReg { - struct { -#ifdef WORDS_BIGENDIAN - float32 e; - int32_t __pad; -#else - int32_t __pad; - float32 e; -#endif - }; - float64 d; - uint64_t i; -} FPReg; +#define MMU_MODE0_SUFFIX _primary +#define MMU_MODE1_SUFFIX _secondary +#define MMU_MODE2_SUFFIX _home + +#define MMU_USER_IDX 1 + +#define MAX_EXT_QUEUE 16 + +typedef struct PSW { + uint64_t mask; + uint64_t addr; +} PSW; + +typedef struct ExtQueue { + uint32_t code; + uint32_t param; + uint32_t param64; +} ExtQueue; typedef struct CPUS390XState { uint64_t regs[16]; /* GP registers */ @@ -51,17 +62,42 @@ typedef struct CPUS390XState { uint32_t aregs[16]; /* access registers */ uint32_t fpc; /* floating-point control register */ - FPReg fregs[16]; /* FP registers */ + CPU_DoubleU fregs[16]; /* FP registers */ float_status fpu_status; /* passed to softfloat lib */ - struct { - uint64_t mask; - uint64_t addr; - } psw; + PSW psw; - int cc; /* condition code (0-3) */ + uint32_t cc; + uint32_t cc_op; + uint64_t cc_src; + uint64_t cc_dst; + uint64_t cc_vr; uint64_t __excp_addr; + uint64_t psa; + + uint32_t int_pgm_code; + uint32_t int_pgm_ilc; + + uint32_t int_svc_code; + uint32_t int_svc_ilc; + + uint64_t cregs[16]; /* control registers */ + + int pending_int; + ExtQueue ext_queue[MAX_EXT_QUEUE]; + + /* reset does memset(0) up to here */ + + int ext_index; + int cpu_num; + uint8_t *storage_keys; + + uint64_t tod_offset; + uint64_t tod_basetime; + QEMUTimer *tod_timer; + + QEMUTimer *cpu_timer; CPU_COMMON } CPUS390XState; @@ -69,24 +105,174 @@ typedef struct CPUS390XState { #if defined(CONFIG_USER_ONLY) static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) { - if (newsp) + if (newsp) { env->regs[15] = newsp; + } env->regs[0] = 0; } #endif -#define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_USER_IDX 1 +/* Interrupt Codes */ +/* Program Interrupts */ +#define PGM_OPERATION 0x0001 +#define PGM_PRIVILEGED 0x0002 +#define PGM_EXECUTE 0x0003 +#define PGM_PROTECTION 0x0004 +#define PGM_ADDRESSING 0x0005 +#define PGM_SPECIFICATION 0x0006 +#define PGM_DATA 0x0007 +#define PGM_FIXPT_OVERFLOW 0x0008 +#define PGM_FIXPT_DIVIDE 0x0009 +#define PGM_DEC_OVERFLOW 0x000a +#define PGM_DEC_DIVIDE 0x000b +#define PGM_HFP_EXP_OVERFLOW 0x000c +#define PGM_HFP_EXP_UNDERFLOW 0x000d +#define PGM_HFP_SIGNIFICANCE 0x000e +#define PGM_HFP_DIVIDE 0x000f +#define PGM_SEGMENT_TRANS 0x0010 +#define PGM_PAGE_TRANS 0x0011 +#define PGM_TRANS_SPEC 0x0012 +#define PGM_SPECIAL_OP 0x0013 +#define PGM_OPERAND 0x0015 +#define PGM_TRACE_TABLE 0x0016 +#define PGM_SPACE_SWITCH 0x001c +#define PGM_HFP_SQRT 0x001d +#define PGM_PC_TRANS_SPEC 0x001f +#define PGM_AFX_TRANS 0x0020 +#define PGM_ASX_TRANS 0x0021 +#define PGM_LX_TRANS 0x0022 +#define PGM_EX_TRANS 0x0023 +#define PGM_PRIM_AUTH 0x0024 +#define PGM_SEC_AUTH 0x0025 +#define PGM_ALET_SPEC 0x0028 +#define PGM_ALEN_SPEC 0x0029 +#define PGM_ALE_SEQ 0x002a +#define PGM_ASTE_VALID 0x002b +#define PGM_ASTE_SEQ 0x002c +#define PGM_EXT_AUTH 0x002d +#define PGM_STACK_FULL 0x0030 +#define PGM_STACK_EMPTY 0x0031 +#define PGM_STACK_SPEC 0x0032 +#define PGM_STACK_TYPE 0x0033 +#define PGM_STACK_OP 0x0034 +#define PGM_ASCE_TYPE 0x0038 +#define PGM_REG_FIRST_TRANS 0x0039 +#define PGM_REG_SEC_TRANS 0x003a +#define PGM_REG_THIRD_TRANS 0x003b +#define PGM_MONITOR 0x0040 +#define PGM_PER 0x0080 +#define PGM_CRYPTO 0x0119 + +/* External Interrupts */ +#define EXT_INTERRUPT_KEY 0x0040 +#define EXT_CLOCK_COMP 0x1004 +#define EXT_CPU_TIMER 0x1005 +#define EXT_MALFUNCTION 0x1200 +#define EXT_EMERGENCY 0x1201 +#define EXT_EXTERNAL_CALL 0x1202 +#define EXT_ETR 0x1406 +#define EXT_SERVICE 0x2401 +#define EXT_VIRTIO 0x2603 + +/* PSW defines */ +#undef PSW_MASK_PER +#undef PSW_MASK_DAT +#undef PSW_MASK_IO +#undef PSW_MASK_EXT +#undef PSW_MASK_KEY +#undef PSW_SHIFT_KEY +#undef PSW_MASK_MCHECK +#undef PSW_MASK_WAIT +#undef PSW_MASK_PSTATE +#undef PSW_MASK_ASC +#undef PSW_MASK_CC +#undef PSW_MASK_PM +#undef PSW_MASK_64 + +#define PSW_MASK_PER 0x4000000000000000ULL +#define PSW_MASK_DAT 0x0400000000000000ULL +#define PSW_MASK_IO 0x0200000000000000ULL +#define PSW_MASK_EXT 0x0100000000000000ULL +#define PSW_MASK_KEY 0x00F0000000000000ULL +#define PSW_SHIFT_KEY 56 +#define PSW_MASK_MCHECK 0x0004000000000000ULL +#define PSW_MASK_WAIT 0x0002000000000000ULL +#define PSW_MASK_PSTATE 0x0001000000000000ULL +#define PSW_MASK_ASC 0x0000C00000000000ULL +#define PSW_MASK_CC 0x0000300000000000ULL +#define PSW_MASK_PM 0x00000F0000000000ULL +#define PSW_MASK_64 0x0000000100000000ULL +#define PSW_MASK_32 0x0000000080000000ULL + +#undef PSW_ASC_PRIMARY +#undef PSW_ASC_ACCREG +#undef PSW_ASC_SECONDARY +#undef PSW_ASC_HOME + +#define PSW_ASC_PRIMARY 0x0000000000000000ULL +#define PSW_ASC_ACCREG 0x0000400000000000ULL +#define PSW_ASC_SECONDARY 0x0000800000000000ULL +#define PSW_ASC_HOME 0x0000C00000000000ULL + +/* tb flags */ + +#define FLAG_MASK_PER (PSW_MASK_PER >> 32) +#define FLAG_MASK_DAT (PSW_MASK_DAT >> 32) +#define FLAG_MASK_IO (PSW_MASK_IO >> 32) +#define FLAG_MASK_EXT (PSW_MASK_EXT >> 32) +#define FLAG_MASK_KEY (PSW_MASK_KEY >> 32) +#define FLAG_MASK_MCHECK (PSW_MASK_MCHECK >> 32) +#define FLAG_MASK_WAIT (PSW_MASK_WAIT >> 32) +#define FLAG_MASK_PSTATE (PSW_MASK_PSTATE >> 32) +#define FLAG_MASK_ASC (PSW_MASK_ASC >> 32) +#define FLAG_MASK_CC (PSW_MASK_CC >> 32) +#define FLAG_MASK_PM (PSW_MASK_PM >> 32) +#define FLAG_MASK_64 (PSW_MASK_64 >> 32) +#define FLAG_MASK_32 0x00001000 + static inline int cpu_mmu_index (CPUState *env) { - /* XXX: Currently we don't implement virtual memory */ + if (env->psw.mask & PSW_MASK_PSTATE) { + return 1; + } + return 0; } +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->psw.addr; + *cs_base = 0; + *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) | + ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); +} + +static inline int get_ilc(uint8_t opc) +{ + switch (opc >> 6) { + case 0: + return 1; + case 1: + case 2: + return 2; + case 3: + return 3; + } + + return 0; +} + +#define ILC_LATER 0x20 +#define ILC_LATER_INC 0x21 +#define ILC_LATER_INC_2 0x22 + + CPUS390XState *cpu_s390x_init(const char *cpu_model); +void s390x_translate_init(void); int cpu_s390x_exec(CPUS390XState *s); void cpu_s390x_close(CPUS390XState *s); +void do_interrupt (CPUState *env); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero @@ -97,41 +283,61 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw int mmu_idx, int is_softmuu); #define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault -#define TARGET_PAGE_BITS 12 - -/* ??? This is certainly wrong for 64-bit s390x, but given that only KVM - emulation actually works, this is good enough for a placeholder. */ -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 #ifndef CONFIG_USER_ONLY -int s390_virtio_hypercall(CPUState *env); +int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall); + +void kvm_s390_interrupt(CPUState *env, int type, uint32_t code); void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token); +void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, + uint64_t parm64, int vm); CPUState *s390_cpu_addr2state(uint16_t cpu_addr); + +#ifndef KVM_S390_SIGP_STOP +#define KVM_S390_SIGP_STOP 0 +#define KVM_S390_PROGRAM_INT 0 +#define KVM_S390_SIGP_SET_PREFIX 0 +#define KVM_S390_RESTART 0 +#define KVM_S390_INT_VIRTIO 0 +#define KVM_S390_INT_SERVICE 0 +#define KVM_S390_INT_EMERGENCY 0 +#endif + #endif +void cpu_lock(void); +void cpu_unlock(void); +static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) +{ + env->aregs[0] = newtls >> 32; + env->aregs[1] = newtls & 0xffffffffULL; +} #define cpu_init cpu_s390x_init #define cpu_exec cpu_s390x_exec #define cpu_gen_code cpu_s390x_gen_code +#define cpu_signal_handler cpu_s390x_signal_handler -#include "cpu-all.h" +#include "exec-all.h" + +#ifdef CONFIG_USER_ONLY #define EXCP_OPEX 1 /* operation exception (sigill) */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_ADDR 5 /* addressing exception */ -#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */ +#define EXCP_SPEC 6 /* specification exception */ -static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, - target_ulong *cs_base, int *flags) -{ - *pc = env->psw.addr; - /* XXX this is correct for user-mode emulation, but needs - * the asce register information as well when softmmu - * is implemented in the future */ - *cs_base = 0; - *flags = env->psw.mask; -} +#else + +#define EXCP_EXT 1 /* external interrupt */ +#define EXCP_SVC 2 /* supervisor call (syscall) */ +#define EXCP_PGM 3 /* program interruption */ + +#endif /* CONFIG_USER_ONLY */ + +#define INTERRUPT_EXT (1 << 0) +#define INTERRUPT_TOD (1 << 1) +#define INTERRUPT_CPUTIMER (1 << 2) /* Program Status Word. */ #define S390_PSWM_REGNUM 0 @@ -265,5 +471,485 @@ static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, #define S390_NUM_PSEUDO_REGS 2 #define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) +/* CC optimization */ + +enum cc_op { + CC_OP_CONST0 = 0, /* CC is 0 */ + CC_OP_CONST1, /* CC is 1 */ + CC_OP_CONST2, /* CC is 2 */ + CC_OP_CONST3, /* CC is 3 */ + + CC_OP_DYNAMIC, /* CC calculation defined by env->cc_op */ + CC_OP_STATIC, /* CC value is env->cc_op */ + + CC_OP_NZ, /* env->cc_dst != 0 */ + CC_OP_LTGT_32, /* signed less/greater than (32bit) */ + CC_OP_LTGT_64, /* signed less/greater than (64bit) */ + CC_OP_LTUGTU_32, /* unsigned less/greater than (32bit) */ + CC_OP_LTUGTU_64, /* unsigned less/greater than (64bit) */ + CC_OP_LTGT0_32, /* signed less/greater than 0 (32bit) */ + CC_OP_LTGT0_64, /* signed less/greater than 0 (64bit) */ + + CC_OP_ADD_64, /* overflow on add (64bit) */ + CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ + CC_OP_SUB_64, /* overflow on substraction (64bit) */ + CC_OP_SUBU_64, /* overflow on unsigned substraction (64bit) */ + CC_OP_ABS_64, /* sign eval on abs (64bit) */ + CC_OP_NABS_64, /* sign eval on nabs (64bit) */ + + CC_OP_ADD_32, /* overflow on add (32bit) */ + CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ + CC_OP_SUB_32, /* overflow on substraction (32bit) */ + CC_OP_SUBU_32, /* overflow on unsigned substraction (32bit) */ + CC_OP_ABS_32, /* sign eval on abs (64bit) */ + CC_OP_NABS_32, /* sign eval on nabs (64bit) */ + + CC_OP_COMP_32, /* complement */ + CC_OP_COMP_64, /* complement */ + + CC_OP_TM_32, /* test under mask (32bit) */ + CC_OP_TM_64, /* test under mask (64bit) */ + + CC_OP_LTGT_F32, /* FP compare (32bit) */ + CC_OP_LTGT_F64, /* FP compare (64bit) */ + + CC_OP_NZ_F32, /* FP dst != 0 (32bit) */ + CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ + + CC_OP_ICM, /* insert characters under mask */ + CC_OP_SLAG, /* Calculate shift left signed */ + CC_OP_MAX +}; + +static const char *cc_names[] = { + [CC_OP_CONST0] = "CC_OP_CONST0", + [CC_OP_CONST1] = "CC_OP_CONST1", + [CC_OP_CONST2] = "CC_OP_CONST2", + [CC_OP_CONST3] = "CC_OP_CONST3", + [CC_OP_DYNAMIC] = "CC_OP_DYNAMIC", + [CC_OP_STATIC] = "CC_OP_STATIC", + [CC_OP_NZ] = "CC_OP_NZ", + [CC_OP_LTGT_32] = "CC_OP_LTGT_32", + [CC_OP_LTGT_64] = "CC_OP_LTGT_64", + [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32", + [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64", + [CC_OP_LTGT0_32] = "CC_OP_LTGT0_32", + [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", + [CC_OP_ADD_64] = "CC_OP_ADD_64", + [CC_OP_ADDU_64] = "CC_OP_ADDU_64", + [CC_OP_SUB_64] = "CC_OP_SUB_64", + [CC_OP_SUBU_64] = "CC_OP_SUBU_64", + [CC_OP_ABS_64] = "CC_OP_ABS_64", + [CC_OP_NABS_64] = "CC_OP_NABS_64", + [CC_OP_ADD_32] = "CC_OP_ADD_32", + [CC_OP_ADDU_32] = "CC_OP_ADDU_32", + [CC_OP_SUB_32] = "CC_OP_SUB_32", + [CC_OP_SUBU_32] = "CC_OP_SUBU_32", + [CC_OP_ABS_32] = "CC_OP_ABS_32", + [CC_OP_NABS_32] = "CC_OP_NABS_32", + [CC_OP_COMP_32] = "CC_OP_COMP_32", + [CC_OP_COMP_64] = "CC_OP_COMP_64", + [CC_OP_TM_32] = "CC_OP_TM_32", + [CC_OP_TM_64] = "CC_OP_TM_64", + [CC_OP_LTGT_F32] = "CC_OP_LTGT_F32", + [CC_OP_LTGT_F64] = "CC_OP_LTGT_F64", + [CC_OP_NZ_F32] = "CC_OP_NZ_F32", + [CC_OP_NZ_F64] = "CC_OP_NZ_F64", + [CC_OP_ICM] = "CC_OP_ICM", + [CC_OP_SLAG] = "CC_OP_SLAG", +}; + +static inline const char *cc_name(int cc_op) +{ + return cc_names[cc_op]; +} + +/* SCLP PV interface defines */ +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 + +#define SCP_LENGTH 0x00 +#define SCP_FUNCTION_CODE 0x02 +#define SCP_CONTROL_MASK 0x03 +#define SCP_RESPONSE_CODE 0x06 +#define SCP_MEM_CODE 0x08 +#define SCP_INCREMENT 0x0a + +typedef struct LowCore +{ + /* prefix area: defined by architecture */ + uint32_t ccw1[2]; /* 0x000 */ + uint32_t ccw2[4]; /* 0x008 */ + uint8_t pad1[0x80-0x18]; /* 0x018 */ + uint32_t ext_params; /* 0x080 */ + uint16_t cpu_addr; /* 0x084 */ + uint16_t ext_int_code; /* 0x086 */ + uint16_t svc_ilc; /* 0x088 */ + uint16_t svc_code; /* 0x08a */ + uint16_t pgm_ilc; /* 0x08c */ + uint16_t pgm_code; /* 0x08e */ + uint32_t data_exc_code; /* 0x090 */ + uint16_t mon_class_num; /* 0x094 */ + uint16_t per_perc_atmid; /* 0x096 */ + uint64_t per_address; /* 0x098 */ + uint8_t exc_access_id; /* 0x0a0 */ + uint8_t per_access_id; /* 0x0a1 */ + uint8_t op_access_id; /* 0x0a2 */ + uint8_t ar_access_id; /* 0x0a3 */ + uint8_t pad2[0xA8-0xA4]; /* 0x0a4 */ + uint64_t trans_exc_code; /* 0x0a8 */ + uint64_t monitor_code; /* 0x0b0 */ + uint16_t subchannel_id; /* 0x0b8 */ + uint16_t subchannel_nr; /* 0x0ba */ + uint32_t io_int_parm; /* 0x0bc */ + uint32_t io_int_word; /* 0x0c0 */ + uint8_t pad3[0xc8-0xc4]; /* 0x0c4 */ + uint32_t stfl_fac_list; /* 0x0c8 */ + uint8_t pad4[0xe8-0xcc]; /* 0x0cc */ + uint32_t mcck_interruption_code[2]; /* 0x0e8 */ + uint8_t pad5[0xf4-0xf0]; /* 0x0f0 */ + uint32_t external_damage_code; /* 0x0f4 */ + uint64_t failing_storage_address; /* 0x0f8 */ + uint8_t pad6[0x120-0x100]; /* 0x100 */ + PSW restart_old_psw; /* 0x120 */ + PSW external_old_psw; /* 0x130 */ + PSW svc_old_psw; /* 0x140 */ + PSW program_old_psw; /* 0x150 */ + PSW mcck_old_psw; /* 0x160 */ + PSW io_old_psw; /* 0x170 */ + uint8_t pad7[0x1a0-0x180]; /* 0x180 */ + PSW restart_psw; /* 0x1a0 */ + PSW external_new_psw; /* 0x1b0 */ + PSW svc_new_psw; /* 0x1c0 */ + PSW program_new_psw; /* 0x1d0 */ + PSW mcck_new_psw; /* 0x1e0 */ + PSW io_new_psw; /* 0x1f0 */ + PSW return_psw; /* 0x200 */ + uint8_t irb[64]; /* 0x210 */ + uint64_t sync_enter_timer; /* 0x250 */ + uint64_t async_enter_timer; /* 0x258 */ + uint64_t exit_timer; /* 0x260 */ + uint64_t last_update_timer; /* 0x268 */ + uint64_t user_timer; /* 0x270 */ + uint64_t system_timer; /* 0x278 */ + uint64_t last_update_clock; /* 0x280 */ + uint64_t steal_clock; /* 0x288 */ + PSW return_mcck_psw; /* 0x290 */ + uint8_t pad8[0xc00-0x2a0]; /* 0x2a0 */ + /* System info area */ + uint64_t save_area[16]; /* 0xc00 */ + uint8_t pad9[0xd40-0xc80]; /* 0xc80 */ + uint64_t kernel_stack; /* 0xd40 */ + uint64_t thread_info; /* 0xd48 */ + uint64_t async_stack; /* 0xd50 */ + uint64_t kernel_asce; /* 0xd58 */ + uint64_t user_asce; /* 0xd60 */ + uint64_t panic_stack; /* 0xd68 */ + uint64_t user_exec_asce; /* 0xd70 */ + uint8_t pad10[0xdc0-0xd78]; /* 0xd78 */ + + /* SMP info area: defined by DJB */ + uint64_t clock_comparator; /* 0xdc0 */ + uint64_t ext_call_fast; /* 0xdc8 */ + uint64_t percpu_offset; /* 0xdd0 */ + uint64_t current_task; /* 0xdd8 */ + uint32_t softirq_pending; /* 0xde0 */ + uint32_t pad_0x0de4; /* 0xde4 */ + uint64_t int_clock; /* 0xde8 */ + uint8_t pad12[0xe00-0xdf0]; /* 0xdf0 */ + + /* 0xe00 is used as indicator for dump tools */ + /* whether the kernel died with panic() or not */ + uint32_t panic_magic; /* 0xe00 */ + + uint8_t pad13[0x11b8-0xe04]; /* 0xe04 */ + + /* 64 bit extparam used for pfault, diag 250 etc */ + uint64_t ext_params2; /* 0x11B8 */ + + uint8_t pad14[0x1200-0x11C0]; /* 0x11C0 */ + + /* System info area */ + + uint64_t floating_pt_save_area[16]; /* 0x1200 */ + uint64_t gpregs_save_area[16]; /* 0x1280 */ + uint32_t st_status_fixed_logout[4]; /* 0x1300 */ + uint8_t pad15[0x1318-0x1310]; /* 0x1310 */ + uint32_t prefixreg_save_area; /* 0x1318 */ + uint32_t fpt_creg_save_area; /* 0x131c */ + uint8_t pad16[0x1324-0x1320]; /* 0x1320 */ + uint32_t tod_progreg_save_area; /* 0x1324 */ + uint32_t cpu_timer_save_area[2]; /* 0x1328 */ + uint32_t clock_comp_save_area[2]; /* 0x1330 */ + uint8_t pad17[0x1340-0x1338]; /* 0x1338 */ + uint32_t access_regs_save_area[16]; /* 0x1340 */ + uint64_t cregs_save_area[16]; /* 0x1380 */ + + /* align to the top of the prefix area */ + + uint8_t pad18[0x2000-0x1400]; /* 0x1400 */ +} __attribute__((packed)) LowCore; + +/* STSI */ +#define STSI_LEVEL_MASK 0x00000000f0000000ULL +#define STSI_LEVEL_CURRENT 0x0000000000000000ULL +#define STSI_LEVEL_1 0x0000000010000000ULL +#define STSI_LEVEL_2 0x0000000020000000ULL +#define STSI_LEVEL_3 0x0000000030000000ULL +#define STSI_R0_RESERVED_MASK 0x000000000fffff00ULL +#define STSI_R0_SEL1_MASK 0x00000000000000ffULL +#define STSI_R1_RESERVED_MASK 0x00000000ffff0000ULL +#define STSI_R1_SEL2_MASK 0x000000000000ffffULL + +/* Basic Machine Configuration */ +struct sysib_111 { + uint32_t res1[8]; + uint8_t manuf[16]; + uint8_t type[4]; + uint8_t res2[12]; + uint8_t model[16]; + uint8_t sequence[16]; + uint8_t plant[4]; + uint8_t res3[156]; +}; + +/* Basic Machine CPU */ +struct sysib_121 { + uint32_t res1[80]; + uint8_t sequence[16]; + uint8_t plant[4]; + uint8_t res2[2]; + uint16_t cpu_addr; + uint8_t res3[152]; +}; + +/* Basic Machine CPUs */ +struct sysib_122 { + uint8_t res1[32]; + uint32_t capability; + uint16_t total_cpus; + uint16_t active_cpus; + uint16_t standby_cpus; + uint16_t reserved_cpus; + uint16_t adjustments[2026]; +}; + +/* LPAR CPU */ +struct sysib_221 { + uint32_t res1[80]; + uint8_t sequence[16]; + uint8_t plant[4]; + uint16_t cpu_id; + uint16_t cpu_addr; + uint8_t res3[152]; +}; + +/* LPAR CPUs */ +struct sysib_222 { + uint32_t res1[32]; + uint16_t lpar_num; + uint8_t res2; + uint8_t lcpuc; + uint16_t total_cpus; + uint16_t conf_cpus; + uint16_t standby_cpus; + uint16_t reserved_cpus; + uint8_t name[8]; + uint32_t caf; + uint8_t res3[16]; + uint16_t dedicated_cpus; + uint16_t shared_cpus; + uint8_t res4[180]; +}; + +/* VM CPUs */ +struct sysib_322 { + uint8_t res1[31]; + uint8_t count; + struct { + uint8_t res2[4]; + uint16_t total_cpus; + uint16_t conf_cpus; + uint16_t standby_cpus; + uint16_t reserved_cpus; + uint8_t name[8]; + uint32_t caf; + uint8_t cpi[16]; + uint8_t res3[24]; + } vm[8]; + uint8_t res4[3552]; +}; + +/* MMU defines */ +#define _ASCE_ORIGIN ~0xfffULL /* segment table origin */ +#define _ASCE_SUBSPACE 0x200 /* subspace group control */ +#define _ASCE_PRIVATE_SPACE 0x100 /* private space control */ +#define _ASCE_ALT_EVENT 0x80 /* storage alteration event control */ +#define _ASCE_SPACE_SWITCH 0x40 /* space switch event */ +#define _ASCE_REAL_SPACE 0x20 /* real space control */ +#define _ASCE_TYPE_MASK 0x0c /* asce table type mask */ +#define _ASCE_TYPE_REGION1 0x0c /* region first table type */ +#define _ASCE_TYPE_REGION2 0x08 /* region second table type */ +#define _ASCE_TYPE_REGION3 0x04 /* region third table type */ +#define _ASCE_TYPE_SEGMENT 0x00 /* segment table type */ +#define _ASCE_TABLE_LENGTH 0x03 /* region table length */ + +#define _REGION_ENTRY_ORIGIN ~0xfffULL /* region/segment table origin */ +#define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ +#define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ +#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ +#define _REGION_ENTRY_TYPE_R2 0x08 /* region second table type */ +#define _REGION_ENTRY_TYPE_R3 0x04 /* region third table type */ +#define _REGION_ENTRY_LENGTH 0x03 /* region third length */ + +#define _SEGMENT_ENTRY_ORIGIN ~0x7ffULL /* segment table origin */ +#define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ +#define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ + +#define _PAGE_RO 0x200 /* HW read-only bit */ +#define _PAGE_INVALID 0x400 /* HW invalid bit */ + + + +/* EBCDIC handling */ +static const uint8_t ebcdic2ascii[] = { + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, +}; + +static const uint8_t ascii2ebcdic [] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) +{ + int i; + + for (i = 0; i < len; i++) { + p[i] = ascii2ebcdic[(int)ascii[i]]; + } +} + +#define SIGP_SENSE 0x01 +#define SIGP_EXTERNAL_CALL 0x02 +#define SIGP_EMERGENCY 0x03 +#define SIGP_START 0x04 +#define SIGP_STOP 0x05 +#define SIGP_RESTART 0x06 +#define SIGP_STOP_STORE_STATUS 0x09 +#define SIGP_INITIAL_CPU_RESET 0x0b +#define SIGP_CPU_RESET 0x0c +#define SIGP_SET_PREFIX 0x0d +#define SIGP_STORE_STATUS_ADDR 0x0e +#define SIGP_SET_ARCH 0x12 + +/* cpu status bits */ +#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL +#define SIGP_STAT_INCORRECT_STATE 0x00000200UL +#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL +#define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL +#define SIGP_STAT_STOPPED 0x00000040UL +#define SIGP_STAT_OPERATOR_INTERV 0x00000020UL +#define SIGP_STAT_CHECK_STOP 0x00000010UL +#define SIGP_STAT_INOPERATIVE 0x00000004UL +#define SIGP_STAT_INVALID_ORDER 0x00000002UL +#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL + +void load_psw(CPUState *env, uint64_t mask, uint64_t addr); +int mmu_translate(CPUState *env, target_ulong vaddr, int rw, uint64_t asc, + target_ulong *raddr, int *flags); +int sclp_service_call(CPUState *env, uint32_t sccb, uint64_t code); +uint32_t calc_cc(CPUState *env, uint32_t cc_op, uint64_t src, uint64_t dst, + uint64_t vr); + +#define TARGET_HAS_ICE 1 + +/* The value of the TOD clock for 1.1.1970. */ +#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL + +/* Converts ns to s390's clock format */ +static inline uint64_t time2tod(uint64_t ns) { + return (ns << 9) / 125; +} + +static inline void cpu_inject_ext(CPUState *env, uint32_t code, uint32_t param, + uint64_t param64) +{ + if (env->ext_index == MAX_EXT_QUEUE - 1) { + /* ugh - can't queue anymore. Let's drop. */ + return; + } + + env->ext_index++; + assert(env->ext_index < MAX_EXT_QUEUE); + + env->ext_queue[env->ext_index].code = code; + env->ext_queue[env->ext_index].param = param; + env->ext_queue[env->ext_index].param64 = param64; + + env->pending_int |= INTERRUPT_EXT; + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} #endif diff --git a/target-s390x/exec.h b/target-s390x/exec.h index f7893f3..7a87fff 100644 --- a/target-s390x/exec.h +++ b/target-s390x/exec.h @@ -31,7 +31,16 @@ register struct CPUS390XState *env asm(AREG0); static inline int cpu_has_work(CPUState *env) { - return env->interrupt_request & CPU_INTERRUPT_HARD; // guess + return ((env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->psw.mask & PSW_MASK_EXT)); +} + +static inline void regs_to_env(void) +{ +} + +static inline void env_to_regs(void) +{ } static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 4a5297b..629dfd9 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -82,3 +82,7 @@ int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 0; } #endif /* CONFIG_USER_ONLY */ + +void do_interrupt (CPUState *env) +{ +} diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index ae7dc56..2643460 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -182,8 +182,8 @@ int kvm_arch_process_async_events(CPUState *env) return 0; } -static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, - uint64_t parm64, int vm) +void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, + uint64_t parm64, int vm) { struct kvm_s390_interrupt kvmint; int r; @@ -218,7 +218,7 @@ void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token) token, 1); } -static void kvm_s390_interrupt(CPUState *env, int type, uint32_t code) +void kvm_s390_interrupt(CPUState *env, int type, uint32_t code) { kvm_s390_interrupt_internal(env, type, code, 0, 0); } @@ -237,7 +237,8 @@ static void setcc(CPUState *env, uint64_t cc) env->psw.mask |= (cc & 3) << 44; } -static int sclp_service_call(CPUState *env, struct kvm_run *run, uint16_t ipbh0) +static int kvm_sclp_service_call(CPUState *env, struct kvm_run *run, + uint16_t ipbh0) { uint32_t sccb; uint64_t code; @@ -287,7 +288,7 @@ static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1) dprintf("KVM: PRIV: %d\n", ipa1); switch (ipa1) { case PRIV_SCLP_CALL: - r = sclp_service_call(env, run, ipbh0); + r = kvm_sclp_service_call(env, run, ipbh0); break; default: dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); @@ -300,12 +301,10 @@ static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1) static int handle_hypercall(CPUState *env, struct kvm_run *run) { - int r; - cpu_synchronize_state(env); - r = s390_virtio_hypercall(env); + env->regs[2] = s390_virtio_hypercall(env, env->regs[2], env->regs[1]); - return r; + return 0; } static int handle_diag(CPUState *env, struct kvm_run *run, int ipb_code) diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 402df2d..be455b9 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -61,7 +61,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (likely(tb)) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } /* XXX */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d33bfb1..4d45e32 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -36,7 +36,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, } } for (i = 0; i < 16; i++) { - cpu_fprintf(f, "F%02d=%016lx", i, (long)env->fregs[i].i); + cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]); if ((i % 4) == 3) { cpu_fprintf(f, "\n"); } else { @@ -54,8 +54,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->psw.addr = gen_opc_pc[pc_pos]; } diff --git a/target-sh4/helper.h b/target-sh4/helper.h index 2e52768..95e3c7c 100644 --- a/target-sh4/helper.h +++ b/target-sh4/helper.h @@ -23,31 +23,31 @@ DEF_HELPER_2(macw, void, i32, i32) DEF_HELPER_1(ld_fpscr, void, i32) -DEF_HELPER_1(fabs_FT, i32, i32) -DEF_HELPER_1(fabs_DT, i64, i64) -DEF_HELPER_2(fadd_FT, i32, i32, i32) -DEF_HELPER_2(fadd_DT, i64, i64, i64) -DEF_HELPER_1(fcnvsd_FT_DT, i64, i32) -DEF_HELPER_1(fcnvds_DT_FT, i32, i64) +DEF_HELPER_1(fabs_FT, f32, f32) +DEF_HELPER_1(fabs_DT, f64, f64) +DEF_HELPER_2(fadd_FT, f32, f32, f32) +DEF_HELPER_2(fadd_DT, f64, f64, f64) +DEF_HELPER_1(fcnvsd_FT_DT, f64, f32) +DEF_HELPER_1(fcnvds_DT_FT, f32, f64) -DEF_HELPER_2(fcmp_eq_FT, void, i32, i32) -DEF_HELPER_2(fcmp_eq_DT, void, i64, i64) -DEF_HELPER_2(fcmp_gt_FT, void, i32, i32) -DEF_HELPER_2(fcmp_gt_DT, void, i64, i64) -DEF_HELPER_2(fdiv_FT, i32, i32, i32) -DEF_HELPER_2(fdiv_DT, i64, i64, i64) -DEF_HELPER_1(float_FT, i32, i32) -DEF_HELPER_1(float_DT, i64, i32) -DEF_HELPER_3(fmac_FT, i32, i32, i32, i32) -DEF_HELPER_2(fmul_FT, i32, i32, i32) -DEF_HELPER_2(fmul_DT, i64, i64, i64) -DEF_HELPER_1(fneg_T, i32, i32) -DEF_HELPER_2(fsub_FT, i32, i32, i32) -DEF_HELPER_2(fsub_DT, i64, i64, i64) -DEF_HELPER_1(fsqrt_FT, i32, i32) -DEF_HELPER_1(fsqrt_DT, i64, i64) -DEF_HELPER_1(ftrc_FT, i32, i32) -DEF_HELPER_1(ftrc_DT, i32, i64) +DEF_HELPER_2(fcmp_eq_FT, void, f32, f32) +DEF_HELPER_2(fcmp_eq_DT, void, f64, f64) +DEF_HELPER_2(fcmp_gt_FT, void, f32, f32) +DEF_HELPER_2(fcmp_gt_DT, void, f64, f64) +DEF_HELPER_2(fdiv_FT, f32, f32, f32) +DEF_HELPER_2(fdiv_DT, f64, f64, f64) +DEF_HELPER_1(float_FT, f32, i32) +DEF_HELPER_1(float_DT, f64, i32) +DEF_HELPER_3(fmac_FT, f32, f32, f32, f32) +DEF_HELPER_2(fmul_FT, f32, f32, f32) +DEF_HELPER_2(fmul_DT, f64, f64, f64) +DEF_HELPER_1(fneg_T, f32, f32) +DEF_HELPER_2(fsub_FT, f32, f32, f32) +DEF_HELPER_2(fsub_DT, f64, f64, f64) +DEF_HELPER_1(fsqrt_FT, f32, f32) +DEF_HELPER_1(fsqrt_DT, f64, f64) +DEF_HELPER_1(ftrc_FT, i32, f32) +DEF_HELPER_1(ftrc_DT, i32, f64) DEF_HELPER_2(fipr, void, i32, i32) DEF_HELPER_1(ftrv, void, i32) diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index b8f4ca2..b909d18 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -32,7 +32,7 @@ static void cpu_restore_state_from_retaddr(void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } } @@ -487,53 +487,38 @@ static void update_fpscr(void *retaddr) } } -uint32_t helper_fabs_FT(uint32_t t0) +float32 helper_fabs_FT(float32 t0) { - CPU_FloatU f; - f.l = t0; - f.f = float32_abs(f.f); - return f.l; + return float32_abs(t0); } -uint64_t helper_fabs_DT(uint64_t t0) +float64 helper_fabs_DT(float64 t0) { - CPU_DoubleU d; - d.ll = t0; - d.d = float64_abs(d.d); - return d.ll; + return float64_abs(t0); } -uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1) +float32 helper_fadd_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - f0.f = float32_add(f0.f, f1.f, &env->fp_status); + t0 = float32_add(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return f0.l; + return t0; } -uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1) +float64 helper_fadd_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - d0.d = float64_add(d0.d, d1.d, &env->fp_status); + t0 = float64_add(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return d0.ll; + return t0; } -void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1) +void helper_fcmp_eq_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; int relation; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - relation = float32_compare(f0.f, f1.f, &env->fp_status); + relation = float32_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_equal) { @@ -543,15 +528,12 @@ void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1) } } -void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1) +void helper_fcmp_eq_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; int relation; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - relation = float64_compare(d0.d, d1.d, &env->fp_status); + relation = float64_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_equal) { @@ -561,15 +543,12 @@ void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1) } } -void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1) +void helper_fcmp_gt_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; int relation; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - relation = float32_compare(f0.f, f1.f, &env->fp_status); + relation = float32_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_greater) { @@ -579,15 +558,12 @@ void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1) } } -void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1) +void helper_fcmp_gt_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; int relation; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - relation = float64_compare(d0.d, d1.d, &env->fp_status); + relation = float64_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_greater) { @@ -597,176 +573,134 @@ void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1) } } -uint64_t helper_fcnvsd_FT_DT(uint32_t t0) +float64 helper_fcnvsd_FT_DT(float32 t0) { - CPU_DoubleU d; - CPU_FloatU f; - f.l = t0; + float64 ret; set_float_exception_flags(0, &env->fp_status); - d.d = float32_to_float64(f.f, &env->fp_status); + ret = float32_to_float64(t0, &env->fp_status); update_fpscr(GETPC()); - return d.ll; + return ret; } -uint32_t helper_fcnvds_DT_FT(uint64_t t0) +float32 helper_fcnvds_DT_FT(float64 t0) { - CPU_DoubleU d; - CPU_FloatU f; - d.ll = t0; + float32 ret; set_float_exception_flags(0, &env->fp_status); - f.f = float64_to_float32(d.d, &env->fp_status); + ret = float64_to_float32(t0, &env->fp_status); update_fpscr(GETPC()); - return f.l; + return ret; } -uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1) +float32 helper_fdiv_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - f0.f = float32_div(f0.f, f1.f, &env->fp_status); + t0 = float32_div(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return f0.l; + return t0; } -uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1) +float64 helper_fdiv_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - d0.d = float64_div(d0.d, d1.d, &env->fp_status); + t0 = float64_div(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return d0.ll; + return t0; } -uint32_t helper_float_FT(uint32_t t0) +float32 helper_float_FT(uint32_t t0) { - CPU_FloatU f; - + float32 ret; set_float_exception_flags(0, &env->fp_status); - f.f = int32_to_float32(t0, &env->fp_status); + ret = int32_to_float32(t0, &env->fp_status); update_fpscr(GETPC()); - - return f.l; + return ret; } -uint64_t helper_float_DT(uint32_t t0) +float64 helper_float_DT(uint32_t t0) { - CPU_DoubleU d; + float64 ret; set_float_exception_flags(0, &env->fp_status); - d.d = int32_to_float64(t0, &env->fp_status); + ret = int32_to_float64(t0, &env->fp_status); update_fpscr(GETPC()); - return d.ll; + return ret; } -uint32_t helper_fmac_FT(uint32_t t0, uint32_t t1, uint32_t t2) +float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2) { - CPU_FloatU f0, f1, f2; - f0.l = t0; - f1.l = t1; - f2.l = t2; set_float_exception_flags(0, &env->fp_status); - f0.f = float32_mul(f0.f, f1.f, &env->fp_status); - f0.f = float32_add(f0.f, f2.f, &env->fp_status); + t0 = float32_mul(t0, t1, &env->fp_status); + t0 = float32_add(t0, t2, &env->fp_status); update_fpscr(GETPC()); - - return f0.l; + return t0; } -uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1) +float32 helper_fmul_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - f0.f = float32_mul(f0.f, f1.f, &env->fp_status); + t0 = float32_mul(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return f0.l; + return t0; } -uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1) +float64 helper_fmul_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - d0.d = float64_mul(d0.d, d1.d, &env->fp_status); + t0 = float64_mul(t0, t1, &env->fp_status); update_fpscr(GETPC()); - - return d0.ll; + return t0; } -uint32_t helper_fneg_T(uint32_t t0) +float32 helper_fneg_T(float32 t0) { - CPU_FloatU f; - f.l = t0; - f.f = float32_chs(f.f); - return f.l; + return float32_chs(t0); } -uint32_t helper_fsqrt_FT(uint32_t t0) +float32 helper_fsqrt_FT(float32 t0) { - CPU_FloatU f; - f.l = t0; set_float_exception_flags(0, &env->fp_status); - f.f = float32_sqrt(f.f, &env->fp_status); + t0 = float32_sqrt(t0, &env->fp_status); update_fpscr(GETPC()); - return f.l; + return t0; } -uint64_t helper_fsqrt_DT(uint64_t t0) +float64 helper_fsqrt_DT(float64 t0) { - CPU_DoubleU d; - d.ll = t0; set_float_exception_flags(0, &env->fp_status); - d.d = float64_sqrt(d.d, &env->fp_status); + t0 = float64_sqrt(t0, &env->fp_status); update_fpscr(GETPC()); - return d.ll; + return t0; } -uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1) +float32 helper_fsub_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - f0.f = float32_sub(f0.f, f1.f, &env->fp_status); + t0 = float32_sub(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return f0.l; + return t0; } -uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1) +float64 helper_fsub_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; - - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - d0.d = float64_sub(d0.d, d1.d, &env->fp_status); + t0 = float64_sub(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return d0.ll; + return t0; } -uint32_t helper_ftrc_FT(uint32_t t0) +uint32_t helper_ftrc_FT(float32 t0) { - CPU_FloatU f; uint32_t ret; - f.l = t0; set_float_exception_flags(0, &env->fp_status); - ret = float32_to_int32_round_to_zero(f.f, &env->fp_status); + ret = float32_to_int32_round_to_zero(t0, &env->fp_status); update_fpscr(GETPC()); return ret; } -uint32_t helper_ftrc_DT(uint64_t t0) +uint32_t helper_ftrc_DT(float64 t0) { - CPU_DoubleU d; uint32_t ret; - d.ll = t0; set_float_exception_flags(0, &env->fp_status); - ret = float64_to_int32_round_to_zero(d.d, &env->fp_status); + ret = float64_to_int32_round_to_zero(t0, &env->fp_status); update_fpscr(GETPC()); return ret; } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 58e9b8f..93c8636 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -302,7 +302,7 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) /* Use a direct jump if in same page and singlestep not enabled */ tcg_gen_goto_tb(n); tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb((long) tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_i32(cpu_pc, dest); if (ctx->singlestep_enabled) @@ -2069,8 +2069,7 @@ void gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; env->flags = gen_opc_hflags[pc_pos]; diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 854f168..ffffb8c 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -4375,7 +4375,7 @@ static void cpu_restore_state2(void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, (void *)(long)env->cond); + cpu_restore_state(tb, env, pc); } } } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e26462e..3c958b2 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -241,7 +241,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, tcg_gen_goto_tb(tb_num); tcg_gen_movi_tl(cpu_pc, pc); tcg_gen_movi_tl(cpu_npc, npc); - tcg_gen_exit_tb((long)tb + tb_num); + tcg_gen_exit_tb((tcg_target_long)tb + tb_num); } else { /* jump to another page: currently not optimized */ tcg_gen_movi_tl(cpu_pc, pc); @@ -5080,8 +5080,7 @@ void gen_intermediate_code_init(CPUSPARCState *env) } } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { target_ulong npc; env->pc = gen_opc_pc[pc_pos]; diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h new file mode 100644 index 0000000..1e10049 --- /dev/null +++ b/target-unicore32/cpu.h @@ -0,0 +1,182 @@ +/* + * UniCore32 virtual CPU header + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __CPU_UC32_H__ +#define __CPU_UC32_H__ + +#define TARGET_LONG_BITS 32 +#define TARGET_PAGE_BITS 12 + +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 + +#define ELF_MACHINE EM_UNICORE32 + +#define CPUState struct CPUState_UniCore32 + +#include "cpu-defs.h" +#include "softfloat.h" + +#define NB_MMU_MODES 2 + +typedef struct CPUState_UniCore32 { + /* Regs for current mode. */ + uint32_t regs[32]; + /* Frequently accessed ASR bits are stored separately for efficiently. + This contains all the other bits. Use asr_{read,write} to access + the whole ASR. */ + uint32_t uncached_asr; + uint32_t bsr; + + /* Banked registers. */ + uint32_t banked_bsr[6]; + uint32_t banked_r29[6]; + uint32_t banked_r30[6]; + + /* asr flag cache for faster execution */ + uint32_t CF; /* 0 or 1 */ + uint32_t VF; /* V is the bit 31. All other bits are undefined */ + uint32_t NF; /* N is bit 31. All other bits are undefined. */ + uint32_t ZF; /* Z set if zero. */ + + /* System control coprocessor (cp0) */ + struct { + uint32_t c0_cpuid; + uint32_t c0_cachetype; + uint32_t c1_sys; /* System control register. */ + uint32_t c2_base; /* MMU translation table base. */ + uint32_t c3_faultstatus; /* Fault status registers. */ + uint32_t c4_faultaddr; /* Fault address registers. */ + uint32_t c5_cacheop; /* Cache operation registers. */ + uint32_t c6_tlbop; /* TLB operation registers. */ + } cp0; + + /* UniCore-F64 coprocessor state. */ + struct { + float64 regs[16]; + uint32_t xregs[32]; + float_status fp_status; + } ucf64; + + CPU_COMMON + + /* Internal CPU feature flags. */ + uint32_t features; + +} CPUState_UniCore32; + +#define ASR_M (0x1f) +#define ASR_MODE_USER (0x10) +#define ASR_MODE_INTR (0x12) +#define ASR_MODE_PRIV (0x13) +#define ASR_MODE_TRAP (0x17) +#define ASR_MODE_EXTN (0x1b) +#define ASR_MODE_SUSR (0x1f) +#define ASR_I (1 << 7) +#define ASR_V (1 << 28) +#define ASR_C (1 << 29) +#define ASR_Z (1 << 30) +#define ASR_N (1 << 31) +#define ASR_NZCV (ASR_N | ASR_Z | ASR_C | ASR_V) +#define ASR_RESERVED (~(ASR_M | ASR_I | ASR_NZCV)) + +#define UC32_EXCP_PRIV (ASR_MODE_PRIV) +#define UC32_EXCP_TRAP (ASR_MODE_TRAP) + +/* Return the current ASR value. */ +target_ulong cpu_asr_read(CPUState *env1); +/* Set the ASR. Note that some bits of mask must be all-set or all-clear. */ +void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask); + +/* UniCore-F64 system registers. */ +#define UC32_UCF64_FPSCR (31) +#define UCF64_FPSCR_MASK (0x27ffffff) +#define UCF64_FPSCR_RND_MASK (0x7) +#define UCF64_FPSCR_RND(r) (((r) >> 0) & UCF64_FPSCR_RND_MASK) +#define UCF64_FPSCR_TRAPEN_MASK (0x7f) +#define UCF64_FPSCR_TRAPEN(r) (((r) >> 10) & UCF64_FPSCR_TRAPEN_MASK) +#define UCF64_FPSCR_FLAG_MASK (0x3ff) +#define UCF64_FPSCR_FLAG(r) (((r) >> 17) & UCF64_FPSCR_FLAG_MASK) +#define UCF64_FPSCR_FLAG_ZERO (1 << 17) +#define UCF64_FPSCR_FLAG_INFINITY (1 << 18) +#define UCF64_FPSCR_FLAG_INVALID (1 << 19) +#define UCF64_FPSCR_FLAG_UNDERFLOW (1 << 20) +#define UCF64_FPSCR_FLAG_OVERFLOW (1 << 21) +#define UCF64_FPSCR_FLAG_INEXACT (1 << 22) +#define UCF64_FPSCR_FLAG_HUGEINT (1 << 23) +#define UCF64_FPSCR_FLAG_DENORMAL (1 << 24) +#define UCF64_FPSCR_FLAG_UNIMP (1 << 25) +#define UCF64_FPSCR_FLAG_DIVZERO (1 << 26) + +#define UC32_HWCAP_CMOV 4 /* 1 << 2 */ +#define UC32_HWCAP_UCF64 8 /* 1 << 3 */ + +#define UC32_CPUID(env) (env->cp0.c0_cpuid) +#define UC32_CPUID_UCV2 0x40010863 +#define UC32_CPUID_ANY 0xffffffff + +#define cpu_init uc32_cpu_init +#define cpu_exec uc32_cpu_exec +#define cpu_signal_handler uc32_cpu_signal_handler +#define cpu_handle_mmu_fault uc32_cpu_handle_mmu_fault + +CPUState *uc32_cpu_init(const char *cpu_model); +int uc32_cpu_exec(CPUState *s); +int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc); +int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmuu); + +#define CPU_SAVE_VERSION 2 + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index(CPUState *env) +{ + return (env->uncached_asr & ASR_M) == ASR_MODE_USER ? 1 : 0; +} + +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) { + env->regs[29] = newsp; + } + env->regs[0] = 0; +} + +static inline void cpu_set_tls(CPUState *env, target_ulong newtls) +{ + env->regs[16] = newtls; +} + +#include "cpu-all.h" +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->regs[31] = tb->pc; +} + +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->regs[31]; + *cs_base = 0; + *flags = 0; + if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) { + *flags |= (1 << 6); + } +} + +void uc32_translate_init(void); +void do_interrupt(CPUState *); +void switch_mode(CPUState_UniCore32 *, int); + +#endif /* __CPU_UC32_H__ */ diff --git a/target-unicore32/exec.h b/target-unicore32/exec.h new file mode 100644 index 0000000..4ab55f4 --- /dev/null +++ b/target-unicore32/exec.h @@ -0,0 +1,50 @@ +/* + * UniCore32 execution defines + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __UC32_EXEC_H__ +#define __UC32_EXEC_H__ + +#include "config.h" +#include "dyngen-exec.h" + +register struct CPUState_UniCore32 *env asm(AREG0); + +#include "cpu.h" +#include "exec-all.h" + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +static inline int cpu_has_work(CPUState *env) +{ + return env->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); +} + +static inline int cpu_halted(CPUState *env) +{ + if (!env->halted) { + return 0; + } + /* An interrupt wakes the CPU even if the I and R ASR bits are + set. We use EXITTB to silently wake CPU without causing an + actual interrupt. */ + if (cpu_has_work(env)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + +#endif /* __UC32_EXEC_H__ */ diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c new file mode 100644 index 0000000..483aeae --- /dev/null +++ b/target-unicore32/helper.c @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cpu.h" +#include "exec-all.h" +#include "gdbstub.h" +#include "helper.h" +#include "qemu-common.h" +#include "host-utils.h" + +static inline void set_feature(CPUState *env, int feature) +{ + env->features |= feature; +} + +struct uc32_cpu_t { + uint32_t id; + const char *name; +}; + +static const struct uc32_cpu_t uc32_cpu_names[] = { + { UC32_CPUID_UCV2, "UniCore-II"}, + { UC32_CPUID_ANY, "any"}, + { 0, NULL} +}; + +/* return 0 if not found */ +static uint32_t uc32_cpu_find_by_name(const char *name) +{ + int i; + uint32_t id; + + id = 0; + for (i = 0; uc32_cpu_names[i].name; i++) { + if (strcmp(name, uc32_cpu_names[i].name) == 0) { + id = uc32_cpu_names[i].id; + break; + } + } + return id; +} + +CPUState *uc32_cpu_init(const char *cpu_model) +{ + CPUState *env; + uint32_t id; + static int inited = 1; + + env = qemu_mallocz(sizeof(CPUState)); + cpu_exec_init(env); + + id = uc32_cpu_find_by_name(cpu_model); + switch (id) { + case UC32_CPUID_UCV2: + set_feature(env, UC32_HWCAP_CMOV); + set_feature(env, UC32_HWCAP_UCF64); + env->ucf64.xregs[UC32_UCF64_FPSCR] = 0; + env->cp0.c0_cachetype = 0x1dd20d2; + env->cp0.c1_sys = 0x00090078; + break; + case UC32_CPUID_ANY: /* For userspace emulation. */ + set_feature(env, UC32_HWCAP_CMOV); + set_feature(env, UC32_HWCAP_UCF64); + break; + default: + cpu_abort(env, "Bad CPU ID: %x\n", id); + } + + env->cpu_model_str = cpu_model; + env->cp0.c0_cpuid = id; + env->uncached_asr = ASR_MODE_USER; + env->regs[31] = 0; + + if (inited) { + inited = 0; + uc32_translate_init(); + } + + tlb_flush(env, 1); + qemu_init_vcpu(env); + return env; +} + +uint32_t HELPER(clo)(uint32_t x) +{ + return clo32(x); +} + +uint32_t HELPER(clz)(uint32_t x) +{ + return clz32(x); +} + +void do_interrupt(CPUState *env) +{ + env->exception_index = -1; +} + +int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) +{ + env->exception_index = UC32_EXCP_TRAP; + env->cp0.c4_faultaddr = address; + return 1; +} + +/* These should probably raise undefined insn exceptions. */ +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return; +} + +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return 0; +} + +void HELPER(set_cp0)(CPUState *env, uint32_t insn, uint32_t val) +{ + cpu_abort(env, "cp0 insn %08x\n", insn); +} + +uint32_t HELPER(get_cp0)(CPUState *env, uint32_t insn) +{ + cpu_abort(env, "cp0 insn %08x\n", insn); + return 0; +} + +void switch_mode(CPUState *env, int mode) +{ + if (mode != ASR_MODE_USER) { + cpu_abort(env, "Tried to switch out of user mode\n"); + } +} + +void HELPER(set_r29_banked)(CPUState *env, uint32_t mode, uint32_t val) +{ + cpu_abort(env, "banked r29 write\n"); +} + +uint32_t HELPER(get_r29_banked)(CPUState *env, uint32_t mode) +{ + cpu_abort(env, "banked r29 read\n"); + return 0; +} + +/* UniCore-F64 support. We follow the convention used for F64 instrunctions: + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ + +/* Convert host exception flags to f64 form. */ +static inline int ucf64_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + + if (host_bits & float_flag_invalid) { + target_bits |= UCF64_FPSCR_FLAG_INVALID; + } + if (host_bits & float_flag_divbyzero) { + target_bits |= UCF64_FPSCR_FLAG_DIVZERO; + } + if (host_bits & float_flag_overflow) { + target_bits |= UCF64_FPSCR_FLAG_OVERFLOW; + } + if (host_bits & float_flag_underflow) { + target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW; + } + if (host_bits & float_flag_inexact) { + target_bits |= UCF64_FPSCR_FLAG_INEXACT; + } + return target_bits; +} + +uint32_t HELPER(ucf64_get_fpscr)(CPUState *env) +{ + int i; + uint32_t fpscr; + + fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK); + i = get_float_exception_flags(&env->ucf64.fp_status); + fpscr |= ucf64_exceptbits_from_host(i); + return fpscr; +} + +/* Convert ucf64 exception flags to target form. */ +static inline int ucf64_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + + if (target_bits & UCF64_FPSCR_FLAG_INVALID) { + host_bits |= float_flag_invalid; + } + if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) { + host_bits |= float_flag_divbyzero; + } + if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) { + host_bits |= float_flag_overflow; + } + if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) { + host_bits |= float_flag_underflow; + } + if (target_bits & UCF64_FPSCR_FLAG_INEXACT) { + host_bits |= float_flag_inexact; + } + return host_bits; +} + +void HELPER(ucf64_set_fpscr)(CPUState *env, uint32_t val) +{ + int i; + uint32_t changed; + + changed = env->ucf64.xregs[UC32_UCF64_FPSCR]; + env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK); + + changed ^= val; + if (changed & (UCF64_FPSCR_RND_MASK)) { + i = UCF64_FPSCR_RND(val); + switch (i) { + case 0: + i = float_round_nearest_even; + break; + case 1: + i = float_round_to_zero; + break; + case 2: + i = float_round_up; + break; + case 3: + i = float_round_down; + break; + default: /* 100 and 101 not implement */ + cpu_abort(env, "Unsupported UniCore-F64 round mode"); + } + set_float_rounding_mode(i, &env->ucf64.fp_status); + } + + i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val)); + set_float_exception_flags(i, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUState *env) +{ + return float32_add(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUState *env) +{ + return float64_add(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUState *env) +{ + return float32_sub(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUState *env) +{ + return float64_sub(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUState *env) +{ + return float32_mul(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUState *env) +{ + return float64_mul(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUState *env) +{ + return float32_div(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUState *env) +{ + return float64_div(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_negs)(float32 a) +{ + return float32_chs(a); +} + +float64 HELPER(ucf64_negd)(float64 a) +{ + return float64_chs(a); +} + +float32 HELPER(ucf64_abss)(float32 a) +{ + return float32_abs(a); +} + +float64 HELPER(ucf64_absd)(float64 a) +{ + return float64_abs(a); +} + +/* XXX: check quiet/signaling case */ +void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUState *env) +{ + int flag; + flag = float32_compare_quiet(a, b, &env->ucf64.fp_status); + env->CF = 0; + switch (c & 0x7) { + case 0: /* F */ + break; + case 1: /* UN */ + if (flag == 2) { + env->CF = 1; + } + break; + case 2: /* EQ */ + if (flag == 0) { + env->CF = 1; + } + break; + case 3: /* UEQ */ + if ((flag == 0) || (flag == 2)) { + env->CF = 1; + } + break; + case 4: /* OLT */ + if (flag == -1) { + env->CF = 1; + } + break; + case 5: /* ULT */ + if ((flag == -1) || (flag == 2)) { + env->CF = 1; + } + break; + case 6: /* OLE */ + if ((flag == -1) || (flag == 0)) { + env->CF = 1; + } + break; + case 7: /* ULE */ + if (flag != 1) { + env->CF = 1; + } + break; + } + env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) + | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); +} + +void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUState *env) +{ + int flag; + flag = float64_compare_quiet(a, b, &env->ucf64.fp_status); + env->CF = 0; + switch (c & 0x7) { + case 0: /* F */ + break; + case 1: /* UN */ + if (flag == 2) { + env->CF = 1; + } + break; + case 2: /* EQ */ + if (flag == 0) { + env->CF = 1; + } + break; + case 3: /* UEQ */ + if ((flag == 0) || (flag == 2)) { + env->CF = 1; + } + break; + case 4: /* OLT */ + if (flag == -1) { + env->CF = 1; + } + break; + case 5: /* ULT */ + if ((flag == -1) || (flag == 2)) { + env->CF = 1; + } + break; + case 6: /* OLE */ + if ((flag == -1) || (flag == 0)) { + env->CF = 1; + } + break; + case 7: /* ULE */ + if (flag != 1) { + env->CF = 1; + } + break; + } + env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) + | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); +} + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 ucf64_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t ucf64_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +static inline float64 ucf64_itod(uint64_t i) +{ + union { + uint64_t i; + float64 d; + } v; + + v.i = i; + return v.d; +} + +static inline uint64_t ucf64_dtoi(float64 d) +{ + union { + uint64_t i; + float64 d; + } v; + + v.d = d; + return v.i; +} + +/* Integer to float conversion. */ +float32 HELPER(ucf64_si2sf)(float32 x, CPUState *env) +{ + return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_si2df)(float32 x, CPUState *env) +{ + return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status); +} + +/* Float to integer conversion. */ +float32 HELPER(ucf64_sf2si)(float32 x, CPUState *env) +{ + return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status)); +} + +float32 HELPER(ucf64_df2si)(float64 x, CPUState *env) +{ + return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status)); +} + +/* floating point conversion */ +float64 HELPER(ucf64_sf2df)(float32 x, CPUState *env) +{ + return float32_to_float64(x, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_df2sf)(float64 x, CPUState *env) +{ + return float64_to_float32(x, &env->ucf64.fp_status); +} diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h new file mode 100644 index 0000000..615de2a --- /dev/null +++ b/target-unicore32/helper.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "def-helper.h" + +DEF_HELPER_1(clz, i32, i32) +DEF_HELPER_1(clo, i32, i32) + +DEF_HELPER_1(exception, void, i32) + +DEF_HELPER_2(asr_write, void, i32, i32) +DEF_HELPER_0(asr_read, i32) + +DEF_HELPER_3(set_cp0, void, env, i32, i32) +DEF_HELPER_2(get_cp0, i32, env, i32) + +DEF_HELPER_3(set_cp, void, env, i32, i32) +DEF_HELPER_2(get_cp, i32, env, i32) + +DEF_HELPER_1(get_user_reg, i32, i32) +DEF_HELPER_2(set_user_reg, void, i32, i32) + +DEF_HELPER_2(add_cc, i32, i32, i32) +DEF_HELPER_2(adc_cc, i32, i32, i32) +DEF_HELPER_2(sub_cc, i32, i32, i32) +DEF_HELPER_2(sbc_cc, i32, i32, i32) + +DEF_HELPER_2(shl, i32, i32, i32) +DEF_HELPER_2(shr, i32, i32, i32) +DEF_HELPER_2(sar, i32, i32, i32) +DEF_HELPER_2(shl_cc, i32, i32, i32) +DEF_HELPER_2(shr_cc, i32, i32, i32) +DEF_HELPER_2(sar_cc, i32, i32, i32) +DEF_HELPER_2(ror_cc, i32, i32, i32) + +DEF_HELPER_2(get_r29_banked, i32, env, i32) +DEF_HELPER_3(set_r29_banked, void, env, i32, i32) + +DEF_HELPER_1(ucf64_get_fpscr, i32, env) +DEF_HELPER_2(ucf64_set_fpscr, void, env, i32) + +DEF_HELPER_3(ucf64_adds, f32, f32, f32, env) +DEF_HELPER_3(ucf64_addd, f64, f64, f64, env) +DEF_HELPER_3(ucf64_subs, f32, f32, f32, env) +DEF_HELPER_3(ucf64_subd, f64, f64, f64, env) +DEF_HELPER_3(ucf64_muls, f32, f32, f32, env) +DEF_HELPER_3(ucf64_muld, f64, f64, f64, env) +DEF_HELPER_3(ucf64_divs, f32, f32, f32, env) +DEF_HELPER_3(ucf64_divd, f64, f64, f64, env) +DEF_HELPER_1(ucf64_negs, f32, f32) +DEF_HELPER_1(ucf64_negd, f64, f64) +DEF_HELPER_1(ucf64_abss, f32, f32) +DEF_HELPER_1(ucf64_absd, f64, f64) +DEF_HELPER_4(ucf64_cmps, void, f32, f32, i32, env) +DEF_HELPER_4(ucf64_cmpd, void, f64, f64, i32, env) + +DEF_HELPER_2(ucf64_sf2df, f64, f32, env) +DEF_HELPER_2(ucf64_df2sf, f32, f64, env) + +DEF_HELPER_2(ucf64_si2sf, f32, f32, env) +DEF_HELPER_2(ucf64_si2df, f64, f32, env) + +DEF_HELPER_2(ucf64_sf2si, f32, f32, env) +DEF_HELPER_2(ucf64_df2si, f32, f64, env) + +#include "def-helper.h" diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c new file mode 100644 index 0000000..31e4b11 --- /dev/null +++ b/target-unicore32/op_helper.c @@ -0,0 +1,248 @@ +/* + * UniCore32 helper routines + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "exec.h" +#include "helper.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) + +void HELPER(exception)(uint32_t excp) +{ + env->exception_index = excp; + cpu_loop_exit(); +} + +static target_ulong asr_read(void) +{ + int ZF; + ZF = (env->ZF == 0); + return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); +} + +target_ulong cpu_asr_read(CPUState *env1) +{ + CPUState *saved_env; + target_ulong ret; + + saved_env = env; + env = env1; + ret = asr_read(); + env = saved_env; + return ret; +} + +target_ulong HELPER(asr_read)(void) +{ + return asr_read(); +} + +static void asr_write(target_ulong val, target_ulong mask) +{ + if (mask & ASR_NZCV) { + env->ZF = (~val) & ASR_Z; + env->NF = val; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + + if ((env->uncached_asr ^ val) & mask & ASR_M) { + switch_mode(env, val & ASR_M); + } + mask &= ~ASR_NZCV; + env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask); +} + +void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + asr_write(val, mask); + env = saved_env; +} + +void HELPER(asr_write)(target_ulong val, target_ulong mask) +{ + asr_write(val, mask); +} + +/* Access to user mode registers from privileged modes. */ +uint32_t HELPER(get_user_reg)(uint32_t regno) +{ + uint32_t val; + + if (regno == 29) { + val = env->banked_r29[0]; + } else if (regno == 30) { + val = env->banked_r30[0]; + } else { + val = env->regs[regno]; + } + return val; +} + +void HELPER(set_user_reg)(uint32_t regno, uint32_t val) +{ + if (regno == 29) { + env->banked_r29[0] = val; + } else if (regno == 30) { + env->banked_r30[0] = val; + } else { + env->regs[regno] = val; + } +} + +/* ??? Flag setting arithmetic is awkward because we need to do comparisons. + 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)(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)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a + b; + env->CF = result < a; + } else { + result = a + b + 1; + env->CF = result <= a; + } + env->VF = (a ^ b ^ -1) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +uint32_t HELPER(sub_cc)(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)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a - b - 1; + env->CF = a > b; + } else { + result = a - b; + env->CF = a >= b; + } + env->VF = (a ^ b) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +/* Similarly for variable shift instructions. */ + +uint32_t HELPER(shl)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + return 0; + } + return x << shift; +} + +uint32_t HELPER(shr)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + return 0; + } + return (uint32_t)x >> shift; +} + +uint32_t HELPER(sar)(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)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) { + env->CF = x & 1; + } else { + env->CF = 0; + } + return 0; + } else if (shift != 0) { + env->CF = (x >> (32 - shift)) & 1; + return x << shift; + } + return x; +} + +uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) { + env->CF = (x >> 31) & 1; + } else { + env->CF = 0; + } + return 0; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return x >> shift; + } + return x; +} + +uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + env->CF = (x >> 31) & 1; + return (int32_t)x >> 31; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return (int32_t)x >> shift; + } + return x; +} + +uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) +{ + int shift1, shift; + shift1 = i & 0xff; + shift = shift1 & 0x1f; + if (shift == 0) { + if (shift1 != 0) { + env->CF = (x >> 31) & 1; + } + return x; + } else { + env->CF = (x >> (shift - 1)) & 1; + return ((uint32_t)x >> shift) | (x << (32 - shift)); + } +} diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c new file mode 100644 index 0000000..98eaeb3 --- /dev/null +++ b/target-unicore32/translate.c @@ -0,0 +1,2104 @@ +/* + * UniCore32 translation + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "qemu-log.h" + +#include "helper.h" +#define GEN_HELPER 1 +#include "helper.h" + +/* internal defines */ +typedef struct DisasContext { + target_ulong pc; + int is_jmp; + /* Nonzero if this instruction has been conditionally skipped. */ + int condjmp; + /* The label that will be jumped to when the instruction is skipped. */ + int condlabel; + struct TranslationBlock *tb; + int singlestep_enabled; +} DisasContext; + +#define IS_USER(s) 1 + +/* These instructions trap after executing, so defer them until after the + conditional executions state has been updated. */ +#define DISAS_SYSCALL 5 + +static TCGv_ptr cpu_env; +static TCGv_i32 cpu_R[32]; + +/* FIXME: These should be removed. */ +static TCGv cpu_F0s, cpu_F1s; +static TCGv_i64 cpu_F0d, cpu_F1d; + +#include "gen-icount.h" + +static const char *regnames[] = { + "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", + "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" }; + +/* initialize TCG globals. */ +void uc32_translate_init(void) +{ + int i; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + for (i = 0; i < 32; i++) { + cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, regs[i]), regnames[i]); + } + +#define GEN_HELPER 2 +#include "helper.h" +} + +static int num_temps; + +/* Allocate a temporary variable. */ +static TCGv_i32 new_tmp(void) +{ + num_temps++; + return tcg_temp_new_i32(); +} + +/* Release a temporary variable. */ +static void dead_tmp(TCGv tmp) +{ + tcg_temp_free(tmp); + num_temps--; +} + +static inline TCGv load_cpu_offset(int offset) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, offset); + return tmp; +} + +#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name)) + +static inline void store_cpu_offset(TCGv var, int offset) +{ + tcg_gen_st_i32(var, cpu_env, offset); + dead_tmp(var); +} + +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUState, name)) + +/* Set a variable to the value of a CPU register. */ +static void load_reg_var(DisasContext *s, TCGv var, int reg) +{ + if (reg == 31) { + uint32_t addr; + /* normaly, since we updated PC */ + addr = (long)s->pc; + tcg_gen_movi_i32(var, addr); + } else { + tcg_gen_mov_i32(var, cpu_R[reg]); + } +} + +/* Create a new temporary and set it to the value of a CPU register. */ +static inline TCGv load_reg(DisasContext *s, int reg) +{ + TCGv tmp = new_tmp(); + load_reg_var(s, tmp, reg); + return tmp; +} + +/* Set a CPU register. The source must be a temporary and will be + marked as dead. */ +static void store_reg(DisasContext *s, int reg, TCGv var) +{ + if (reg == 31) { + tcg_gen_andi_i32(var, var, ~3); + s->is_jmp = DISAS_JUMP; + } + tcg_gen_mov_i32(cpu_R[reg], var); + dead_tmp(var); +} + +/* Value extensions. */ +#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var) +#define gen_uxth(var) tcg_gen_ext16u_i32(var, var) +#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var) +#define gen_sxth(var) tcg_gen_ext16s_i32(var, var) + +#define UCOP_REG_M (((insn) >> 0) & 0x1f) +#define UCOP_REG_N (((insn) >> 19) & 0x1f) +#define UCOP_REG_D (((insn) >> 14) & 0x1f) +#define UCOP_REG_S (((insn) >> 9) & 0x1f) +#define UCOP_REG_LO (((insn) >> 14) & 0x1f) +#define UCOP_REG_HI (((insn) >> 9) & 0x1f) +#define UCOP_SH_OP (((insn) >> 6) & 0x03) +#define UCOP_SH_IM (((insn) >> 9) & 0x1f) +#define UCOP_OPCODES (((insn) >> 25) & 0x0f) +#define UCOP_IMM_9 (((insn) >> 0) & 0x1ff) +#define UCOP_IMM10 (((insn) >> 0) & 0x3ff) +#define UCOP_IMM14 (((insn) >> 0) & 0x3fff) +#define UCOP_COND (((insn) >> 25) & 0x0f) +#define UCOP_CMOV_COND (((insn) >> 19) & 0x0f) +#define UCOP_CPNUM (((insn) >> 10) & 0x0f) +#define UCOP_UCF64_FMT (((insn) >> 24) & 0x03) +#define UCOP_UCF64_FUNC (((insn) >> 6) & 0x0f) +#define UCOP_UCF64_COND (((insn) >> 6) & 0x0f) + +#define UCOP_SET(i) ((insn) & (1 << (i))) +#define UCOP_SET_P UCOP_SET(28) +#define UCOP_SET_U UCOP_SET(27) +#define UCOP_SET_B UCOP_SET(26) +#define UCOP_SET_W UCOP_SET(25) +#define UCOP_SET_L UCOP_SET(24) +#define UCOP_SET_S UCOP_SET(24) + +#define ILLEGAL cpu_abort(env, \ + "Illegal UniCore32 instruction %x at line %d!", \ + insn, __LINE__) + +static inline void gen_set_asr(TCGv var, uint32_t mask) +{ + TCGv tmp_mask = tcg_const_i32(mask); + gen_helper_asr_write(var, tmp_mask); + tcg_temp_free_i32(tmp_mask); +} +/* Set NZCV flags from the high 4 bits of var. */ +#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV) + +static void gen_exception(int excp) +{ + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, excp); + gen_helper_exception(tmp); + dead_tmp(tmp); +} + +/* FIXME: Most targets have native widening multiplication. + It would be good to use that instead of a full wide multiply. */ +/* 32x32->64 multiply. Marks inputs as dead. */ +static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_extu_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_ext_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF)) + +/* Set CF to the top bit of var. */ +static void gen_set_CF_bit31(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 31); + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Set N and Z flags from var. */ +static inline void gen_logic_CC(TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF)); + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF)); +} + +/* 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); + dead_tmp(tmp); +} + +/* 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_subi_i32(dest, dest, 1); + dead_tmp(tmp); +} + +static void shifter_out_im(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift == 0) { + tcg_gen_andi_i32(tmp, var, 1); + } else { + tcg_gen_shri_i32(tmp, var, shift); + if (shift != 31) { + tcg_gen_andi_i32(tmp, tmp, 1); + } + } + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Shift by immediate. Includes special handling for shift == 0. */ +static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift, + int flags) +{ + switch (shiftop) { + case 0: /* LSL */ + if (shift != 0) { + if (flags) { + shifter_out_im(var, 32 - shift); + } + tcg_gen_shli_i32(var, var, shift); + } + break; + case 1: /* LSR */ + if (shift == 0) { + if (flags) { + tcg_gen_shri_i32(var, var, 31); + gen_set_CF(var); + } + tcg_gen_movi_i32(var, 0); + } else { + if (flags) { + shifter_out_im(var, shift - 1); + } + tcg_gen_shri_i32(var, var, shift); + } + break; + case 2: /* ASR */ + if (shift == 0) { + shift = 32; + } + if (flags) { + shifter_out_im(var, shift - 1); + } + if (shift == 32) { + shift = 31; + } + tcg_gen_sari_i32(var, var, shift); + break; + case 3: /* ROR/RRX */ + if (shift != 0) { + if (flags) { + shifter_out_im(var, shift - 1); + } + tcg_gen_rotri_i32(var, var, shift); break; + } else { + TCGv tmp = load_cpu_field(CF); + if (flags) { + shifter_out_im(var, 0); + } + tcg_gen_shri_i32(var, var, 1); + tcg_gen_shli_i32(tmp, tmp, 31); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); + } + } +}; + +static inline void gen_uc32_shift_reg(TCGv var, int shiftop, + TCGv shift, int flags) +{ + if (flags) { + switch (shiftop) { + case 0: + gen_helper_shl_cc(var, var, shift); + break; + case 1: + gen_helper_shr_cc(var, var, shift); + break; + case 2: + gen_helper_sar_cc(var, var, shift); + break; + case 3: + gen_helper_ror_cc(var, var, shift); + break; + } + } else { + switch (shiftop) { + case 0: + gen_helper_shl(var, var, shift); + break; + case 1: + gen_helper_shr(var, var, shift); + break; + case 2: + gen_helper_sar(var, var, shift); + break; + case 3: + tcg_gen_andi_i32(shift, shift, 0x1f); + tcg_gen_rotr_i32(var, var, shift); + break; + } + } + dead_tmp(shift); +} + +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); + break; + case 1: /* ne: !Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 2: /* cs: C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 3: /* cc: !C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 4: /* mi: N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 5: /* pl: !N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 6: /* vs: V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 7: /* vc: !V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 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); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 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); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 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); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + 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); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + 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); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + 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); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + default: + fprintf(stderr, "Bad condition code 0x%x\n", cc); + abort(); + } + dead_tmp(tmp); +} + +static const uint8_t table_logic_cc[16] = { + 1, /* and */ 1, /* xor */ 0, /* sub */ 0, /* rsb */ + 0, /* add */ 0, /* adc */ 0, /* sbc */ 0, /* rsc */ + 1, /* andl */ 1, /* xorl */ 0, /* cmp */ 0, /* cmn */ + 1, /* orr */ 1, /* mov */ 1, /* bic */ 1, /* mvn */ +}; + +/* Set PC state from an immediate address. */ +static inline void gen_bx_im(DisasContext *s, uint32_t addr) +{ + s->is_jmp = DISAS_UPDATE; + tcg_gen_movi_i32(cpu_R[31], addr & ~3); +} + +/* Set PC state from var. var is marked as dead. */ +static inline void gen_bx(DisasContext *s, TCGv var) +{ + s->is_jmp = DISAS_UPDATE; + tcg_gen_andi_i32(cpu_R[31], var, ~3); + dead_tmp(var); +} + +static inline void store_reg_bx(DisasContext *s, int reg, TCGv var) +{ + store_reg(s, reg, var); +} + +static inline TCGv gen_ld8s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8s(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld8u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8u(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld16s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16s(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld16u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16u(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld32(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld32u(tmp, addr, index); + return tmp; +} + +static inline TCGv_i64 gen_ld64(TCGv addr, int index) +{ + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp, addr, index); + return tmp; +} + +static inline void gen_st8(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st8(val, addr, index); + dead_tmp(val); +} + +static inline void gen_st16(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st16(val, addr, index); + dead_tmp(val); +} + +static inline void gen_st32(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st32(val, addr, index); + dead_tmp(val); +} + +static inline void gen_st64(TCGv_i64 val, TCGv addr, int index) +{ + tcg_gen_qemu_st64(val, addr, index); + tcg_temp_free_i64(val); +} + +static inline void gen_set_pc_im(uint32_t val) +{ + tcg_gen_movi_i32(cpu_R[31], val); +} + +/* Force a TB lookup after an instruction that changes the CPU state. */ +static inline void gen_lookup_tb(DisasContext *s) +{ + tcg_gen_movi_i32(cpu_R[31], s->pc & ~1); + s->is_jmp = DISAS_UPDATE; +} + +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, + TCGv var) +{ + int val; + TCGv offset; + + if (UCOP_SET(29)) { + /* immediate */ + val = UCOP_IMM14; + if (!UCOP_SET_U) { + val = -val; + } + if (val != 0) { + tcg_gen_addi_i32(var, var, val); + } + } else { + /* shift/register */ + offset = load_reg(s, UCOP_REG_M); + gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0); + if (!UCOP_SET_U) { + tcg_gen_sub_i32(var, var, offset); + } else { + tcg_gen_add_i32(var, var, offset); + } + dead_tmp(offset); + } +} + +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, + TCGv var) +{ + int val; + TCGv offset; + + if (UCOP_SET(26)) { + /* immediate */ + val = (insn & 0x1f) | ((insn >> 4) & 0x3e0); + if (!UCOP_SET_U) { + val = -val; + } + if (val != 0) { + tcg_gen_addi_i32(var, var, val); + } + } else { + /* register */ + offset = load_reg(s, UCOP_REG_M); + if (!UCOP_SET_U) { + tcg_gen_sub_i32(var, var, offset); + } else { + tcg_gen_add_i32(var, var, offset); + } + dead_tmp(offset); + } +} + +static inline long ucf64_reg_offset(int reg) +{ + if (reg & 1) { + return offsetof(CPUState, ucf64.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.upper); + } else { + return offsetof(CPUState, ucf64.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.lower); + } +} + +#define ucf64_gen_ld32(reg) load_cpu_offset(ucf64_reg_offset(reg)) +#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg)) + +/* UniCore-F64 single load/store I_offset */ +static void do_ucf64_ldst_i(CPUState *env, DisasContext *s, uint32_t insn) +{ + int offset; + TCGv tmp; + TCGv addr; + + addr = load_reg(s, UCOP_REG_N); + if (!UCOP_SET_P && !UCOP_SET_W) { + ILLEGAL; + } + + if (UCOP_SET_P) { + offset = UCOP_IMM10 << 2; + if (!UCOP_SET_U) { + offset = -offset; + } + if (offset != 0) { + tcg_gen_addi_i32(addr, addr, offset); + } + } + + if (UCOP_SET_L) { /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + ucf64_gen_st32(tmp, UCOP_REG_D); + } else { /* store */ + tmp = ucf64_gen_ld32(UCOP_REG_D); + gen_st32(tmp, addr, IS_USER(s)); + } + + if (!UCOP_SET_P) { + offset = UCOP_IMM10 << 2; + if (!UCOP_SET_U) { + offset = -offset; + } + if (offset != 0) { + tcg_gen_addi_i32(addr, addr, offset); + } + } + if (UCOP_SET_W) { + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } +} + +/* UniCore-F64 load/store multiple words */ +static void do_ucf64_ldst_m(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int i; + int j, n, freg; + TCGv tmp; + TCGv addr; + + if (UCOP_REG_D != 0) { + ILLEGAL; + } + if (UCOP_REG_N == 31) { + ILLEGAL; + } + if ((insn << 24) == 0) { + ILLEGAL; + } + + addr = load_reg(s, UCOP_REG_N); + + n = 0; + for (i = 0; i < 8; i++) { + if (UCOP_SET(i)) { + n++; + } + } + + if (UCOP_SET_U) { + if (UCOP_SET_P) { /* pre increment */ + tcg_gen_addi_i32(addr, addr, 4); + } /* unnecessary to do anything when post increment */ + } else { + if (UCOP_SET_P) { /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } else { /* post decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } + } + + freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */ + + for (i = 0, j = 0; i < 8; i++, freg++) { + if (!UCOP_SET(i)) { + continue; + } + + if (UCOP_SET_L) { /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + ucf64_gen_st32(tmp, freg); + } else { /* store */ + tmp = ucf64_gen_ld32(freg); + gen_st32(tmp, addr, IS_USER(s)); + } + + j++; + /* unnecessary to add after the last transfer */ + if (j != n) { + tcg_gen_addi_i32(addr, addr, 4); + } + } + + if (UCOP_SET_W) { /* write back */ + if (UCOP_SET_U) { + if (!UCOP_SET_P) { /* post increment */ + tcg_gen_addi_i32(addr, addr, 4); + } /* unnecessary to do anything when pre increment */ + } else { + if (UCOP_SET_P) { + /* pre decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } else { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } +} + +/* UniCore-F64 mrc/mcr */ +static void do_ucf64_trans(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp; + + if ((insn & 0xfe0003ff) == 0xe2000000) { + /* control register */ + if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) { + ILLEGAL; + } + if (UCOP_SET(24)) { + /* CFF */ + tmp = new_tmp(); + gen_helper_ucf64_get_fpscr(tmp, cpu_env); + store_reg(s, UCOP_REG_D, tmp); + } else { + /* CTF */ + tmp = load_reg(s, UCOP_REG_D); + gen_helper_ucf64_set_fpscr(cpu_env, tmp); + dead_tmp(tmp); + gen_lookup_tb(s); + } + return; + } + if ((insn & 0xfe0003ff) == 0xe0000000) { + /* general register */ + if (UCOP_REG_D == 31) { + ILLEGAL; + } + if (UCOP_SET(24)) { /* MFF */ + tmp = ucf64_gen_ld32(UCOP_REG_N); + store_reg(s, UCOP_REG_D, tmp); + } else { /* MTF */ + tmp = load_reg(s, UCOP_REG_D); + ucf64_gen_st32(tmp, UCOP_REG_N); + } + return; + } + if ((insn & 0xfb000000) == 0xe9000000) { + /* MFFC */ + if (UCOP_REG_D != 31) { + ILLEGAL; + } + if (UCOP_UCF64_COND & 0x8) { + ILLEGAL; + } + + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, UCOP_UCF64_COND); + if (UCOP_SET(26)) { + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env); + } else { + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env); + } + dead_tmp(tmp); + return; + } + ILLEGAL; +} + +/* UniCore-F64 convert instructions */ +static void do_ucf64_fcvt(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (UCOP_UCF64_FMT == 3) { + ILLEGAL; + } + if (UCOP_REG_N != 0) { + ILLEGAL; + } + switch (UCOP_UCF64_FUNC) { + case 0: /* cvt.s */ + switch (UCOP_UCF64_FMT) { + case 1 /* d */: + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + case 2 /* w */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + default /* s */: + ILLEGAL; + break; + } + break; + case 1: /* cvt.d */ + switch (UCOP_UCF64_FMT) { + case 0 /* s */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env); + tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + case 2 /* w */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env); + tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + default /* d */: + ILLEGAL; + break; + } + break; + case 4: /* cvt.w */ + switch (UCOP_UCF64_FMT) { + case 0 /* s */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + case 1 /* d */: + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + default /* w */: + ILLEGAL; + break; + } + break; + default: + ILLEGAL; + } +} + +/* UniCore-F64 compare instructions */ +static void do_ucf64_fcmp(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (UCOP_SET(25)) { + ILLEGAL; + } + if (UCOP_REG_D != 0) { + ILLEGAL; + } + + ILLEGAL; /* TODO */ + if (UCOP_SET(24)) { + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */ + } else { + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */ + } +} + +#define gen_helper_ucf64_movs(x, y) do { } while (0) +#define gen_helper_ucf64_movd(x, y) do { } while (0) + +#define UCF64_OP1(name) do { \ + if (UCOP_REG_N != 0) { \ + ILLEGAL; \ + } \ + switch (UCOP_UCF64_FMT) { \ + case 0 /* s */: \ + tcg_gen_ld_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \ + tcg_gen_st_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 1 /* d */: \ + tcg_gen_ld_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \ + tcg_gen_st_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 2 /* w */: \ + ILLEGAL; \ + break; \ + } \ + } while (0) + +#define UCF64_OP2(name) do { \ + switch (UCOP_UCF64_FMT) { \ + case 0 /* s */: \ + tcg_gen_ld_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_N)); \ + tcg_gen_ld_i32(cpu_F1s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##s(cpu_F0s, \ + cpu_F0s, cpu_F1s, cpu_env); \ + tcg_gen_st_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 1 /* d */: \ + tcg_gen_ld_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_N)); \ + tcg_gen_ld_i64(cpu_F1d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##d(cpu_F0d, \ + cpu_F0d, cpu_F1d, cpu_env); \ + tcg_gen_st_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 2 /* w */: \ + ILLEGAL; \ + break; \ + } \ + } while (0) + +/* UniCore-F64 data processing */ +static void do_ucf64_datap(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (UCOP_UCF64_FMT == 3) { + ILLEGAL; + } + switch (UCOP_UCF64_FUNC) { + case 0: /* add */ + UCF64_OP2(add); + break; + case 1: /* sub */ + UCF64_OP2(sub); + break; + case 2: /* mul */ + UCF64_OP2(mul); + break; + case 4: /* div */ + UCF64_OP2(div); + break; + case 5: /* abs */ + UCF64_OP1(abs); + break; + case 6: /* mov */ + UCF64_OP1(mov); + break; + case 7: /* neg */ + UCF64_OP1(neg); + break; + default: + ILLEGAL; + } +} + +/* Disassemble an F64 instruction */ +static void disas_ucf64_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (!UCOP_SET(29)) { + if (UCOP_SET(26)) { + do_ucf64_ldst_m(env, s, insn); + } else { + do_ucf64_ldst_i(env, s, insn); + } + } else { + if (UCOP_SET(5)) { + switch ((insn >> 26) & 0x3) { + case 0: + do_ucf64_datap(env, s, insn); + break; + case 1: + ILLEGAL; + break; + case 2: + do_ucf64_fcvt(env, s, insn); + break; + case 3: + do_ucf64_fcmp(env, s, insn); + break; + } + } else { + do_ucf64_trans(env, s, insn); + } + } +} + +static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) +{ + TranslationBlock *tb; + + tb = s->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + tcg_gen_goto_tb(n); + gen_set_pc_im(dest); + tcg_gen_exit_tb((long)tb + n); + } else { + gen_set_pc_im(dest); + tcg_gen_exit_tb(0); + } +} + +static inline void gen_jmp(DisasContext *s, uint32_t dest) +{ + if (unlikely(s->singlestep_enabled)) { + /* An indirect jump so that we still trigger the debug exception. */ + gen_bx_im(s, dest); + } else { + gen_goto_tb(s, 0, dest); + s->is_jmp = DISAS_TB_JUMP; + } +} + +static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y) +{ + if (x) { + tcg_gen_sari_i32(t0, t0, 16); + } else { + gen_sxth(t0); + } + if (y) { + tcg_gen_sari_i32(t1, t1, 16); + } else { + gen_sxth(t1); + } + tcg_gen_mul_i32(t0, t0, t1); +} + +/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */ +static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0) +{ + TCGv tmp; + if (bsr) { + /* ??? This is also undefined in system mode. */ + if (IS_USER(s)) { + return 1; + } + + tmp = load_cpu_field(bsr); + tcg_gen_andi_i32(tmp, tmp, ~mask); + tcg_gen_andi_i32(t0, t0, mask); + tcg_gen_or_i32(tmp, tmp, t0); + store_cpu_field(tmp, bsr); + } else { + gen_set_asr(t0, mask); + } + dead_tmp(t0); + gen_lookup_tb(s); + return 0; +} + +/* Generate an old-style exception return. Marks pc as dead. */ +static void gen_exception_return(DisasContext *s, TCGv pc) +{ + TCGv tmp; + store_reg(s, 31, pc); + tmp = load_cpu_field(bsr); + gen_set_asr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; +} + +static void disas_coproc_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + switch (UCOP_CPNUM) { + case 2: + disas_ucf64_insn(env, s, insn); + break; + default: + /* Unknown coprocessor. */ + cpu_abort(env, "Unknown coprocessor!"); + } +} + + +/* Store a 64-bit value to a register pair. Clobbers val. */ +static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val) +{ + TCGv tmp; + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rlow, tmp); + tmp = new_tmp(); + tcg_gen_shri_i64(val, val, 32); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rhigh, tmp); +} + +/* load and add a 64-bit value from a register pair. */ +static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh) +{ + TCGv_i64 tmp; + TCGv tmpl; + TCGv tmph; + + /* Load 64-bit value rd:rn. */ + tmpl = load_reg(s, rlow); + tmph = load_reg(s, rhigh); + tmp = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(tmp, tmpl, tmph); + dead_tmp(tmpl); + dead_tmp(tmph); + tcg_gen_add_i64(val, val, tmp); + tcg_temp_free_i64(tmp); +} + +/* data processing instructions */ +static void do_datap(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp; + TCGv tmp2; + int logic_cc; + + if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) { + if (UCOP_SET(23)) { /* CMOV instructions */ + if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) { + ILLEGAL; + } + /* if not always execute, we generate a conditional jump to + next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel); + s->condjmp = 1; + } + } + + logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24); + + if (UCOP_SET(29)) { + unsigned int val; + /* immediate operand */ + val = UCOP_IMM_9; + if (UCOP_SH_IM) { + val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); + } + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, val); + if (logic_cc && UCOP_SH_IM) { + gen_set_CF_bit31(tmp2); + } + } else { + /* register */ + tmp2 = load_reg(s, UCOP_REG_M); + if (UCOP_SET(5)) { + tmp = load_reg(s, UCOP_REG_S); + gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc); + } else { + gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc); + } + } + + if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { + tmp = load_reg(s, UCOP_REG_N); + } else { + TCGV_UNUSED(tmp); + } + + switch (UCOP_OPCODES) { + case 0x00: + tcg_gen_and_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x01: + tcg_gen_xor_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x02: + if (UCOP_SET_S && UCOP_REG_D == 31) { + /* SUBS r31, ... is used for exception return. */ + if (IS_USER(s)) { + ILLEGAL; + } + gen_helper_sub_cc(tmp, tmp, tmp2); + gen_exception_return(s, tmp); + } else { + if (UCOP_SET_S) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + } + break; + case 0x03: + if (UCOP_SET_S) { + gen_helper_sub_cc(tmp, tmp2, tmp); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x04: + if (UCOP_SET_S) { + gen_helper_add_cc(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x05: + if (UCOP_SET_S) { + gen_helper_adc_cc(tmp, tmp, tmp2); + } else { + gen_add_carry(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x06: + if (UCOP_SET_S) { + gen_helper_sbc_cc(tmp, tmp, tmp2); + } else { + gen_sub_carry(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x07: + if (UCOP_SET_S) { + gen_helper_sbc_cc(tmp, tmp2, tmp); + } else { + gen_sub_carry(tmp, tmp2, tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x08: + if (UCOP_SET_S) { + tcg_gen_and_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x09: + if (UCOP_SET_S) { + tcg_gen_xor_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x0a: + if (UCOP_SET_S) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0b: + if (UCOP_SET_S) { + gen_helper_add_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0c: + tcg_gen_or_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x0d: + if (logic_cc && UCOP_REG_D == 31) { + /* MOVS r31, ... is used for exception return. */ + if (IS_USER(s)) { + ILLEGAL; + } + gen_exception_return(s, tmp2); + } else { + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp2); + } + break; + case 0x0e: + tcg_gen_andc_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + default: + case 0x0f: + tcg_gen_not_i32(tmp2, tmp2); + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp2); + break; + } + if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { + dead_tmp(tmp2); + } +} + +/* multiply */ +static void do_mult(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp; + TCGv tmp2; + TCGv_i64 tmp64; + + if (UCOP_SET(27)) { + /* 64 bit mul */ + tmp = load_reg(s, UCOP_REG_M); + tmp2 = load_reg(s, UCOP_REG_N); + if (UCOP_SET(26)) { + tmp64 = gen_muls_i64_i32(tmp, tmp2); + } else { + tmp64 = gen_mulu_i64_i32(tmp, tmp2); + } + if (UCOP_SET(25)) { /* mult accumulate */ + gen_addq(s, tmp64, UCOP_REG_LO, UCOP_REG_HI); + } + gen_storeq_reg(s, UCOP_REG_LO, UCOP_REG_HI, tmp64); + tcg_temp_free_i64(tmp64); + } else { + /* 32 bit mul */ + tmp = load_reg(s, UCOP_REG_M); + tmp2 = load_reg(s, UCOP_REG_N); + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (UCOP_SET(25)) { + /* Add */ + tmp2 = load_reg(s, UCOP_REG_S); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + if (UCOP_SET_S) { + gen_logic_CC(tmp); + } + store_reg(s, UCOP_REG_D, tmp); + } +} + +/* miscellaneous instructions */ +static void do_misc(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int val; + TCGv tmp; + + if ((insn & 0xffffffe0) == 0x10ffc120) { + /* Trivial implementation equivalent to bx. */ + tmp = load_reg(s, UCOP_REG_M); + gen_bx(s, tmp); + return; + } + + if ((insn & 0xfbffc000) == 0x30ffc000) { + /* PSR = immediate */ + val = UCOP_IMM_9; + if (UCOP_SH_IM) { + val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); + } + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { + ILLEGAL; + } + return; + } + + if ((insn & 0xfbffffe0) == 0x12ffc020) { + /* PSR.flag = reg */ + tmp = load_reg(s, UCOP_REG_M); + if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) { + ILLEGAL; + } + return; + } + + if ((insn & 0xfbffffe0) == 0x10ffc020) { + /* PSR = reg */ + tmp = load_reg(s, UCOP_REG_M); + if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { + ILLEGAL; + } + return; + } + + if ((insn & 0xfbf83fff) == 0x10f80000) { + /* reg = PSR */ + if (UCOP_SET_B) { + if (IS_USER(s)) { + ILLEGAL; + } + tmp = load_cpu_field(bsr); + } else { + tmp = new_tmp(); + gen_helper_asr_read(tmp); + } + store_reg(s, UCOP_REG_D, tmp); + return; + } + + if ((insn & 0xfbf83fe0) == 0x12f80120) { + /* clz */ + tmp = load_reg(s, UCOP_REG_M); + if (UCOP_SET(26)) { + gen_helper_clo(tmp, tmp); + } else { + gen_helper_clz(tmp, tmp); + } + store_reg(s, UCOP_REG_D, tmp); + return; + } + + /* otherwise */ + ILLEGAL; +} + +/* load/store I_offset and R_offset */ +static void do_ldst_ir(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int i; + TCGv tmp; + TCGv tmp2; + + tmp2 = load_reg(s, UCOP_REG_N); + i = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W)); + + /* immediate */ + if (UCOP_SET_P) { + gen_add_data_offset(s, insn, tmp2); + } + + if (UCOP_SET_L) { + /* load */ + if (UCOP_SET_B) { + tmp = gen_ld8u(tmp2, i); + } else { + tmp = gen_ld32(tmp2, i); + } + } else { + /* store */ + tmp = load_reg(s, UCOP_REG_D); + if (UCOP_SET_B) { + gen_st8(tmp, tmp2, i); + } else { + gen_st32(tmp, tmp2, i); + } + } + if (!UCOP_SET_P) { + gen_add_data_offset(s, insn, tmp2); + store_reg(s, UCOP_REG_N, tmp2); + } else if (UCOP_SET_W) { + store_reg(s, UCOP_REG_N, tmp2); + } else { + dead_tmp(tmp2); + } + if (UCOP_SET_L) { + /* Complete the load. */ + if (UCOP_REG_D == 31) { + gen_bx(s, tmp); + } else { + store_reg(s, UCOP_REG_D, tmp); + } + } +} + +/* SWP instruction */ +static void do_swap(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv addr; + TCGv tmp; + TCGv tmp2; + + if ((insn & 0xff003fe0) != 0x40000120) { + ILLEGAL; + } + + /* ??? This is not really atomic. However we know + we never have multiple CPUs running in parallel, + so it is good enough. */ + addr = load_reg(s, UCOP_REG_N); + tmp = load_reg(s, UCOP_REG_M); + if (UCOP_SET_B) { + tmp2 = gen_ld8u(addr, IS_USER(s)); + gen_st8(tmp, addr, IS_USER(s)); + } else { + tmp2 = gen_ld32(addr, IS_USER(s)); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + store_reg(s, UCOP_REG_D, tmp2); +} + +/* load/store hw/sb */ +static void do_ldst_hwsb(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv addr; + TCGv tmp; + + if (UCOP_SH_OP == 0) { + do_swap(env, s, insn); + return; + } + + addr = load_reg(s, UCOP_REG_N); + if (UCOP_SET_P) { + gen_add_datah_offset(s, insn, addr); + } + + if (UCOP_SET_L) { /* load */ + switch (UCOP_SH_OP) { + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + tmp = gen_ld8s(addr, IS_USER(s)); + break; + default: /* see do_swap */ + case 3: + tmp = gen_ld16s(addr, IS_USER(s)); + break; + } + } else { /* store */ + if (UCOP_SH_OP != 1) { + ILLEGAL; + } + tmp = load_reg(s, UCOP_REG_D); + gen_st16(tmp, addr, IS_USER(s)); + } + /* Perform base writeback before the loaded value to + ensure correct behavior with overlapping index registers. */ + if (!UCOP_SET_P) { + gen_add_datah_offset(s, insn, addr); + store_reg(s, UCOP_REG_N, addr); + } else if (UCOP_SET_W) { + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } + if (UCOP_SET_L) { + /* Complete the load. */ + store_reg(s, UCOP_REG_D, tmp); + } +} + +/* load/store multiple words */ +static void do_ldst_m(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int val, i; + int j, n, reg, user, loaded_base; + TCGv tmp; + TCGv tmp2; + TCGv addr; + TCGv loaded_var; + + if (UCOP_SET(7)) { + ILLEGAL; + } + /* XXX: store correct base if write back */ + user = 0; + if (UCOP_SET_B) { /* S bit in instruction table */ + if (IS_USER(s)) { + ILLEGAL; /* only usable in supervisor mode */ + } + if (UCOP_SET(18) == 0) { /* pc reg */ + user = 1; + } + } + + addr = load_reg(s, UCOP_REG_N); + + /* compute total size */ + loaded_base = 0; + TCGV_UNUSED(loaded_var); + n = 0; + for (i = 0; i < 6; i++) { + if (UCOP_SET(i)) { + n++; + } + } + for (i = 9; i < 19; i++) { + if (UCOP_SET(i)) { + n++; + } + } + /* XXX: test invalid n == 0 case ? */ + if (UCOP_SET_U) { + if (UCOP_SET_P) { + /* pre increment */ + tcg_gen_addi_i32(addr, addr, 4); + } else { + /* post increment */ + } + } else { + if (UCOP_SET_P) { + /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } else { + /* post decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } + } + + j = 0; + reg = UCOP_SET(6) ? 16 : 0; + for (i = 0; i < 19; i++, reg++) { + if (i == 6) { + i = i + 3; + } + if (UCOP_SET(i)) { + if (UCOP_SET_L) { /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + if (reg == 31) { + gen_bx(s, tmp); + } else if (user) { + tmp2 = tcg_const_i32(reg); + gen_helper_set_user_reg(tmp2, tmp); + tcg_temp_free_i32(tmp2); + dead_tmp(tmp); + } else if (reg == UCOP_REG_N) { + loaded_var = tmp; + loaded_base = 1; + } else { + store_reg(s, reg, tmp); + } + } else { /* store */ + if (reg == 31) { + /* special case: r31 = PC + 4 */ + val = (long)s->pc; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + } else if (user) { + tmp = new_tmp(); + tmp2 = tcg_const_i32(reg); + gen_helper_get_user_reg(tmp, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, reg); + } + gen_st32(tmp, addr, IS_USER(s)); + } + j++; + /* no need to add after the last transfer */ + if (j != n) { + tcg_gen_addi_i32(addr, addr, 4); + } + } + } + if (UCOP_SET_W) { /* write back */ + if (UCOP_SET_U) { + if (UCOP_SET_P) { + /* pre increment */ + } else { + /* post increment */ + tcg_gen_addi_i32(addr, addr, 4); + } + } else { + if (UCOP_SET_P) { + /* pre decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } else { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } + if (loaded_base) { + store_reg(s, UCOP_REG_N, loaded_var); + } + if (UCOP_SET_B && !user) { + /* Restore ASR from BSR. */ + tmp = load_cpu_field(bsr); + gen_set_asr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; + } +} + +/* branch (and link) */ +static void do_branch(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int val; + int32_t offset; + TCGv tmp; + + if (UCOP_COND == 0xf) { + ILLEGAL; + } + + if (UCOP_COND != 0xe) { + /* if not always execute, we generate a conditional jump to + next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(UCOP_COND ^ 1, s->condlabel); + s->condjmp = 1; + } + + val = (int32_t)s->pc; + if (UCOP_SET_L) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 30, tmp); + } + offset = (((int32_t)insn << 8) >> 8); + val += (offset << 2); /* unicore is pc+4 */ + gen_jmp(s, val); +} + +static void disas_uc32_insn(CPUState *env, DisasContext *s) +{ + unsigned int insn; + + insn = ldl_code(s->pc); + s->pc += 4; + + /* UniCore instructions class: + * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx + * AAA : see switch case + * BBBB : opcodes or cond or PUBW + * C : S OR L + * D : 8 + * E : 5 + */ + switch (insn >> 29) { + case 0b000: + if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) { + do_mult(env, s, insn); + break; + } + + if (UCOP_SET(8)) { + do_misc(env, s, insn); + break; + } + case 0b001: + if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) { + do_misc(env, s, insn); + break; + } + do_datap(env, s, insn); + break; + + case 0b010: + if (UCOP_SET(8) && UCOP_SET(5)) { + do_ldst_hwsb(env, s, insn); + break; + } + if (UCOP_SET(8) || UCOP_SET(5)) { + ILLEGAL; + } + case 0b011: + do_ldst_ir(env, s, insn); + break; + + case 0b100: + if (UCOP_SET(8)) { + ILLEGAL; /* extended instructions */ + } + do_ldst_m(env, s, insn); + break; + case 0b101: + do_branch(env, s, insn); + break; + case 0b110: + /* Coprocessor. */ + disas_coproc_insn(env, s, insn); + break; + case 0b111: + if (!UCOP_SET(28)) { + disas_coproc_insn(env, s, insn); + break; + } + if ((insn & 0xff000000) == 0xff000000) { /* syscall */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_SYSCALL; + break; + } + ILLEGAL; + } + + return; +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline void gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, int search_pc) +{ + DisasContext dc1, *dc = &dc1; + CPUBreakpoint *bp; + uint16_t *gen_opc_end; + int j, lj; + target_ulong pc_start; + uint32_t next_page_start; + int num_insns; + int max_insns; + + /* generate intermediate code */ + num_temps = 0; + + pc_start = tb->pc; + + dc->tb = tb; + + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + dc->singlestep_enabled = env->singlestep_enabled; + dc->condjmp = 0; + cpu_F0s = tcg_temp_new_i32(); + cpu_F1s = tcg_temp_new_i32(); + cpu_F0d = tcg_temp_new_i64(); + cpu_F1d = tcg_temp_new_i64(); + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) { + max_insns = CF_COUNT_MASK; + } + + gen_icount_start(); + do { + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc->pc) { + gen_set_pc_im(dc->pc); + gen_exception(EXCP_DEBUG); + dc->is_jmp = DISAS_JUMP; + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + dc->pc += 2; /* FIXME */ + goto done_generating; + break; + } + } + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) { + gen_opc_instr_start[lj++] = 0; + } + } + gen_opc_pc[lj] = dc->pc; + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + gen_io_start(); + } + + disas_uc32_insn(env, dc); + + if (num_temps) { + fprintf(stderr, "Internal resource leak before %08x\n", dc->pc); + num_temps = 0; + } + + if (dc->condjmp && !dc->is_jmp) { + gen_set_label(dc->condlabel); + dc->condjmp = 0; + } + /* Translation stops when a conditional branch is encountered. + * Otherwise the subsequent code could get translated several times. + * Also stop translation when a page boundary is reached. This + * ensures prefetch aborts occur at the right place. */ + num_insns++; + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + !env->singlestep_enabled && + !singlestep && + dc->pc < next_page_start && + num_insns < max_insns); + + if (tb->cflags & CF_LAST_IO) { + if (dc->condjmp) { + /* FIXME: This can theoretically happen with self-modifying + code. */ + cpu_abort(env, "IO on conditional branch instruction"); + } + gen_io_end(); + } + + /* At this stage dc->condjmp will only be set when the skipped + instruction was a conditional branch or trap, and the PC has + already been written. */ + if (unlikely(env->singlestep_enabled)) { + /* Make sure the pc is updated, and raise a debug exception. */ + if (dc->condjmp) { + if (dc->is_jmp == DISAS_SYSCALL) { + gen_exception(UC32_EXCP_PRIV); + } else { + gen_exception(EXCP_DEBUG); + } + gen_set_label(dc->condlabel); + } + if (dc->condjmp || !dc->is_jmp) { + gen_set_pc_im(dc->pc); + dc->condjmp = 0; + } + if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) { + gen_exception(UC32_EXCP_PRIV); + } else { + gen_exception(EXCP_DEBUG); + } + } else { + /* While branches must always occur at the end of an IT block, + there are a few other things that can cause us to terminate + the TB in the middel of an IT block: + - Exception generating instructions (bkpt, swi, undefined). + - Page boundaries. + - Hardware watchpoints. + Hardware breakpoints have already been handled and skip this code. + */ + switch (dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 1, dc->pc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used to find the next TB */ + tcg_gen_exit_tb(0); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + case DISAS_SYSCALL: + gen_exception(UC32_EXCP_PRIV); + break; + } + if (dc->condjmp) { + gen_set_label(dc->condlabel); + gen_goto_tb(dc, 1, dc->pc); + dc->condjmp = 0; + } + } + +done_generating: + gen_icount_end(tb, num_insns); + *gen_opc_ptr = INDEX_op_end; + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("----------------\n"); + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(pc_start, dc->pc - pc_start, 0); + qemu_log("\n"); + } +#endif + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) { + gen_opc_instr_start[lj++] = 0; + } + } else { + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + } +} + +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 1); +} + +static const char *cpu_mode_names[16] = { + "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP", + "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR" +}; + +#define UCF64_DUMP_STATE +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + int i; +#ifdef UCF64_DUMP_STATE + 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 < 32; i++) { + cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); + if ((i % 4) == 3) { + cpu_fprintf(f, "\n"); + } else { + cpu_fprintf(f, " "); + } + } + psr = cpu_asr_read(env); + cpu_fprintf(f, "PSR=%08x %c%c%c%c %s\n", + psr, + psr & (1 << 31) ? 'N' : '-', + psr & (1 << 30) ? 'Z' : '-', + psr & (1 << 29) ? 'C' : '-', + psr & (1 << 28) ? 'V' : '-', + cpu_mode_names[psr & 0xf]); + +#ifdef UCF64_DUMP_STATE + for (i = 0; i < 16; i++) { + d.d = env->ucf64.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=%" PRIx64 "(%8g)\n", + i * 2, (int)s0.i, s0.s, + i * 2 + 1, (int)s1.i, s1.s, + i, (uint64_t)d0.f64, d0.d); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]); +#endif +} + +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) +{ + env->regs[31] = gen_opc_pc[pc_pos]; +} diff --git a/tests/test-mmap.c b/tests/test-mmap.c index fcb365f..c578e25 100644 --- a/tests/test-mmap.c +++ b/tests/test-mmap.c @@ -164,6 +164,7 @@ void check_aligned_anonymous_unfixed_colliding_mmaps(void) nlen = pagesize * 8; p3 = mmap(NULL, nlen, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + fail_unless (p3 != MAP_FAILED); /* Check if the mmaped areas collide. */ if (p3 < p2 @@ -174,7 +175,6 @@ void check_aligned_anonymous_unfixed_colliding_mmaps(void) /* Make sure we get pages aligned with the pagesize. The target expects this. */ - fail_unless (p3 != MAP_FAILED); p = (uintptr_t) p3; fail_unless ((p & pagemask) == 0); munmap (p2, pagesize); diff --git a/translate-all.c b/translate-all.c index efcfb9a..2ca190c 100644 --- a/translate-all.c +++ b/translate-all.c @@ -112,8 +112,7 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) /* The cpu state corresponding to 'searched_pc' is restored. */ int cpu_restore_state(TranslationBlock *tb, - CPUState *env, unsigned long searched_pc, - void *puc) + CPUState *env, unsigned long searched_pc) { TCGContext *s = &tcg_ctx; int j; @@ -157,7 +156,7 @@ int cpu_restore_state(TranslationBlock *tb, j--; env->icount_decr.u16.low -= gen_opc_icount[j]; - gen_pc_load(env, tb, searched_pc, j, puc); + restore_state_to_opc(env, tb, j); #ifdef CONFIG_PROFILER s->restore_time += profile_getclock() - ti; diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 2522936..87fdf35 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -868,8 +868,8 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, zstream->avail_in = vs->tight.tight.offset; zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset; zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset; + previous_out = zstream->avail_out; zstream->data_type = Z_BINARY; - previous_out = zstream->total_out; /* start encoding */ if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { @@ -878,7 +878,8 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, } vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out; - bytes = zstream->total_out - previous_out; + /* ...how much data has actually been produced by deflate() */ + bytes = previous_out - zstream->avail_out; tight_send_compact_size(vs, bytes); vnc_write(vs, vs->tight.zlib.buffer, bytes); diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c index 3c6e6ab..e32e4cd 100644 --- a/ui/vnc-enc-zlib.c +++ b/ui/vnc-enc-zlib.c @@ -103,8 +103,8 @@ static int vnc_zlib_stop(VncState *vs) zstream->avail_in = vs->zlib.zlib.offset; zstream->next_out = vs->output.buffer + vs->output.offset; zstream->avail_out = vs->output.capacity - vs->output.offset; + previous_out = zstream->avail_out; zstream->data_type = Z_BINARY; - previous_out = zstream->total_out; // start encoding if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { @@ -113,7 +113,7 @@ static int vnc_zlib_stop(VncState *vs) } vs->output.offset = vs->output.capacity - zstream->avail_out; - return zstream->total_out - previous_out; + return previous_out - zstream->avail_out; } int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) diff --git a/usb-linux.c b/usb-linux.c index 255009f..1f33c2c 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -107,7 +107,7 @@ enum { /* * Control transfer state. * Note that 'buffer' _must_ follow 'req' field because - * we need contigious buffer when we submit control URB. + * we need contiguous buffer when we submit control URB. */ struct ctrl_struct { uint16_t len; @@ -344,6 +344,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) for (interface = 0; interface < nb_interfaces; interface++) { ctrl.ioctl_code = USBDEVFS_DISCONNECT; ctrl.ifno = interface; + ctrl.data = 0; ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl); if (ret < 0 && errno != ENODATA) { perror("USBDEVFS_DISCONNECT"); @@ -579,7 +580,7 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p) /* * Setup ctrl transfer. * - * s->ctrl is layed out such that data buffer immediately follows + * s->ctrl is laid out such that data buffer immediately follows * 'req' struct which is exactly what usbdevfs expects. */ urb = &aurb->urb; |