summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--.mailmap2
-rw-r--r--.shippable.yml12
-rw-r--r--.travis.yml5
-rw-r--r--exec.c8
-rw-r--r--hw/virtio/trace-events3
-rw-r--r--hw/virtio/vhost.c57
-rw-r--r--include/qemu/qemu-plugin.h1
-rw-r--r--linux-user/elfload.c71
-rw-r--r--linux-user/mmap.c2
-rwxr-xr-xscripts/clean-includes1
-rw-r--r--scripts/coverity-scan/coverity-scan.docker2
-rwxr-xr-xscripts/decodetree.py511
-rw-r--r--target/arm/t32.decode4
-rw-r--r--target/mips/Makefile.objs2
-rw-r--r--target/mips/cpu.h32
-rw-r--r--target/mips/fpu_helper.c658
-rw-r--r--target/mips/internal.h3
-rw-r--r--target/mips/lmmi_helper.c (renamed from target/mips/lmi_helper.c)0
-rw-r--r--target/mips/mips-defs.h45
-rw-r--r--target/mips/msa_helper.c77
-rw-r--r--target/mips/translate.c2
-rw-r--r--target/mips/translate_init.inc.c95
-rw-r--r--tests/decode/err_pattern_group_nest1.decode11
-rw-r--r--tests/decode/err_pattern_group_nest2.decode6
-rw-r--r--tests/decode/err_pattern_group_nest3.decode14
-rw-r--r--tests/decode/succ_pattern_group_nest2.decode13
-rw-r--r--tests/decode/succ_pattern_group_nest3.decode11
-rw-r--r--tests/decode/succ_pattern_group_nest4.decode13
-rw-r--r--tests/docker/Makefile.include2
-rw-r--r--tests/docker/dockerfiles/centos7.docker2
-rw-r--r--tests/docker/dockerfiles/centos8.docker2
-rw-r--r--tests/docker/dockerfiles/debian-xtensa-cross.docker2
-rw-r--r--tests/docker/dockerfiles/debian10.docker2
-rw-r--r--tests/docker/dockerfiles/debian9.docker2
-rw-r--r--tests/docker/dockerfiles/fedora.docker2
-rw-r--r--tests/docker/dockerfiles/ubuntu.docker4
-rw-r--r--tests/docker/dockerfiles/ubuntu1804.docker2
-rw-r--r--tests/plugin/mem.c2
-rw-r--r--tests/tcg/arm/Makefile.target2
-rw-r--r--tests/tcg/arm/commpage.c61
-rwxr-xr-xtests/vm/fedora1
-rwxr-xr-xtests/vm/freebsd1
-rwxr-xr-xtests/vm/netbsd1
-rwxr-xr-xtests/vm/openbsd1
-rwxr-xr-xtests/vm/ubuntu.i3862
46 files changed, 1212 insertions, 542 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index de0727cb09..ce7850a320 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -7,7 +7,7 @@ freebsd_12_task:
cpu: 8
memory: 8G
install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; pkg install -y
- bash bison curl cyrus-sasl git glib gmake gnutls gsed
+ bash curl cyrus-sasl git glib gmake gnutls gsed
nettle perl5 pixman pkgconf png usbredir
script:
- mkdir build
diff --git a/.mailmap b/.mailmap
index e3628c7a66..84f36592ba 100644
--- a/.mailmap
+++ b/.mailmap
@@ -45,12 +45,14 @@ Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <amarkovic@wavecomp.com>
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <arikalo@wavecomp.com>
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
+Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com>
Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com>
Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org>
Philippe Mathieu-Daudé <philmd@redhat.com> <f4bug@amsat.org>
+Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
# Also list preferred name forms where people have changed their
diff --git a/.shippable.yml b/.shippable.yml
index 2cce7b5689..10cf219bff 100644
--- a/.shippable.yml
+++ b/.shippable.yml
@@ -5,8 +5,8 @@ env:
global:
- LC_ALL=C
matrix:
- - IMAGE=debian-amd64
- TARGET_LIST=x86_64-softmmu,x86_64-linux-user
+ # - IMAGE=debian-amd64
+ # TARGET_LIST=x86_64-softmmu,x86_64-linux-user
- IMAGE=debian-win32-cross
TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu
- IMAGE=debian-win64-cross
@@ -19,10 +19,10 @@ env:
TARGET_LIST=aarch64-softmmu,aarch64-linux-user
- IMAGE=debian-s390x-cross
TARGET_LIST=s390x-softmmu,s390x-linux-user
- - IMAGE=debian-mips-cross
- TARGET_LIST=mips-softmmu,mipsel-linux-user
- - IMAGE=debian-mips64el-cross
- TARGET_LIST=mips64el-softmmu,mips64el-linux-user
+ # - IMAGE=debian-mips-cross
+ # TARGET_LIST=mips-softmmu,mipsel-linux-user
+ # - IMAGE=debian-mips64el-cross
+ # TARGET_LIST=mips64el-softmmu,mips64el-linux-user
- IMAGE=debian-ppc64el-cross
TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user
build:
diff --git a/.travis.yml b/.travis.yml
index 564be50a3c..ec6367af1f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -429,6 +429,7 @@ jobs:
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS}"
+ - UNRELIABLE=true
- name: "[ppc64] GCC check-tcg"
arch: ppc64le
@@ -493,6 +494,7 @@ jobs:
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
+ - UNRELIABLE=true
script:
- ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF )
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
@@ -535,6 +537,7 @@ jobs:
- TEST_CMD="make check-unit"
- CONFIG="--disable-containers --disable-tcg --enable-kvm
--disable-tools --host-cc=clang --cxx=clang++"
+ - UNRELIABLE=true
# Release builds
# The make-release script expect a QEMU version, so our tag must start with a 'v'.
@@ -556,3 +559,5 @@ jobs:
- mkdir -p release-build && cd release-build
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
- make install
+ allow_failures:
+ - env: UNRELIABLE=true
diff --git a/exec.c b/exec.c
index be4be2df3a..a0bf9d61c8 100644
--- a/exec.c
+++ b/exec.c
@@ -1038,6 +1038,7 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
int flags, CPUWatchpoint **watchpoint)
{
CPUWatchpoint *wp;
+ vaddr in_page;
/* forbid ranges which are empty or run off the end of the address space */
if (len == 0 || (addr + len - 1) < addr) {
@@ -1058,7 +1059,12 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
QTAILQ_INSERT_TAIL(&cpu->watchpoints, wp, entry);
}
- tlb_flush_page(cpu, addr);
+ in_page = -(addr | TARGET_PAGE_MASK);
+ if (len <= in_page) {
+ tlb_flush_page(cpu, addr);
+ } else {
+ tlb_flush(cpu);
+ }
if (watchpoint)
*watchpoint = wp;
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index e83500bee9..6427a0047d 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -5,7 +5,8 @@ vhost_commit(bool started, bool changed) "Started: %d Changed: %d"
vhost_region_add_section(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
vhost_region_add_section_merge(const char *name, uint64_t new_size, uint64_t gpa, uint64_t owr) "%s: size: 0x%"PRIx64 " gpa: 0x%"PRIx64 " owr: 0x%"PRIx64
vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
-vhost_section(const char *name, int r) "%s:%d"
+vhost_section(const char *name) "%s"
+vhost_reject_section(const char *name, int d) "%s:%d"
vhost_iotlb_miss(void *dev, int step) "%p step %d"
# vhost-user.c
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index aff98a0ede..e3e2181290 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -27,6 +27,7 @@
#include "migration/blocker.h"
#include "migration/qemu-file-types.h"
#include "sysemu/dma.h"
+#include "sysemu/tcg.h"
#include "trace.h"
/* enabled until disconnected backend stabilizes */
@@ -403,26 +404,50 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
return r;
}
+/*
+ * vhost_section: identify sections needed for vhost access
+ *
+ * We only care about RAM sections here (where virtqueue and guest
+ * internals accessed by virtio might live). If we find one we still
+ * allow the backend to potentially filter it out of our list.
+ */
static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section)
{
- bool result;
- bool log_dirty = memory_region_get_dirty_log_mask(section->mr) &
- ~(1 << DIRTY_MEMORY_MIGRATION);
- result = memory_region_is_ram(section->mr) &&
- !memory_region_is_rom(section->mr);
-
- /* Vhost doesn't handle any block which is doing dirty-tracking other
- * than migration; this typically fires on VGA areas.
- */
- result &= !log_dirty;
+ MemoryRegion *mr = section->mr;
+
+ if (memory_region_is_ram(mr) && !memory_region_is_rom(mr)) {
+ uint8_t dirty_mask = memory_region_get_dirty_log_mask(mr);
+ uint8_t handled_dirty;
+
+ /*
+ * Kernel based vhost doesn't handle any block which is doing
+ * dirty-tracking other than migration for which it has
+ * specific logging support. However for TCG the kernel never
+ * gets involved anyway so we can also ignore it's
+ * self-modiying code detection flags. However a vhost-user
+ * client could still confuse a TCG guest if it re-writes
+ * executable memory that has already been translated.
+ */
+ handled_dirty = (1 << DIRTY_MEMORY_MIGRATION) |
+ (1 << DIRTY_MEMORY_CODE);
- if (result && dev->vhost_ops->vhost_backend_mem_section_filter) {
- result &=
- dev->vhost_ops->vhost_backend_mem_section_filter(dev, section);
- }
+ if (dirty_mask & ~handled_dirty) {
+ trace_vhost_reject_section(mr->name, 1);
+ return false;
+ }
+
+ if (dev->vhost_ops->vhost_backend_mem_section_filter &&
+ !dev->vhost_ops->vhost_backend_mem_section_filter(dev, section)) {
+ trace_vhost_reject_section(mr->name, 2);
+ return false;
+ }
- trace_vhost_section(section->mr->name, result);
- return result;
+ trace_vhost_section(mr->name);
+ return true;
+ } else {
+ trace_vhost_reject_section(mr->name, 3);
+ return false;
+ }
}
static void vhost_begin(MemoryListener *listener)
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 89ed579f55..bab8b0d4b3 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -12,6 +12,7 @@
#include <inttypes.h>
#include <stdbool.h>
+#include <stddef.h>
/*
* For best performance, build the plugin with -fvisibility=hidden so that
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ebc663ea0b..b5cb21384a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -389,7 +389,7 @@ static bool init_guest_commpage(void)
{
void *want = g2h(ARM_COMMPAGE & -qemu_host_page_size);
void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
if (addr == MAP_FAILED) {
perror("Allocating guest commpage");
@@ -2101,9 +2101,54 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
}
}
+/**
+ * pgd_find_hole_fallback: potential mmap address
+ * @guest_size: size of available space
+ * @brk: location of break
+ * @align: memory alignment
+ *
+ * This is a fallback method for finding a hole in the host address
+ * space if we don't have the benefit of being able to access
+ * /proc/self/map. It can potentially take a very long time as we can
+ * only dumbly iterate up the host address space seeing if the
+ * allocation would work.
+ */
+static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk,
+ long align, uintptr_t offset)
+{
+ uintptr_t base;
+
+ /* Start (aligned) at the bottom and work our way up */
+ base = ROUND_UP(mmap_min_addr, align);
+
+ while (true) {
+ uintptr_t align_start, end;
+ align_start = ROUND_UP(base, align);
+ end = align_start + guest_size + offset;
+
+ /* if brk is anywhere in the range give ourselves some room to grow. */
+ if (align_start <= brk && brk < end) {
+ base = brk + (16 * MiB);
+ continue;
+ } else if (align_start + guest_size < align_start) {
+ /* we have run out of space */
+ return -1;
+ } else {
+ int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE | MAP_FIXED;
+ void * mmap_start = mmap((void *) align_start, guest_size,
+ PROT_NONE, flags, -1, 0);
+ if (mmap_start != MAP_FAILED) {
+ munmap((void *) align_start, guest_size);
+ return (uintptr_t) mmap_start + offset;
+ }
+ base += qemu_host_page_size;
+ }
+ }
+}
+
/* Return value for guest_base, or -1 if no hole found. */
static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size,
- long align)
+ long align, uintptr_t offset)
{
GSList *maps, *iter;
uintptr_t this_start, this_end, next_start, brk;
@@ -2116,6 +2161,10 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size,
/* Read brk after we've read the maps, which will malloc. */
brk = (uintptr_t)sbrk(0);
+ if (!maps) {
+ return pgd_find_hole_fallback(guest_size, brk, align, offset);
+ }
+
/* The first hole is before the first map entry. */
this_start = mmap_min_addr;
@@ -2125,7 +2174,7 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size,
this_end = ((MapInfo *)iter->data)->start;
next_start = ((MapInfo *)iter->data)->end;
- align_start = ROUND_UP(this_start, align);
+ align_start = ROUND_UP(this_start + offset, align);
/* Skip holes that are too small. */
if (align_start >= this_end) {
@@ -2175,6 +2224,7 @@ static void pgb_static(const char *image_name, abi_ulong orig_loaddr,
{
uintptr_t loaddr = orig_loaddr;
uintptr_t hiaddr = orig_hiaddr;
+ uintptr_t offset = 0;
uintptr_t addr;
if (hiaddr != orig_hiaddr) {
@@ -2188,18 +2238,19 @@ static void pgb_static(const char *image_name, abi_ulong orig_loaddr,
if (ARM_COMMPAGE) {
/*
* Extend the allocation to include the commpage.
- * For a 64-bit host, this is just 4GiB; for a 32-bit host,
- * the address arithmetic will wrap around, but the difference
- * will produce the correct allocation size.
+ * For a 64-bit host, this is just 4GiB; for a 32-bit host we
+ * need to ensure there is space bellow the guest_base so we
+ * can map the commpage in the place needed when the address
+ * arithmetic wraps around.
*/
if (sizeof(uintptr_t) == 8 || loaddr >= 0x80000000u) {
- hiaddr = (uintptr_t)4 << 30;
+ hiaddr = (uintptr_t) 4 << 30;
} else {
- loaddr = ARM_COMMPAGE & -align;
+ offset = -(ARM_COMMPAGE & -align);
}
}
- addr = pgb_find_hole(loaddr, hiaddr - loaddr, align);
+ addr = pgb_find_hole(loaddr, hiaddr - loaddr, align, offset);
if (addr == -1) {
/*
* If ARM_COMMPAGE, there *might* be a non-consecutive allocation
@@ -2234,7 +2285,7 @@ static void pgb_dynamic(const char *image_name, long align)
* just above that, and maximises the positive guest addresses.
*/
commpage = ARM_COMMPAGE & -align;
- addr = pgb_find_hole(commpage, -commpage, align);
+ addr = pgb_find_hole(commpage, -commpage, align, 0);
assert(addr != -1);
guest_base = addr;
}
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index caab62909e..0019447892 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -467,7 +467,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
* It can fail only on 64-bit host with 32-bit target.
* On any other target/host host mmap() handles this error correctly.
*/
- if (!guest_range_valid(start, len)) {
+ if (end < start || !guest_range_valid(start, len)) {
errno = ENOMEM;
goto fail;
}
diff --git a/scripts/clean-includes b/scripts/clean-includes
index dd938daa3e..795b3bea31 100755
--- a/scripts/clean-includes
+++ b/scripts/clean-includes
@@ -123,6 +123,7 @@ for f in "$@"; do
;;
*include/qemu/osdep.h | \
*include/qemu/compiler.h | \
+ *include/qemu/qemu-plugin.h | \
*include/glib-compat.h | \
*include/sysemu/os-posix.h | \
*include/sysemu/os-win32.h | \
diff --git a/scripts/coverity-scan/coverity-scan.docker b/scripts/coverity-scan/coverity-scan.docker
index a4f64d1283..ad4d64c0f8 100644
--- a/scripts/coverity-scan/coverity-scan.docker
+++ b/scripts/coverity-scan/coverity-scan.docker
@@ -19,7 +19,6 @@ FROM fedora:30
ENV PACKAGES \
alsa-lib-devel \
bc \
- bison \
brlapi-devel \
bzip2 \
bzip2-devel \
@@ -30,7 +29,6 @@ ENV PACKAGES \
dbus-daemon \
device-mapper-multipath-devel \
findutils \
- flex \
gcc \
gcc-c++ \
gettext \
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index f9d204aa36..530d41ca62 100755
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -31,7 +31,6 @@ variablewidth = False
fields = {}
arguments = {}
formats = {}
-patterns = []
allpatterns = []
anyextern = False
@@ -51,23 +50,27 @@ def error_with_file(file, lineno, *args):
global output_file
global output_fd
+ prefix = ''
+ if file:
+ prefix += '{0}:'.format(file)
if lineno:
- r = '{0}:{1}: error:'.format(file, lineno)
- elif input_file:
- r = '{0}: error:'.format(file)
- else:
- r = 'error:'
- for a in args:
- r += ' ' + str(a)
- r += '\n'
- sys.stderr.write(r)
+ prefix += '{0}:'.format(lineno)
+ if prefix:
+ prefix += ' '
+ print(prefix, end='error: ', file=sys.stderr)
+ print(*args, file=sys.stderr)
+
if output_file and output_fd:
output_fd.close()
os.remove(output_file)
exit(1)
+# end error_with_file
+
def error(lineno, *args):
- error_with_file(input_file, lineno, args)
+ error_with_file(input_file, lineno, *args)
+# end error
+
def output(*args):
global output_fd
@@ -120,6 +123,7 @@ def is_pow2(x):
def ctz(x):
"""Return the number of times 2 factors into X."""
+ assert x != 0
r = 0
while ((x >> r) & 1) == 0:
r += 1
@@ -127,6 +131,8 @@ def ctz(x):
def is_contiguous(bits):
+ if bits == 0:
+ return -1
shift = ctz(bits)
if is_pow2((bits >> shift) + 1):
return shift
@@ -364,32 +370,99 @@ class Pattern(General):
output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
output(ind, 'if (', translate_prefix, '_', self.name,
'(ctx, &u.f_', arg, ')) return true;\n')
+
+ # Normal patterns do not have children.
+ def build_tree(self):
+ return
+ def prop_masks(self):
+ return
+ def prop_format(self):
+ return
+ def prop_width(self):
+ return
+
# end Pattern
class MultiPattern(General):
- """Class representing an overlapping set of instruction patterns"""
+ """Class representing a set of instruction patterns"""
- def __init__(self, lineno, pats, fixb, fixm, udfm, w):
+ def __init__(self, lineno):
self.file = input_file
self.lineno = lineno
- self.pats = pats
+ self.pats = []
self.base = None
- self.fixedbits = fixb
- self.fixedmask = fixm
- self.undefmask = udfm
- self.width = w
+ self.fixedbits = 0
+ self.fixedmask = 0
+ self.undefmask = 0
+ self.width = None
def __str__(self):
- r = "{"
- for p in self.pats:
- r = r + ' ' + str(p)
- return r + "}"
+ r = 'group'
+ if self.fixedbits is not None:
+ r += ' ' + str_match_bits(self.fixedbits, self.fixedmask)
+ return r
def output_decl(self):
for p in self.pats:
p.output_decl()
+ def prop_masks(self):
+ global insnmask
+
+ fixedmask = insnmask
+ undefmask = insnmask
+
+ # Collect fixedmask/undefmask for all of the children.
+ for p in self.pats:
+ p.prop_masks()
+ fixedmask &= p.fixedmask
+ undefmask &= p.undefmask
+
+ # Widen fixedmask until all fixedbits match
+ repeat = True
+ fixedbits = 0
+ while repeat and fixedmask != 0:
+ fixedbits = None
+ for p in self.pats:
+ thisbits = p.fixedbits & fixedmask
+ if fixedbits is None:
+ fixedbits = thisbits
+ elif fixedbits != thisbits:
+ fixedmask &= ~(fixedbits ^ thisbits)
+ break
+ else:
+ repeat = False
+
+ self.fixedbits = fixedbits
+ self.fixedmask = fixedmask
+ self.undefmask = undefmask
+
+ def build_tree(self):
+ for p in self.pats:
+ p.build_tree()
+
+ def prop_format(self):
+ for p in self.pats:
+ p.build_tree()
+
+ def prop_width(self):
+ width = None
+ for p in self.pats:
+ p.prop_width()
+ if width is None:
+ width = p.width
+ elif width != p.width:
+ error_with_file(self.file, self.lineno,
+ 'width mismatch in patterns within braces')
+ self.width = width
+
+# end MultiPattern
+
+
+class IncMultiPattern(MultiPattern):
+ """Class representing an overlapping set of instruction patterns"""
+
def output_code(self, i, extracted, outerbits, outermask):
global translate_prefix
ind = str_indent(i)
@@ -406,7 +479,154 @@ class MultiPattern(General):
output(ind, '}\n')
else:
p.output_code(i, extracted, p.fixedbits, p.fixedmask)
-#end MultiPattern
+#end IncMultiPattern
+
+
+class Tree:
+ """Class representing a node in a decode tree"""
+
+ def __init__(self, fm, tm):
+ self.fixedmask = fm
+ self.thismask = tm
+ self.subs = []
+ self.base = None
+
+ def str1(self, i):
+ ind = str_indent(i)
+ r = '{0}{1:08x}'.format(ind, self.fixedmask)
+ if self.format:
+ r += ' ' + self.format.name
+ r += ' [\n'
+ for (b, s) in self.subs:
+ r += '{0} {1:08x}:\n'.format(ind, b)
+ r += s.str1(i + 4) + '\n'
+ r += ind + ']'
+ return r
+
+ def __str__(self):
+ return self.str1(0)
+
+ def output_code(self, i, extracted, outerbits, outermask):
+ ind = str_indent(i)
+
+ # If we identified all nodes below have the same format,
+ # extract the fields now.
+ if not extracted and self.base:
+ output(ind, self.base.extract_name(),
+ '(ctx, &u.f_', self.base.base.name, ', insn);\n')
+ extracted = True
+
+ # Attempt to aid the compiler in producing compact switch statements.
+ # If the bits in the mask are contiguous, extract them.
+ sh = is_contiguous(self.thismask)
+ if sh > 0:
+ # Propagate SH down into the local functions.
+ def str_switch(b, sh=sh):
+ return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
+
+ def str_case(b, sh=sh):
+ return '0x{0:x}'.format(b >> sh)
+ else:
+ def str_switch(b):
+ return 'insn & 0x{0:08x}'.format(b)
+
+ def str_case(b):
+ return '0x{0:08x}'.format(b)
+
+ output(ind, 'switch (', str_switch(self.thismask), ') {\n')
+ for b, s in sorted(self.subs):
+ assert (self.thismask & ~s.fixedmask) == 0
+ innermask = outermask | self.thismask
+ innerbits = outerbits | b
+ output(ind, 'case ', str_case(b), ':\n')
+ output(ind, ' /* ',
+ str_match_bits(innerbits, innermask), ' */\n')
+ s.output_code(i + 4, extracted, innerbits, innermask)
+ output(ind, ' return false;\n')
+ output(ind, '}\n')
+# end Tree
+
+
+class ExcMultiPattern(MultiPattern):
+ """Class representing a non-overlapping set of instruction patterns"""
+
+ def output_code(self, i, extracted, outerbits, outermask):
+ # Defer everything to our decomposed Tree node
+ self.tree.output_code(i, extracted, outerbits, outermask)
+
+ @staticmethod
+ def __build_tree(pats, outerbits, outermask):
+ # Find the intersection of all remaining fixedmask.
+ innermask = ~outermask & insnmask
+ for i in pats:
+ innermask &= i.fixedmask
+
+ if innermask == 0:
+ # Edge condition: One pattern covers the entire insnmask
+ if len(pats) == 1:
+ t = Tree(outermask, innermask)
+ t.subs.append((0, pats[0]))
+ return t
+
+ text = 'overlapping patterns:'
+ for p in pats:
+ text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
+ error_with_file(pats[0].file, pats[0].lineno, text)
+
+ fullmask = outermask | innermask
+
+ # Sort each element of pats into the bin selected by the mask.
+ bins = {}
+ for i in pats:
+ fb = i.fixedbits & innermask
+ if fb in bins:
+ bins[fb].append(i)
+ else:
+ bins[fb] = [i]
+
+ # We must recurse if any bin has more than one element or if
+ # the single element in the bin has not been fully matched.
+ t = Tree(fullmask, innermask)
+
+ for b, l in bins.items():
+ s = l[0]
+ if len(l) > 1 or s.fixedmask & ~fullmask != 0:
+ s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask)
+ t.subs.append((b, s))
+
+ return t
+
+ def build_tree(self):
+ super().prop_format()
+ self.tree = self.__build_tree(self.pats, self.fixedbits,
+ self.fixedmask)
+
+ @staticmethod
+ def __prop_format(tree):
+ """Propagate Format objects into the decode tree"""
+
+ # Depth first search.
+ for (b, s) in tree.subs:
+ if isinstance(s, Tree):
+ ExcMultiPattern.__prop_format(s)
+
+ # If all entries in SUBS have the same format, then
+ # propagate that into the tree.
+ f = None
+ for (b, s) in tree.subs:
+ if f is None:
+ f = s.base
+ if f is None:
+ return
+ if f is not s.base:
+ return
+ tree.base = f
+
+ def prop_format(self):
+ super().prop_format()
+ self.__prop_format(self.tree)
+
+# end ExcMultiPattern
def parse_field(lineno, name, toks):
@@ -565,18 +785,19 @@ def infer_format(arg, fieldmask, flds, width):
# end infer_format
-def parse_generic(lineno, is_format, name, toks):
+def parse_generic(lineno, parent_pat, name, toks):
"""Parse one instruction format from TOKS at LINENO"""
global fields
global arguments
global formats
- global patterns
global allpatterns
global re_ident
global insnwidth
global insnmask
global variablewidth
+ is_format = parent_pat is None
+
fixedmask = 0
fixedbits = 0
undefmask = 0
@@ -727,7 +948,7 @@ def parse_generic(lineno, is_format, name, toks):
error(lineno, 'field {0} not initialized'.format(f))
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
undefmask, fieldmask, flds, width)
- patterns.append(pat)
+ parent_pat.pats.append(pat)
allpatterns.append(pat)
# Validate the masks that we have assembled.
@@ -747,62 +968,16 @@ def parse_generic(lineno, is_format, name, toks):
.format(allbits ^ insnmask))
# end parse_general
-def build_multi_pattern(lineno, pats):
- """Validate the Patterns going into a MultiPattern."""
- global patterns
- global insnmask
-
- if len(pats) < 2:
- error(lineno, 'less than two patterns within braces')
-
- fixedmask = insnmask
- undefmask = insnmask
-
- # Collect fixed/undefmask for all of the children.
- # Move the defining lineno back to that of the first child.
- for p in pats:
- fixedmask &= p.fixedmask
- undefmask &= p.undefmask
- if p.lineno < lineno:
- lineno = p.lineno
-
- width = None
- for p in pats:
- if width is None:
- width = p.width
- elif width != p.width:
- error(lineno, 'width mismatch in patterns within braces')
-
- repeat = True
- while repeat:
- if fixedmask == 0:
- error(lineno, 'no overlap in patterns within braces')
- fixedbits = None
- for p in pats:
- thisbits = p.fixedbits & fixedmask
- if fixedbits is None:
- fixedbits = thisbits
- elif fixedbits != thisbits:
- fixedmask &= ~(fixedbits ^ thisbits)
- break
- else:
- repeat = False
- mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask, width)
- patterns.append(mp)
-# end build_multi_pattern
-
-def parse_file(f):
+def parse_file(f, parent_pat):
"""Parse all of the patterns within a file"""
- global patterns
-
# Read all of the lines of the file. Concatenate lines
# ending in backslash; discard empty lines and comments.
toks = []
lineno = 0
nesting = 0
- saved_pats = []
+ nesting_pats = []
for line in f:
lineno += 1
@@ -846,17 +1021,23 @@ def parse_file(f):
del toks[0]
# End nesting?
- if name == '}':
- if nesting == 0:
- error(start_lineno, 'mismatched close brace')
+ if name == '}' or name == ']':
if len(toks) != 0:
error(start_lineno, 'extra tokens after close brace')
+
+ # Make sure { } and [ ] nest properly.
+ if (name == '}') != isinstance(parent_pat, IncMultiPattern):
+ error(lineno, 'mismatched close brace')
+
+ try:
+ parent_pat = nesting_pats.pop()
+ except:
+ error(lineno, 'extra close brace')
+
nesting -= 2
if indent != nesting:
- error(start_lineno, 'indentation ', indent, ' != ', nesting)
- pats = patterns
- patterns = saved_pats.pop()
- build_multi_pattern(lineno, pats)
+ error(lineno, 'indentation ', indent, ' != ', nesting)
+
toks = []
continue
@@ -865,11 +1046,18 @@ def parse_file(f):
error(start_lineno, 'indentation ', indent, ' != ', nesting)
# Start nesting?
- if name == '{':
+ if name == '{' or name == '[':
if len(toks) != 0:
error(start_lineno, 'extra tokens after open brace')
- saved_pats.append(patterns)
- patterns = []
+
+ if name == '{':
+ nested_pat = IncMultiPattern(start_lineno)
+ else:
+ nested_pat = ExcMultiPattern(start_lineno)
+ parent_pat.pats.append(nested_pat)
+ nesting_pats.append(parent_pat)
+ parent_pat = nested_pat
+
nesting += 2
toks = []
continue
@@ -880,113 +1068,14 @@ def parse_file(f):
elif name[0] == '&':
parse_arguments(start_lineno, name[1:], toks)
elif name[0] == '@':
- parse_generic(start_lineno, True, name[1:], toks)
+ parse_generic(start_lineno, None, name[1:], toks)
else:
- parse_generic(start_lineno, False, name, toks)
+ parse_generic(start_lineno, parent_pat, name, toks)
toks = []
-# end parse_file
-
-
-class Tree:
- """Class representing a node in a decode tree"""
-
- def __init__(self, fm, tm):
- self.fixedmask = fm
- self.thismask = tm
- self.subs = []
- self.base = None
- def str1(self, i):
- ind = str_indent(i)
- r = '{0}{1:08x}'.format(ind, self.fixedmask)
- if self.format:
- r += ' ' + self.format.name
- r += ' [\n'
- for (b, s) in self.subs:
- r += '{0} {1:08x}:\n'.format(ind, b)
- r += s.str1(i + 4) + '\n'
- r += ind + ']'
- return r
-
- def __str__(self):
- return self.str1(0)
-
- def output_code(self, i, extracted, outerbits, outermask):
- ind = str_indent(i)
-
- # If we identified all nodes below have the same format,
- # extract the fields now.
- if not extracted and self.base:
- output(ind, self.base.extract_name(),
- '(ctx, &u.f_', self.base.base.name, ', insn);\n')
- extracted = True
-
- # Attempt to aid the compiler in producing compact switch statements.
- # If the bits in the mask are contiguous, extract them.
- sh = is_contiguous(self.thismask)
- if sh > 0:
- # Propagate SH down into the local functions.
- def str_switch(b, sh=sh):
- return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
-
- def str_case(b, sh=sh):
- return '0x{0:x}'.format(b >> sh)
- else:
- def str_switch(b):
- return 'insn & 0x{0:08x}'.format(b)
-
- def str_case(b):
- return '0x{0:08x}'.format(b)
-
- output(ind, 'switch (', str_switch(self.thismask), ') {\n')
- for b, s in sorted(self.subs):
- assert (self.thismask & ~s.fixedmask) == 0
- innermask = outermask | self.thismask
- innerbits = outerbits | b
- output(ind, 'case ', str_case(b), ':\n')
- output(ind, ' /* ',
- str_match_bits(innerbits, innermask), ' */\n')
- s.output_code(i + 4, extracted, innerbits, innermask)
- output(ind, ' return false;\n')
- output(ind, '}\n')
-# end Tree
-
-
-def build_tree(pats, outerbits, outermask):
- # Find the intersection of all remaining fixedmask.
- innermask = ~outermask & insnmask
- for i in pats:
- innermask &= i.fixedmask
-
- if innermask == 0:
- text = 'overlapping patterns:'
- for p in pats:
- text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
- error_with_file(pats[0].file, pats[0].lineno, text)
-
- fullmask = outermask | innermask
-
- # Sort each element of pats into the bin selected by the mask.
- bins = {}
- for i in pats:
- fb = i.fixedbits & innermask
- if fb in bins:
- bins[fb].append(i)
- else:
- bins[fb] = [i]
-
- # We must recurse if any bin has more than one element or if
- # the single element in the bin has not been fully matched.
- t = Tree(fullmask, innermask)
-
- for b, l in bins.items():
- s = l[0]
- if len(l) > 1 or s.fixedmask & ~fullmask != 0:
- s = build_tree(l, b | outerbits, fullmask)
- t.subs.append((b, s))
-
- return t
-# end build_tree
+ if nesting != 0:
+ error(lineno, 'missing close brace')
+# end parse_file
class SizeTree:
@@ -1130,28 +1219,6 @@ def build_size_tree(pats, width, outerbits, outermask):
# end build_size_tree
-def prop_format(tree):
- """Propagate Format objects into the decode tree"""
-
- # Depth first search.
- for (b, s) in tree.subs:
- if isinstance(s, Tree):
- prop_format(s)
-
- # If all entries in SUBS have the same format, then
- # propagate that into the tree.
- f = None
- for (b, s) in tree.subs:
- if f is None:
- f = s.base
- if f is None:
- return
- if f is not s.base:
- return
- tree.base = f
-# end prop_format
-
-
def prop_size(tree):
"""Propagate minimum widths up the decode size tree"""
@@ -1172,7 +1239,6 @@ def prop_size(tree):
def main():
global arguments
global formats
- global patterns
global allpatterns
global translate_scope
global translate_prefix
@@ -1219,19 +1285,30 @@ def main():
if len(args) < 1:
error(0, 'missing input file')
+
+ toppat = ExcMultiPattern(0)
+
for filename in args:
input_file = filename
f = open(filename, 'r')
- parse_file(f)
+ parse_file(f, toppat)
f.close()
+ # We do not want to compute masks for toppat, because those masks
+ # are used as a starting point for build_tree. For toppat, we must
+ # insist that decode begins from naught.
+ for i in toppat.pats:
+ i.prop_masks()
+
+ toppat.build_tree()
+ toppat.prop_format()
+
if variablewidth:
- stree = build_size_tree(patterns, 8, 0, 0)
+ for i in toppat.pats:
+ i.prop_width()
+ stree = build_size_tree(toppat.pats, 8, 0, 0)
prop_size(stree)
- dtree = build_tree(patterns, 0, 0)
- prop_format(dtree)
-
if output_file:
output_fd = open(output_file, 'w')
else:
@@ -1289,7 +1366,7 @@ def main():
f = arguments[n]
output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
output(i4, '} u;\n\n')
- dtree.output_code(4, False, 0, 0)
+ toppat.output_code(4, False, 0, 0)
output(i4, 'return false;\n')
output('}\n')
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
index c63082fc9c..c21a988f97 100644
--- a/target/arm/t32.decode
+++ b/target/arm/t32.decode
@@ -312,13 +312,13 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
&cps
# Miscellaneous control
- {
+ [
CLREX 1111 0011 1011 1111 1000 1111 0010 1111
DSB 1111 0011 1011 1111 1000 1111 0100 ----
DMB 1111 0011 1011 1111 1000 1111 0101 ----
ISB 1111 0011 1011 1111 1000 1111 0110 ----
SB 1111 0011 1011 1111 1000 1111 0111 0000
- }
+ ]
# Note that the v7m insn overlaps both the normal and banked insn.
{
diff --git a/target/mips/Makefile.objs b/target/mips/Makefile.objs
index 91eb691833..b820b3b7bc 100644
--- a/target/mips/Makefile.objs
+++ b/target/mips/Makefile.objs
@@ -1,6 +1,6 @@
obj-y += translate.o cpu.o gdbstub.o helper.o
obj-y += op_helper.o cp0_helper.o fpu_helper.o
-obj-y += dsp_helper.o lmi_helper.o msa_helper.o
+obj-y += dsp_helper.o lmmi_helper.o msa_helper.o
obj-$(CONFIG_SOFTMMU) += mips-semi.o
obj-$(CONFIG_SOFTMMU) += machine.o cp0_timer.o
obj-$(CONFIG_KVM) += kvm.o
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 94d01ea798..7cf7f5239f 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -198,8 +198,8 @@ typedef struct mips_def_t mips_def_t;
* 3 Config3 WatchLo3 WatchHi
* 4 Config4 WatchLo4 WatchHi
* 5 Config5 WatchLo5 WatchHi
- * 6 WatchLo6 WatchHi
- * 7 WatchLo7 WatchHi
+ * 6 Config6 WatchLo6 WatchHi
+ * 7 Config7 WatchLo7 WatchHi
*
*
* Register 20 Register 21 Register 22 Register 23
@@ -940,7 +940,35 @@ struct CPUMIPSState {
#define CP0C5_UFR 2
#define CP0C5_NFExists 0
int32_t CP0_Config6;
+ int32_t CP0_Config6_rw_bitmask;
+#define CP0C6_BPPASS 31
+#define CP0C6_KPOS 24
+#define CP0C6_KE 23
+#define CP0C6_VTLBONLY 22
+#define CP0C6_LASX 21
+#define CP0C6_SSEN 20
+#define CP0C6_DISDRTIME 19
+#define CP0C6_PIXNUEN 18
+#define CP0C6_SCRAND 17
+#define CP0C6_LLEXCEN 16
+#define CP0C6_DISVC 15
+#define CP0C6_VCLRU 14
+#define CP0C6_DCLRU 13
+#define CP0C6_PIXUEN 12
+#define CP0C6_DISBLKLYEN 11
+#define CP0C6_UMEMUALEN 10
+#define CP0C6_SFBEN 8
+#define CP0C6_FLTINT 7
+#define CP0C6_VLTINT 6
+#define CP0C6_DISBTB 5
+#define CP0C6_STPREFCTL 2
+#define CP0C6_INSTPREF 1
+#define CP0C6_DATAPREF 0
int32_t CP0_Config7;
+ int64_t CP0_Config7_rw_bitmask;
+#define CP0C7_NAPCGEN 2
+#define CP0C7_UNIMUEN 1
+#define CP0C7_VFPUCGEN 0
uint64_t CP0_LLAddr;
uint64_t CP0_MAAR[MIPS_MAAR_MAX];
int32_t CP0_MAARI;
diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c
index 5287c86c61..7a3a61cab3 100644
--- a/target/mips/fpu_helper.c
+++ b/target/mips/fpu_helper.c
@@ -189,43 +189,48 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
}
}
-int ieee_ex_to_mips(int xcpt)
+static inline int ieee_to_mips_xcpt(int ieee_xcpt)
{
- 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;
- }
+ int mips_xcpt = 0;
+
+ if (ieee_xcpt & float_flag_invalid) {
+ mips_xcpt |= FP_INVALID;
+ }
+ if (ieee_xcpt & float_flag_overflow) {
+ mips_xcpt |= FP_OVERFLOW;
+ }
+ if (ieee_xcpt & float_flag_underflow) {
+ mips_xcpt |= FP_UNDERFLOW;
}
- return ret;
+ if (ieee_xcpt & float_flag_divbyzero) {
+ mips_xcpt |= FP_DIV0;
+ }
+ if (ieee_xcpt & float_flag_inexact) {
+ mips_xcpt |= FP_INEXACT;
+ }
+
+ return mips_xcpt;
}
static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
{
- int tmp = ieee_ex_to_mips(get_float_exception_flags(
- &env->active_fpu.fp_status));
+ int ieee_exception_flags = get_float_exception_flags(
+ &env->active_fpu.fp_status);
+ int mips_exception_flags = 0;
- SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
+ if (ieee_exception_flags) {
+ mips_exception_flags = ieee_to_mips_xcpt(ieee_exception_flags);
+ }
- if (tmp) {
+ SET_FP_CAUSE(env->active_fpu.fcr31, mips_exception_flags);
+
+ if (mips_exception_flags) {
set_float_exception_flags(0, &env->active_fpu.fp_status);
- if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
+ if (GET_FP_ENABLE(env->active_fpu.fcr31) & mips_exception_flags) {
do_raise_exception(env, EXCP_FPE, pc);
} else {
- UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
+ UPDATE_FP_FLAGS(env->active_fpu.fcr31, mips_exception_flags);
}
}
}
@@ -1059,14 +1064,14 @@ uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
{
- uint32_t fst2;
+ uint32_t fstl2;
uint32_t fsth2;
- fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF,
- &env->active_fpu.fp_status);
+ fstl2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF,
+ &env->active_fpu.fp_status);
fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
- return ((uint64_t)fsth2 << 32) | fst2;
+ return ((uint64_t)fsth2 << 32) | fstl2;
}
uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
@@ -1091,31 +1096,34 @@ uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
{
- uint32_t fst2;
+ uint32_t fstl2;
uint32_t fsth2;
- fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
+ fstl2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
- fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
+ fstl2 = float32_div(float32_one, fstl2, &env->active_fpu.fp_status);
fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
- return ((uint64_t)fsth2 << 32) | fst2;
+ return ((uint64_t)fsth2 << 32) | fstl2;
}
-#define FLOAT_RINT(name, bits) \
-uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \
- uint ## bits ## _t fs) \
-{ \
- uint ## bits ## _t fdret; \
- \
- fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
- update_fcr31(env, GETPC()); \
- return fdret; \
+uint64_t helper_float_rint_d(CPUMIPSState *env, uint64_t fs)
+{
+ uint64_t fdret;
+
+ fdret = float64_round_to_int(fs, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return fdret;
}
-FLOAT_RINT(rint_s, 32)
-FLOAT_RINT(rint_d, 64)
-#undef FLOAT_RINT
+uint32_t helper_float_rint_s(CPUMIPSState *env, uint32_t fs)
+{
+ uint32_t fdret;
+
+ fdret = float32_round_to_int(fs, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return fdret;
+}
#define FLOAT_CLASS_SIGNALING_NAN 0x001
#define FLOAT_CLASS_QUIET_NAN 0x002
@@ -1128,91 +1136,220 @@ FLOAT_RINT(rint_d, 64)
#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
#define FLOAT_CLASS_POSITIVE_ZERO 0x200
-#define FLOAT_CLASS(name, bits) \
-uint ## bits ## _t float_ ## name(uint ## bits ## _t arg, \
- float_status *status) \
-{ \
- if (float ## bits ## _is_signaling_nan(arg, status)) { \
- return FLOAT_CLASS_SIGNALING_NAN; \
- } else if (float ## bits ## _is_quiet_nan(arg, status)) { \
- return FLOAT_CLASS_QUIET_NAN; \
- } else if (float ## bits ## _is_neg(arg)) { \
- if (float ## bits ## _is_infinity(arg)) { \
- return FLOAT_CLASS_NEGATIVE_INFINITY; \
- } else if (float ## bits ## _is_zero(arg)) { \
- return FLOAT_CLASS_NEGATIVE_ZERO; \
- } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
- return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \
- } else { \
- return FLOAT_CLASS_NEGATIVE_NORMAL; \
- } \
- } else { \
- if (float ## bits ## _is_infinity(arg)) { \
- return FLOAT_CLASS_POSITIVE_INFINITY; \
- } else if (float ## bits ## _is_zero(arg)) { \
- return FLOAT_CLASS_POSITIVE_ZERO; \
- } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
- return FLOAT_CLASS_POSITIVE_SUBNORMAL; \
- } else { \
- return FLOAT_CLASS_POSITIVE_NORMAL; \
- } \
- } \
-} \
- \
-uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \
- uint ## bits ## _t arg) \
-{ \
- return float_ ## name(arg, &env->active_fpu.fp_status); \
-}
-
-FLOAT_CLASS(class_s, 32)
-FLOAT_CLASS(class_d, 64)
-#undef FLOAT_CLASS
+uint64_t float_class_d(uint64_t arg, float_status *status)
+{
+ if (float64_is_signaling_nan(arg, status)) {
+ return FLOAT_CLASS_SIGNALING_NAN;
+ } else if (float64_is_quiet_nan(arg, status)) {
+ return FLOAT_CLASS_QUIET_NAN;
+ } else if (float64_is_neg(arg)) {
+ if (float64_is_infinity(arg)) {
+ return FLOAT_CLASS_NEGATIVE_INFINITY;
+ } else if (float64_is_zero(arg)) {
+ return FLOAT_CLASS_NEGATIVE_ZERO;
+ } else if (float64_is_zero_or_denormal(arg)) {
+ return FLOAT_CLASS_NEGATIVE_SUBNORMAL;
+ } else {
+ return FLOAT_CLASS_NEGATIVE_NORMAL;
+ }
+ } else {
+ if (float64_is_infinity(arg)) {
+ return FLOAT_CLASS_POSITIVE_INFINITY;
+ } else if (float64_is_zero(arg)) {
+ return FLOAT_CLASS_POSITIVE_ZERO;
+ } else if (float64_is_zero_or_denormal(arg)) {
+ return FLOAT_CLASS_POSITIVE_SUBNORMAL;
+ } else {
+ return FLOAT_CLASS_POSITIVE_NORMAL;
+ }
+ }
+}
+
+uint64_t helper_float_class_d(CPUMIPSState *env, uint64_t arg)
+{
+ return float_class_d(arg, &env->active_fpu.fp_status);
+}
+
+uint32_t float_class_s(uint32_t arg, float_status *status)
+{
+ if (float32_is_signaling_nan(arg, status)) {
+ return FLOAT_CLASS_SIGNALING_NAN;
+ } else if (float32_is_quiet_nan(arg, status)) {
+ return FLOAT_CLASS_QUIET_NAN;
+ } else if (float32_is_neg(arg)) {
+ if (float32_is_infinity(arg)) {
+ return FLOAT_CLASS_NEGATIVE_INFINITY;
+ } else if (float32_is_zero(arg)) {
+ return FLOAT_CLASS_NEGATIVE_ZERO;
+ } else if (float32_is_zero_or_denormal(arg)) {
+ return FLOAT_CLASS_NEGATIVE_SUBNORMAL;
+ } else {
+ return FLOAT_CLASS_NEGATIVE_NORMAL;
+ }
+ } else {
+ if (float32_is_infinity(arg)) {
+ return FLOAT_CLASS_POSITIVE_INFINITY;
+ } else if (float32_is_zero(arg)) {
+ return FLOAT_CLASS_POSITIVE_ZERO;
+ } else if (float32_is_zero_or_denormal(arg)) {
+ return FLOAT_CLASS_POSITIVE_SUBNORMAL;
+ } else {
+ return FLOAT_CLASS_POSITIVE_NORMAL;
+ }
+ }
+}
+
+uint32_t helper_float_class_s(CPUMIPSState *env, uint32_t arg)
+{
+ return float_class_s(arg, &env->active_fpu.fp_status);
+}
/* binary operations */
-#define FLOAT_BINOP(name) \
-uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
- uint64_t fdt0, uint64_t fdt1) \
-{ \
- uint64_t dt2; \
- \
- dt2 = float64_ ## name(fdt0, fdt1, &env->active_fpu.fp_status);\
- update_fcr31(env, GETPC()); \
- return dt2; \
-} \
- \
-uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
- uint32_t fst0, uint32_t fst1) \
-{ \
- uint32_t wt2; \
- \
- wt2 = float32_ ## name(fst0, fst1, &env->active_fpu.fp_status);\
- update_fcr31(env, GETPC()); \
- return wt2; \
-} \
- \
-uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
- uint64_t fdt0, \
- uint64_t fdt1) \
-{ \
- uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
- uint32_t fsth0 = fdt0 >> 32; \
- uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
- uint32_t fsth1 = fdt1 >> 32; \
- uint32_t wt2; \
- uint32_t wth2; \
- \
- wt2 = float32_ ## name(fst0, fst1, &env->active_fpu.fp_status); \
- wth2 = float32_ ## name(fsth0, fsth1, &env->active_fpu.fp_status); \
- update_fcr31(env, GETPC()); \
- return ((uint64_t)wth2 << 32) | wt2; \
-}
-
-FLOAT_BINOP(add)
-FLOAT_BINOP(sub)
-FLOAT_BINOP(mul)
-FLOAT_BINOP(div)
-#undef FLOAT_BINOP
+
+uint64_t helper_float_add_d(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint64_t dt2;
+
+ dt2 = float64_add(fdt0, fdt1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return dt2;
+}
+
+uint32_t helper_float_add_s(CPUMIPSState *env,
+ uint32_t fst0, uint32_t fst1)
+{
+ uint32_t wt2;
+
+ wt2 = float32_sub(fst0, fst1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return wt2;
+}
+
+uint64_t helper_float_add_ps(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t wtl2;
+ uint32_t wth2;
+
+ wtl2 = float32_add(fstl0, fstl1, &env->active_fpu.fp_status);
+ wth2 = float32_add(fsth0, fsth1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return ((uint64_t)wth2 << 32) | wtl2;
+}
+
+uint64_t helper_float_sub_d(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint64_t dt2;
+
+ dt2 = float64_sub(fdt0, fdt1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return dt2;
+}
+
+uint32_t helper_float_sub_s(CPUMIPSState *env,
+ uint32_t fst0, uint32_t fst1)
+{
+ uint32_t wt2;
+
+ wt2 = float32_sub(fst0, fst1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return wt2;
+}
+
+uint64_t helper_float_sub_ps(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t wtl2;
+ uint32_t wth2;
+
+ wtl2 = float32_sub(fstl0, fstl1, &env->active_fpu.fp_status);
+ wth2 = float32_sub(fsth0, fsth1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return ((uint64_t)wth2 << 32) | wtl2;
+}
+
+uint64_t helper_float_mul_d(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint64_t dt2;
+
+ dt2 = float64_mul(fdt0, fdt1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return dt2;
+}
+
+uint32_t helper_float_mul_s(CPUMIPSState *env,
+ uint32_t fst0, uint32_t fst1)
+{
+ uint32_t wt2;
+
+ wt2 = float32_mul(fst0, fst1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return wt2;
+}
+
+uint64_t helper_float_mul_ps(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t wtl2;
+ uint32_t wth2;
+
+ wtl2 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status);
+ wth2 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return ((uint64_t)wth2 << 32) | wtl2;
+}
+
+uint64_t helper_float_div_d(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint64_t dt2;
+
+ dt2 = float64_div(fdt0, fdt1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return dt2;
+}
+
+uint32_t helper_float_div_s(CPUMIPSState *env,
+ uint32_t fst0, uint32_t fst1)
+{
+ uint32_t wt2;
+
+ wt2 = float32_div(fst0, fst1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return wt2;
+}
+
+uint64_t helper_float_div_ps(CPUMIPSState *env,
+ uint64_t fdt0, uint64_t fdt1)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t wtl2;
+ uint32_t wth2;
+
+ wtl2 = float32_div(fstl0, fstl1, &env->active_fpu.fp_status);
+ wth2 = float32_div(fsth0, fsth1, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return ((uint64_t)wth2 << 32) | wtl2;
+}
+
/* MIPS specific binary operations */
uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
@@ -1235,19 +1372,19 @@ uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
{
- uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
uint32_t fsth0 = fdt0 >> 32;
- uint32_t fst2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fstl2 = fdt2 & 0XFFFFFFFF;
uint32_t fsth2 = fdt2 >> 32;
- fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
+ fstl2 = float32_mul(fstl0, fstl2, &env->active_fpu.fp_status);
fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
- fst2 = float32_chs(float32_sub(fst2, float32_one,
+ fstl2 = float32_chs(float32_sub(fstl2, float32_one,
&env->active_fpu.fp_status));
fsth2 = float32_chs(float32_sub(fsth2, float32_one,
&env->active_fpu.fp_status));
update_fcr31(env, GETPC());
- return ((uint64_t)fsth2 << 32) | fst2;
+ return ((uint64_t)fsth2 << 32) | fstl2;
}
uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
@@ -1272,51 +1409,51 @@ uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
{
- uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
uint32_t fsth0 = fdt0 >> 32;
- uint32_t fst2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fstl2 = fdt2 & 0XFFFFFFFF;
uint32_t fsth2 = fdt2 >> 32;
- fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
+ fstl2 = float32_mul(fstl0, fstl2, &env->active_fpu.fp_status);
fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
- fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
+ fstl2 = float32_sub(fstl2, float32_one, &env->active_fpu.fp_status);
fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
- fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32,
+ fstl2 = float32_chs(float32_div(fstl2, FLOAT_TWO32,
&env->active_fpu.fp_status));
fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32,
&env->active_fpu.fp_status));
update_fcr31(env, GETPC());
- return ((uint64_t)fsth2 << 32) | fst2;
+ return ((uint64_t)fsth2 << 32) | fstl2;
}
uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
{
- uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
uint32_t fsth0 = fdt0 >> 32;
- uint32_t fst1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
uint32_t fsth1 = fdt1 >> 32;
- uint32_t fst2;
+ uint32_t fstl2;
uint32_t fsth2;
- fst2 = float32_add(fst0, fsth0, &env->active_fpu.fp_status);
- fsth2 = float32_add(fst1, fsth1, &env->active_fpu.fp_status);
+ fstl2 = float32_add(fstl0, fsth0, &env->active_fpu.fp_status);
+ fsth2 = float32_add(fstl1, fsth1, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
- return ((uint64_t)fsth2 << 32) | fst2;
+ return ((uint64_t)fsth2 << 32) | fstl2;
}
uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
{
- uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
uint32_t fsth0 = fdt0 >> 32;
- uint32_t fst1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
uint32_t fsth1 = fdt1 >> 32;
- uint32_t fst2;
+ uint32_t fstl2;
uint32_t fsth2;
- fst2 = float32_mul(fst0, fsth0, &env->active_fpu.fp_status);
- fsth2 = float32_mul(fst1, fsth1, &env->active_fpu.fp_status);
+ fstl2 = float32_mul(fstl0, fsth0, &env->active_fpu.fp_status);
+ fsth2 = float32_mul(fstl1, fsth1, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
- return ((uint64_t)fsth2 << 32) | fst2;
+ return ((uint64_t)fsth2 << 32) | fstl2;
}
#define FLOAT_MINMAX(name, bits, minmaxfunc) \
@@ -1344,60 +1481,171 @@ FLOAT_MINMAX(mina_d, 64, minnummag)
#undef FLOAT_MINMAX
/* ternary operations */
-#define UNFUSED_FMA(prefix, a, b, c, flags) \
-{ \
- a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
- if ((flags) & float_muladd_negate_c) { \
- a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
- } else { \
- a = prefix##_add(a, c, &env->active_fpu.fp_status); \
- } \
- if ((flags) & float_muladd_negate_result) { \
- a = prefix##_chs(a); \
- } \
-}
-
-/* FMA based operations */
-#define FLOAT_FMA(name, type) \
-uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
- uint64_t fdt0, uint64_t fdt1, \
- uint64_t fdt2) \
-{ \
- UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
- update_fcr31(env, GETPC()); \
- return fdt0; \
-} \
- \
-uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
- uint32_t fst0, uint32_t fst1, \
- uint32_t fst2) \
-{ \
- UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
- update_fcr31(env, GETPC()); \
- return fst0; \
-} \
- \
-uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
- uint64_t fdt0, uint64_t fdt1, \
- uint64_t fdt2) \
-{ \
- uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
- uint32_t fsth0 = fdt0 >> 32; \
- uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
- uint32_t fsth1 = fdt1 >> 32; \
- uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
- uint32_t fsth2 = fdt2 >> 32; \
- \
- UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
- UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
- update_fcr31(env, GETPC()); \
- return ((uint64_t)fsth0 << 32) | fst0; \
-}
-FLOAT_FMA(madd, 0)
-FLOAT_FMA(msub, float_muladd_negate_c)
-FLOAT_FMA(nmadd, float_muladd_negate_result)
-FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
-#undef FLOAT_FMA
+
+uint64_t helper_float_madd_d(CPUMIPSState *env, uint64_t fst0,
+ uint64_t fst1, uint64_t fst2)
+{
+ fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float64_add(fst0, fst2, &env->active_fpu.fp_status);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint32_t helper_float_madd_s(CPUMIPSState *env, uint32_t fst0,
+ uint32_t fst1, uint32_t fst2)
+{
+ fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float32_add(fst0, fst2, &env->active_fpu.fp_status);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint64_t helper_float_madd_ps(CPUMIPSState *env, uint64_t fdt0,
+ uint64_t fdt1, uint64_t fdt2)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t fstl2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fsth2 = fdt2 >> 32;
+
+ fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status);
+ fstl0 = float32_add(fstl0, fstl2, &env->active_fpu.fp_status);
+ fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status);
+ fsth0 = float32_add(fsth0, fsth2, &env->active_fpu.fp_status);
+
+ update_fcr31(env, GETPC());
+ return ((uint64_t)fsth0 << 32) | fstl0;
+}
+
+uint64_t helper_float_msub_d(CPUMIPSState *env, uint64_t fst0,
+ uint64_t fst1, uint64_t fst2)
+{
+ fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float64_sub(fst0, fst2, &env->active_fpu.fp_status);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint32_t helper_float_msub_s(CPUMIPSState *env, uint32_t fst0,
+ uint32_t fst1, uint32_t fst2)
+{
+ fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float32_sub(fst0, fst2, &env->active_fpu.fp_status);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint64_t helper_float_msub_ps(CPUMIPSState *env, uint64_t fdt0,
+ uint64_t fdt1, uint64_t fdt2)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t fstl2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fsth2 = fdt2 >> 32;
+
+ fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status);
+ fstl0 = float32_sub(fstl0, fstl2, &env->active_fpu.fp_status);
+ fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status);
+ fsth0 = float32_sub(fsth0, fsth2, &env->active_fpu.fp_status);
+
+ update_fcr31(env, GETPC());
+ return ((uint64_t)fsth0 << 32) | fstl0;
+}
+
+uint64_t helper_float_nmadd_d(CPUMIPSState *env, uint64_t fst0,
+ uint64_t fst1, uint64_t fst2)
+{
+ fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float64_add(fst0, fst2, &env->active_fpu.fp_status);
+ fst0 = float64_chs(fst0);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint32_t helper_float_nmadd_s(CPUMIPSState *env, uint32_t fst0,
+ uint32_t fst1, uint32_t fst2)
+{
+ fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float32_add(fst0, fst2, &env->active_fpu.fp_status);
+ fst0 = float32_chs(fst0);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint64_t helper_float_nmadd_ps(CPUMIPSState *env, uint64_t fdt0,
+ uint64_t fdt1, uint64_t fdt2)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t fstl2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fsth2 = fdt2 >> 32;
+
+ fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status);
+ fstl0 = float32_add(fstl0, fstl2, &env->active_fpu.fp_status);
+ fstl0 = float32_chs(fstl0);
+ fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status);
+ fsth0 = float32_add(fsth0, fsth2, &env->active_fpu.fp_status);
+ fsth0 = float32_chs(fsth0);
+
+ update_fcr31(env, GETPC());
+ return ((uint64_t)fsth0 << 32) | fstl0;
+}
+
+uint64_t helper_float_nmsub_d(CPUMIPSState *env, uint64_t fst0,
+ uint64_t fst1, uint64_t fst2)
+{
+ fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float64_sub(fst0, fst2, &env->active_fpu.fp_status);
+ fst0 = float64_chs(fst0);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint32_t helper_float_nmsub_s(CPUMIPSState *env, uint32_t fst0,
+ uint32_t fst1, uint32_t fst2)
+{
+ fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status);
+ fst0 = float32_sub(fst0, fst2, &env->active_fpu.fp_status);
+ fst0 = float32_chs(fst0);
+
+ update_fcr31(env, GETPC());
+ return fst0;
+}
+
+uint64_t helper_float_nmsub_ps(CPUMIPSState *env, uint64_t fdt0,
+ uint64_t fdt1, uint64_t fdt2)
+{
+ uint32_t fstl0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fstl1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t fstl2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fsth2 = fdt2 >> 32;
+
+ fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status);
+ fstl0 = float32_sub(fstl0, fstl2, &env->active_fpu.fp_status);
+ fstl0 = float32_chs(fstl0);
+ fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status);
+ fsth0 = float32_sub(fsth0, fsth2, &env->active_fpu.fp_status);
+ fsth0 = float32_chs(fsth0);
+
+ update_fcr31(env, GETPC());
+ return ((uint64_t)fsth0 << 32) | fstl0;
+}
+
#define FLOAT_FMADDSUB(name, bits, muladd_arg) \
uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \
diff --git a/target/mips/internal.h b/target/mips/internal.h
index 1bf274b3ef..7f159a9230 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -36,7 +36,9 @@ struct mips_def_t {
int32_t CP0_Config5;
int32_t CP0_Config5_rw_bitmask;
int32_t CP0_Config6;
+ int32_t CP0_Config6_rw_bitmask;
int32_t CP0_Config7;
+ int32_t CP0_Config7_rw_bitmask;
target_ulong CP0_LLAddr_rw_bitmask;
int CP0_LLAddr_shift;
int32_t SYNCI_Step;
@@ -224,7 +226,6 @@ uint32_t float_class_s(uint32_t arg, float_status *fst);
uint64_t float_class_d(uint64_t arg, float_status *fst);
extern unsigned int ieee_rm[];
-int ieee_ex_to_mips(int xcpt);
void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask);
static inline void restore_rounding_mode(CPUMIPSState *env)
diff --git a/target/mips/lmi_helper.c b/target/mips/lmmi_helper.c
index 6c645cf679..6c645cf679 100644
--- a/target/mips/lmi_helper.c
+++ b/target/mips/lmmi_helper.c
diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h
index a831bb4384..0c129106c8 100644
--- a/target/mips/mips-defs.h
+++ b/target/mips/mips-defs.h
@@ -15,7 +15,7 @@
* ------------------------------------------------
*/
/*
- * bits 0-31: MIPS base instruction sets
+ * bits 0-23: MIPS base instruction sets
*/
#define ISA_MIPS1 0x0000000000000001ULL
#define ISA_MIPS2 0x0000000000000002ULL
@@ -34,30 +34,33 @@
#define ISA_MIPS64R6 0x0000000000004000ULL
#define ISA_NANOMIPS32 0x0000000000008000ULL
/*
- * bits 32-47: MIPS ASEs
+ * bits 24-39: MIPS ASEs
*/
-#define ASE_MIPS16 0x0000000100000000ULL
-#define ASE_MIPS3D 0x0000000200000000ULL
-#define ASE_MDMX 0x0000000400000000ULL
-#define ASE_DSP 0x0000000800000000ULL
-#define ASE_DSP_R2 0x0000001000000000ULL
-#define ASE_DSP_R3 0x0000002000000000ULL
-#define ASE_MT 0x0000004000000000ULL
-#define ASE_SMARTMIPS 0x0000008000000000ULL
-#define ASE_MICROMIPS 0x0000010000000000ULL
-#define ASE_MSA 0x0000020000000000ULL
+#define ASE_MIPS16 0x0000000001000000ULL
+#define ASE_MIPS3D 0x0000000002000000ULL
+#define ASE_MDMX 0x0000000004000000ULL
+#define ASE_DSP 0x0000000008000000ULL
+#define ASE_DSP_R2 0x0000000010000000ULL
+#define ASE_DSP_R3 0x0000000020000000ULL
+#define ASE_MT 0x0000000040000000ULL
+#define ASE_SMARTMIPS 0x0000000080000000ULL
+#define ASE_MICROMIPS 0x0000000100000000ULL
+#define ASE_MSA 0x0000000200000000ULL
/*
- * bits 48-55: vendor-specific base instruction sets
+ * bits 40-51: vendor-specific base instruction sets
*/
-#define INSN_LOONGSON2E 0x0001000000000000ULL
-#define INSN_LOONGSON2F 0x0002000000000000ULL
-#define INSN_VR54XX 0x0004000000000000ULL
-#define INSN_R5900 0x0008000000000000ULL
+#define INSN_VR54XX 0x0000010000000000ULL
+#define INSN_R5900 0x0000020000000000ULL
+#define INSN_LOONGSON2E 0x0000040000000000ULL
+#define INSN_LOONGSON2F 0x0000080000000000ULL
+#define INSN_LOONGSON3A 0x0000100000000000ULL
/*
- * bits 56-63: vendor-specific ASEs
+ * bits 52-63: vendor-specific ASEs
*/
-#define ASE_MMI 0x0100000000000000ULL
-#define ASE_MXU 0x0200000000000000ULL
+#define ASE_MMI 0x0010000000000000ULL
+#define ASE_MXU 0x0020000000000000ULL
+#define ASE_LMMI 0x0040000000000000ULL
+#define ASE_LEXT 0x0080000000000000ULL
/* MIPS CPU defines. */
#define CPU_MIPS1 (ISA_MIPS1)
@@ -94,6 +97,8 @@
/* Wave Computing: "nanoMIPS" */
#define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32)
+#define CPU_LOONGSON3A (CPU_MIPS64R2 | INSN_LOONGSON3A)
+
/*
* Strictly follow the architecture standard:
* - Disallow "special" instruction handling for PMON/SPIM.
diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c
index 3c7012c0b8..c3b271934a 100644
--- a/target/mips/msa_helper.c
+++ b/target/mips/msa_helper.c
@@ -5419,54 +5419,81 @@ static inline void check_msacsr_cause(CPUMIPSState *env, uintptr_t retaddr)
#define CLEAR_IS_INEXACT 2
#define RECIPROCAL_INEXACT 4
-static inline int update_msacsr(CPUMIPSState *env, int action, int denormal)
+
+static inline int ieee_to_mips_xcpt_msa(int ieee_xcpt)
{
- int ieee_ex;
+ int mips_xcpt = 0;
- int c;
+ if (ieee_xcpt & float_flag_invalid) {
+ mips_xcpt |= FP_INVALID;
+ }
+ if (ieee_xcpt & float_flag_overflow) {
+ mips_xcpt |= FP_OVERFLOW;
+ }
+ if (ieee_xcpt & float_flag_underflow) {
+ mips_xcpt |= FP_UNDERFLOW;
+ }
+ if (ieee_xcpt & float_flag_divbyzero) {
+ mips_xcpt |= FP_DIV0;
+ }
+ if (ieee_xcpt & float_flag_inexact) {
+ mips_xcpt |= FP_INEXACT;
+ }
+
+ return mips_xcpt;
+}
+
+static inline int update_msacsr(CPUMIPSState *env, int action, int denormal)
+{
+ int ieee_exception_flags;
+ int mips_exception_flags = 0;
int cause;
int enable;
- ieee_ex = get_float_exception_flags(&env->active_tc.msa_fp_status);
+ ieee_exception_flags = get_float_exception_flags(
+ &env->active_tc.msa_fp_status);
/* QEMU softfloat does not signal all underflow cases */
if (denormal) {
- ieee_ex |= float_flag_underflow;
+ ieee_exception_flags |= float_flag_underflow;
+ }
+ if (ieee_exception_flags) {
+ mips_exception_flags = ieee_to_mips_xcpt_msa(ieee_exception_flags);
}
-
- c = ieee_ex_to_mips(ieee_ex);
enable = GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED;
/* Set Inexact (I) when flushing inputs to zero */
- if ((ieee_ex & float_flag_input_denormal) &&
+ if ((ieee_exception_flags & float_flag_input_denormal) &&
(env->active_tc.msacsr & MSACSR_FS_MASK) != 0) {
if (action & CLEAR_IS_INEXACT) {
- c &= ~FP_INEXACT;
+ mips_exception_flags &= ~FP_INEXACT;
} else {
- c |= FP_INEXACT;
+ mips_exception_flags |= FP_INEXACT;
}
}
/* Set Inexact (I) and Underflow (U) when flushing outputs to zero */
- if ((ieee_ex & float_flag_output_denormal) &&
+ if ((ieee_exception_flags & float_flag_output_denormal) &&
(env->active_tc.msacsr & MSACSR_FS_MASK) != 0) {
- c |= FP_INEXACT;
+ mips_exception_flags |= FP_INEXACT;
if (action & CLEAR_FS_UNDERFLOW) {
- c &= ~FP_UNDERFLOW;
+ mips_exception_flags &= ~FP_UNDERFLOW;
} else {
- c |= FP_UNDERFLOW;
+ mips_exception_flags |= FP_UNDERFLOW;
}
}
/* Set Inexact (I) when Overflow (O) is not enabled */
- if ((c & FP_OVERFLOW) != 0 && (enable & FP_OVERFLOW) == 0) {
- c |= FP_INEXACT;
+ if ((mips_exception_flags & FP_OVERFLOW) != 0 &&
+ (enable & FP_OVERFLOW) == 0) {
+ mips_exception_flags |= FP_INEXACT;
}
/* Clear Exact Underflow when Underflow (U) is not enabled */
- if ((c & FP_UNDERFLOW) != 0 && (enable & FP_UNDERFLOW) == 0 &&
- (c & FP_INEXACT) == 0) {
- c &= ~FP_UNDERFLOW;
+ if ((mips_exception_flags & FP_UNDERFLOW) != 0 &&
+ (enable & FP_UNDERFLOW) == 0 &&
+ (mips_exception_flags & FP_INEXACT) == 0) {
+ mips_exception_flags &= ~FP_UNDERFLOW;
}
/*
@@ -5474,11 +5501,11 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal)
* divide by zero
*/
if ((action & RECIPROCAL_INEXACT) &&
- (c & (FP_INVALID | FP_DIV0)) == 0) {
- c = FP_INEXACT;
+ (mips_exception_flags & (FP_INVALID | FP_DIV0)) == 0) {
+ mips_exception_flags = FP_INEXACT;
}
- cause = c & enable; /* all current enabled exceptions */
+ cause = mips_exception_flags & enable; /* all current enabled exceptions */
if (cause == 0) {
/*
@@ -5486,7 +5513,7 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal)
* with all current exceptions
*/
SET_FP_CAUSE(env->active_tc.msacsr,
- (GET_FP_CAUSE(env->active_tc.msacsr) | c));
+ (GET_FP_CAUSE(env->active_tc.msacsr) | mips_exception_flags));
} else {
/* Current exceptions are enabled */
if ((env->active_tc.msacsr & MSACSR_NX_MASK) == 0) {
@@ -5495,11 +5522,11 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal)
* with all enabled exceptions
*/
SET_FP_CAUSE(env->active_tc.msacsr,
- (GET_FP_CAUSE(env->active_tc.msacsr) | c));
+ (GET_FP_CAUSE(env->active_tc.msacsr) | mips_exception_flags));
}
}
- return c;
+ return mips_exception_flags;
}
static inline int get_enabled_exceptions(const CPUMIPSState *env, int c)
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 25b595a17d..2caf4cba5a 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -31206,7 +31206,9 @@ void cpu_state_reset(CPUMIPSState *env)
env->CP0_Config5 = env->cpu_model->CP0_Config5;
env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
env->CP0_Config6 = env->cpu_model->CP0_Config6;
+ env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
env->CP0_Config7 = env->cpu_model->CP0_Config7;
+ env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
<< env->cpu_model->CP0_LLAddr_shift;
env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
diff --git a/target/mips/translate_init.inc.c b/target/mips/translate_init.inc.c
index 6d145a905a..637caccd89 100644
--- a/target/mips/translate_init.inc.c
+++ b/target/mips/translate_init.inc.c
@@ -366,7 +366,7 @@ const mips_def_t mips_defs[] =
},
{
/* FIXME:
- * Config3: CMGCR, PW, VZ, CTXTC, CDMM, TL
+ * Config3: VZ, CTXTC, CDMM, TL
* Config4: MMUExtDef
* Config5: MRP
* FIR(FCR0): Has2008
@@ -380,10 +380,11 @@ const mips_def_t mips_defs[] =
(2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_FP),
.CP0_Config2 = MIPS_CONFIG2,
- .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) |
+ .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) |
+ (1 << CP0C3_CMGCR) | (1 << CP0C3_MSAP) |
(1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_SC) |
- (1 << CP0C3_ULRI) | (1 << CP0C3_RXI) | (1 << CP0C3_LPA) |
- (1 << CP0C3_VInt),
+ (1 << CP0C3_PW) | (1 << CP0C3_ULRI) | (1 << CP0C3_RXI) |
+ (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) |
(0x1c << CP0C4_KScrExist),
.CP0_Config4_rw_bitmask = 0,
@@ -802,6 +803,92 @@ const mips_def_t mips_defs[] =
.mmu_type = MMU_TYPE_R4000,
},
{
+ .name = "Loongson-3A1000",
+ .CP0_PRid = 0x6305,
+ /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */
+ .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
+ (MMU_TYPE_R4000 << CP0C0_MT),
+ .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
+ (3 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
+ (3 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
+ (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+ .CP0_Config2 = MIPS_CONFIG2 | (7 << CP0C2_SS) | (4 << CP0C2_SL) |
+ (3 << CP0C2_SA),
+ .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA),
+ .CP0_LLAddr_rw_bitmask = 0,
+ .SYNCI_Step = 32,
+ .CCRes = 2,
+ .CP0_Status_rw_bitmask = 0x74D8FFFF,
+ .CP0_PageGrain = (1 << CP0PG_ELPA),
+ .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
+ .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) |
+ (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) |
+ (0x1 << FCR0_D) | (0x1 << FCR0_S),
+ .CP1_fcr31 = 0,
+ .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+ .SEGBITS = 42,
+ .PABITS = 48,
+ .insn_flags = CPU_LOONGSON3A,
+ .mmu_type = MMU_TYPE_R4000,
+ },
+ {
+ .name = "Loongson-3A4000",
+ .CP0_PRid = 0x14C000,
+ /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */
+ .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
+ (MMU_TYPE_R4000 << CP0C0_MT),
+ .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
+ (2 << CP0C1_IS) | (5 << CP0C1_IL) | (3 << CP0C1_IA) |
+ (2 << CP0C1_DS) | (5 << CP0C1_DL) | (3 << CP0C1_DA) |
+ (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+ .CP0_Config2 = MIPS_CONFIG2 | (5 << CP0C2_SS) | (5 << CP0C2_SL) |
+ (15 << CP0C2_SA),
+ .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) |
+ (1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) |
+ (1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
+ .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) |
+ (1 << CP0C4_AE) | (0x1c << CP0C4_KScrExist),
+ .CP0_Config4_rw_bitmask = 0,
+ .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_NFExists),
+ .CP0_Config5_rw_bitmask = (1 << CP0C5_K) | (1 << CP0C5_CV) |
+ (1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) |
+ (1 << CP0C5_FRE) | (1 << CP0C5_SBRI),
+ .CP0_Config6 = (1 << CP0C6_VCLRU) | (1 << CP0C6_DCLRU) |
+ (1 << CP0C6_SFBEN) | (1 << CP0C6_VLTINT) |
+ (1 << CP0C6_INSTPREF) | (1 << CP0C6_DATAPREF),
+ .CP0_Config6_rw_bitmask = (1 << CP0C6_BPPASS) | (0x3f << CP0C6_KPOS) |
+ (1 << CP0C6_KE) | (1 << CP0C6_VTLBONLY) |
+ (1 << CP0C6_LASX) | (1 << CP0C6_SSEN) |
+ (1 << CP0C6_DISDRTIME) | (1 << CP0C6_PIXNUEN) |
+ (1 << CP0C6_SCRAND) | (1 << CP0C6_LLEXCEN) |
+ (1 << CP0C6_DISVC) | (1 << CP0C6_VCLRU) |
+ (1 << CP0C6_DCLRU) | (1 << CP0C6_PIXUEN) |
+ (1 << CP0C6_DISBLKLYEN) | (1 << CP0C6_UMEMUALEN) |
+ (1 << CP0C6_SFBEN) | (1 << CP0C6_FLTINT) |
+ (1 << CP0C6_VLTINT) | (1 << CP0C6_DISBTB) |
+ (3 << CP0C6_STPREFCTL) | (1 << CP0C6_INSTPREF) |
+ (1 << CP0C6_DATAPREF),
+ .CP0_Config7 = 0,
+ .CP0_Config7_rw_bitmask = (1 << CP0C7_NAPCGEN) | (1 << CP0C7_UNIMUEN) |
+ (1 << CP0C7_VFPUCGEN),
+ .CP0_LLAddr_rw_bitmask = 1,
+ .SYNCI_Step = 16,
+ .CCRes = 2,
+ .CP0_Status_rw_bitmask = 0x7DDBFFFF,
+ .CP0_PageGrain = (1 << CP0PG_ELPA),
+ .CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) |
+ (1 << CP0PG_ELPA) | (1 << CP0PG_IEC),
+ .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) |
+ (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) |
+ (0x1 << FCR0_D) | (0x1 << FCR0_S),
+ .CP1_fcr31 = 0,
+ .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+ .SEGBITS = 48,
+ .PABITS = 48,
+ .insn_flags = CPU_LOONGSON3A,
+ .mmu_type = MMU_TYPE_R4000,
+ },
+ {
/* A generic CPU providing MIPS64 DSP R2 ASE features.
FIXME: Eventually this should be replaced by a real CPU model. */
.name = "mips64dspr2",
diff --git a/tests/decode/err_pattern_group_nest1.decode b/tests/decode/err_pattern_group_nest1.decode
index 92e971c3c5..7d09891a1c 100644
--- a/tests/decode/err_pattern_group_nest1.decode
+++ b/tests/decode/err_pattern_group_nest1.decode
@@ -3,11 +3,12 @@
%sub1 0:8
%sub2 8:8
-%sub3 16:8
-%sub4 24:8
-# Groups with no overlap are supposed to fail
+# Make sure braces are matched
{
- top 00000000 00000000 00000000 00000000
- sub4 ........ ........ ........ ........ %sub1 %sub2 %sub3 %sub4
+ top 00000000 00000000 00000000 00000000
+ [
+ sub1 00000000 00000000 00000000 ........ %sub1
+ sub2 00000000 00000000 ........ ........ %sub1 %sub2
+ }
}
diff --git a/tests/decode/err_pattern_group_nest2.decode b/tests/decode/err_pattern_group_nest2.decode
new file mode 100644
index 0000000000..c172239e9b
--- /dev/null
+++ b/tests/decode/err_pattern_group_nest2.decode
@@ -0,0 +1,6 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+# Make sure braces are matched
+{
+ [
diff --git a/tests/decode/err_pattern_group_nest3.decode b/tests/decode/err_pattern_group_nest3.decode
new file mode 100644
index 0000000000..b085d01410
--- /dev/null
+++ b/tests/decode/err_pattern_group_nest3.decode
@@ -0,0 +1,14 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+%sub1 0:8
+%sub2 8:8
+
+# The exclusive group should error for overlap.
+{
+ top 00000000 00000000 00000000 00000000
+ [
+ sub1 00000000 00000000 00000000 ........ %sub1
+ sub2 00000000 00000000 ........ ........ %sub1 %sub2
+ ]
+}
diff --git a/tests/decode/succ_pattern_group_nest2.decode b/tests/decode/succ_pattern_group_nest2.decode
new file mode 100644
index 0000000000..8d5ab4b2d3
--- /dev/null
+++ b/tests/decode/succ_pattern_group_nest2.decode
@@ -0,0 +1,13 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+%sub1 0:8
+%sub2 8:8
+%sub3 16:8
+%sub4 24:8
+
+# Group with complete overlap of the two patterns
+{
+ top 00000000 00000000 00000000 00000000
+ sub4 ........ ........ ........ ........ %sub1 %sub2 %sub3 %sub4
+}
diff --git a/tests/decode/succ_pattern_group_nest3.decode b/tests/decode/succ_pattern_group_nest3.decode
new file mode 100644
index 0000000000..156249f090
--- /dev/null
+++ b/tests/decode/succ_pattern_group_nest3.decode
@@ -0,0 +1,11 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+{
+ [
+ sub1 00000000 a:8 b:8 c:8
+ sub2 00000001 a:8 b:8 c:8
+ sub3 00000010 a:8 b:8 c:8
+ ]
+ sub4 000000 d:2 a:8 b:8 c:8
+}
diff --git a/tests/decode/succ_pattern_group_nest4.decode b/tests/decode/succ_pattern_group_nest4.decode
new file mode 100644
index 0000000000..dc54a1d285
--- /dev/null
+++ b/tests/decode/succ_pattern_group_nest4.decode
@@ -0,0 +1,13 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+# Verify deeper nesting, and a single element in the groups.
+{
+ [
+ {
+ [
+ sub1 00000000 a:8 b:8 c:8
+ ]
+ }
+ ]
+}
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index ed46bd98eb..981b7fcf2a 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -130,7 +130,7 @@ docker-image-debian-sparc64-cross: docker-image-debian10
docker-image-travis: NOUSER=1
# Specialist build images, sometimes very limited tools
-docker-image-tricore-cross: docker-image-debian9
+docker-image-debian-tricore-cross: docker-image-debian9
docker-image-debian-arm64-test-cross: docker-image-debian11
# These images may be good enough for building tests but not for test builds
diff --git a/tests/docker/dockerfiles/centos7.docker b/tests/docker/dockerfiles/centos7.docker
index 9a2a2e515d..e197acdc3c 100644
--- a/tests/docker/dockerfiles/centos7.docker
+++ b/tests/docker/dockerfiles/centos7.docker
@@ -5,13 +5,11 @@ RUN yum -y update
# Please keep this list sorted alphabetically
ENV PACKAGES \
- bison \
bzip2 \
bzip2-devel \
ccache \
csnappy-devel \
dbus-daemon \
- flex \
gcc-c++ \
gcc \
gettext \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index bfa0d33c9c..9852c5b9ee 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -3,11 +3,9 @@ FROM centos:8.1.1911
RUN dnf -y update
ENV PACKAGES \
SDL-devel \
- bison \
bzip2 \
bzip2-devel \
dbus-daemon \
- flex \
gcc \
gcc-c++ \
gettext \
diff --git a/tests/docker/dockerfiles/debian-xtensa-cross.docker b/tests/docker/dockerfiles/debian-xtensa-cross.docker
index e6f93f65ee..beb73f46ba 100644
--- a/tests/docker/dockerfiles/debian-xtensa-cross.docker
+++ b/tests/docker/dockerfiles/debian-xtensa-cross.docker
@@ -11,11 +11,9 @@ RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt-get install -y --no-install-recommends \
- bison \
build-essential \
ca-certificates \
curl \
- flex \
gettext \
git \
python3-minimal
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index 0769700a41..bcdff04ddf 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -18,12 +18,10 @@ RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
bc \
- bison \
build-essential \
ca-certificates \
clang \
dbus \
- flex \
gdb-multiarch \
gettext \
git \
diff --git a/tests/docker/dockerfiles/debian9.docker b/tests/docker/dockerfiles/debian9.docker
index 08cc970feb..0f0ebe530a 100644
--- a/tests/docker/dockerfiles/debian9.docker
+++ b/tests/docker/dockerfiles/debian9.docker
@@ -18,11 +18,9 @@ RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
bc \
- bison \
build-essential \
ca-certificates \
clang \
- flex \
gdb-multiarch \
gettext \
git \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 179575ecaa..92b6e11c8a 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -3,7 +3,6 @@ FROM fedora:30
# Please keep this list sorted alphabetically
ENV PACKAGES \
bc \
- bison \
brlapi-devel \
bzip2 \
bzip2-devel \
@@ -13,7 +12,6 @@ ENV PACKAGES \
dbus-daemon \
device-mapper-multipath-devel \
findutils \
- flex \
gcc \
gcc-c++ \
gettext \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index eeb3b22bf2..161806e6b8 100644
--- a/tests/docker/dockerfiles/ubuntu.docker
+++ b/tests/docker/dockerfiles/ubuntu.docker
@@ -9,8 +9,8 @@
# system won't pick up that it has changed.
#
-FROM ubuntu:19.04
-ENV PACKAGES flex bison \
+FROM ubuntu:20.04
+ENV PACKAGES \
ccache \
clang \
dbus \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index f66b06f4cf..a10ea2850b 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -1,5 +1,5 @@
FROM ubuntu:18.04
-ENV PACKAGES flex bison \
+ENV PACKAGES \
ccache \
clang \
gcc \
diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c
index 878abf09d1..4725bd851d 100644
--- a/tests/plugin/mem.c
+++ b/tests/plugin/mem.c
@@ -28,7 +28,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
g_string_printf(out, "mem accesses: %" PRIu64 "\n", mem_count);
if (do_haddr) {
- g_string_append_printf(out, "io accesses: %" PRIu64 "\n", mem_count);
+ g_string_append_printf(out, "io accesses: %" PRIu64 "\n", io_count);
}
qemu_plugin_outs(out->str);
}
diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target
index 11c39c601e..3da09a38be 100644
--- a/tests/tcg/arm/Makefile.target
+++ b/tests/tcg/arm/Makefile.target
@@ -68,6 +68,8 @@ run-semiconsole-arm: semiconsole-arm
run-plugin-semiconsole-arm-with-%:
$(call skip-test, $<, "MANUAL ONLY")
+ARM_TESTS += commpage
+
TESTS += $(ARM_TESTS)
# On ARM Linux only supports 4k pages
diff --git a/tests/tcg/arm/commpage.c b/tests/tcg/arm/commpage.c
new file mode 100644
index 0000000000..c76e70cb8b
--- /dev/null
+++ b/tests/tcg/arm/commpage.c
@@ -0,0 +1,61 @@
+/*
+ * Verify the COMMPAGE emulation
+ *
+ * The ARM commpage is a set of user space helper functions provided
+ * by the kernel in an effort to ease portability of user space code
+ * between different CPUs with potentially different capabilities. It
+ * is a 32 bit invention and similar to the vdso segment in many ways.
+ *
+ * The ABI is documented in the Linux kernel:
+ * Documentation/arm/kernel_userspace_helpers.rst
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#define ARM_COMMPAGE (0xffff0f00u)
+#define ARM_KUSER_VERSION (*(int32_t *)(ARM_COMMPAGE + 0xfc))
+typedef void * (get_tls_fn)(void);
+#define ARM_KUSER_GET_TLS (*(get_tls_fn *)(ARM_COMMPAGE + 0xe0))
+typedef int (cmpxchg_fn)(int oldval, int newval, volatile int *ptr);
+#define ARM_KUSER_CMPXCHG (*(cmpxchg_fn *)(ARM_COMMPAGE + 0xc0))
+typedef void (dmb_fn)(void);
+#define ARM_KUSER_DMB (*(dmb_fn *)(ARM_COMMPAGE + 0xa0))
+typedef int (cmpxchg64_fn)(const int64_t *oldval,
+ const int64_t *newval,
+ volatile int64_t *ptr);
+#define ARM_KUSER_CMPXCHG64 (*(cmpxchg64_fn *)(ARM_COMMPAGE + 0x60))
+
+#define fail_unless(x) \
+ do { \
+ if (!(x)) { \
+ fprintf(stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \
+ exit(EXIT_FAILURE); \
+ } \
+ } while (0)
+
+
+int main(int argc, char *argv[argc])
+{
+ void *kuser_tls;
+ int val = 1;
+ const int64_t oldval = 1, newval = 2;
+ int64_t val64 = 1;
+
+ fail_unless(ARM_KUSER_VERSION == 0x5);
+ kuser_tls = ARM_KUSER_GET_TLS();
+ printf("TLS = %p\n", kuser_tls);
+ fail_unless(kuser_tls != 0);
+ fail_unless(ARM_KUSER_CMPXCHG(1, 2, &val) == 0);
+ printf("val = %d\n", val);
+ /* this is a crash test, not checking an actual barrier occurs */
+ ARM_KUSER_DMB();
+ fail_unless(ARM_KUSER_CMPXCHG64(&oldval, &newval, &val64) == 0);
+ printf("val64 = %lld\n", val64);
+ return 0;
+}
diff --git a/tests/vm/fedora b/tests/vm/fedora
index bd9c6cf295..a9195670f4 100755
--- a/tests/vm/fedora
+++ b/tests/vm/fedora
@@ -32,7 +32,6 @@ class FedoraVM(basevm.BaseVM):
pkgs = [
# tools
'git-core',
- 'flex', 'bison',
'gcc', 'binutils', 'make',
# perl
diff --git a/tests/vm/freebsd b/tests/vm/freebsd
index 298967fe9c..f87db2b126 100755
--- a/tests/vm/freebsd
+++ b/tests/vm/freebsd
@@ -38,7 +38,6 @@ class FreeBSDVM(basevm.BaseVM):
"bash",
"gmake",
"gsed",
- "flex", "bison",
# libs: crypto
"gnutls",
diff --git a/tests/vm/netbsd b/tests/vm/netbsd
index b10c9d429d..cdac502dad 100755
--- a/tests/vm/netbsd
+++ b/tests/vm/netbsd
@@ -36,7 +36,6 @@ class NetBSDVM(basevm.BaseVM):
"bash",
"gmake",
"gsed",
- "flex", "bison",
# libs: crypto
"gnutls",
diff --git a/tests/vm/openbsd b/tests/vm/openbsd
index 0b705f4945..13e7f9a6d5 100755
--- a/tests/vm/openbsd
+++ b/tests/vm/openbsd
@@ -35,7 +35,6 @@ class OpenBSDVM(basevm.BaseVM):
"bash",
"gmake",
"gsed",
- "bison",
# libs: usb
"libusb1",
diff --git a/tests/vm/ubuntu.i386 b/tests/vm/ubuntu.i386
index 1570775335..24527cc78c 100755
--- a/tests/vm/ubuntu.i386
+++ b/tests/vm/ubuntu.i386
@@ -52,7 +52,7 @@ class UbuntuX86VM(basevm.BaseVM):
self.ssh_root_check("sed -ie s/^#\ deb-src/deb-src/g /etc/apt/sources.list")
self.ssh_root_check("apt-get update")
self.ssh_root_check("apt-get build-dep -y qemu")
- self.ssh_root_check("apt-get install -y libfdt-dev flex bison language-pack-en")
+ self.ssh_root_check("apt-get install -y libfdt-dev language-pack-en")
self.ssh_root("poweroff")
self.wait()
os.rename(img_tmp, img)