summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile12
-rwxr-xr-xtests/check-block.sh21
-rwxr-xr-xtests/qemu-iotests-quick.sh17
-rwxr-xr-xtests/qemu-iotests/0266
-rwxr-xr-xtests/qemu-iotests/0285
-rw-r--r--tests/qemu-iotests/028.out1
-rwxr-xr-xtests/qemu-iotests/030151
-rw-r--r--tests/qemu-iotests/030.out5
-rwxr-xr-xtests/qemu-iotests/check4
-rw-r--r--tests/qemu-iotests/common.config2
-rw-r--r--tests/qemu-iotests/common.filter8
-rw-r--r--tests/qemu-iotests/group25
-rw-r--r--tests/qemu-iotests/iotests.py164
-rw-r--r--tests/tcg/xtensa/Makefile1
-rw-r--r--tests/tcg/xtensa/test_break.S223
15 files changed, 629 insertions, 16 deletions
diff --git a/tests/Makefile b/tests/Makefile
index 74b29dc076..c78ade122e 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,6 +1,9 @@
+export SRC_PATH
+
 CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
 CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
 CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
+CHECKS += $(SRC_PATH)/tests/qemu-iotests-quick.sh
 
 check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
 
@@ -42,6 +45,13 @@ test-qmp-input-visitor: test-qmp-input-visitor.o $(qobject-obj-y) $(qapi-obj-y)
 test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
 test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
 
-.PHONY: check
+$(SRC_PATH)/tests/qemu-iotests-quick.sh: qemu-img qemu-io
+
+
+.PHONY: check check-block
+
 check: $(CHECKS)
 	$(call quiet-command, gtester $(CHECKS), "  CHECK")
+
+check-block:
+	$(call quiet-command, $(SHELL) $(SRC_PATH)/tests/check-block.sh , "  CHECK")
diff --git a/tests/check-block.sh b/tests/check-block.sh
new file mode 100755
index 0000000000..b9d9c6a9f6
--- /dev/null
+++ b/tests/check-block.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+export QEMU_PROG="$(pwd)/x86_64-softmmu/qemu-system-x86_64"
+export QEMU_IMG_PROG="$(pwd)/qemu-img"
+export QEMU_IO_PROG="$(pwd)/qemu-io"
+
+if [ ! -x $QEMU_PROG ]; then
+    echo "'make check-block' requires qemu-system-x86_64"
+    exit 1
+fi
+
+cd $SRC_PATH/tests/qemu-iotests
+
+ret=0
+./check -T -nocache -raw || ret=1
+./check -T -nocache -qcow2 || ret=1
+./check -T -nocache -qed|| ret=1
+./check -T -nocache -vmdk|| ret=1
+./check -T -nocache -vpc || ret=1
+
+exit $ret
diff --git a/tests/qemu-iotests-quick.sh b/tests/qemu-iotests-quick.sh
new file mode 100755
index 0000000000..cf90de0b8b
--- /dev/null
+++ b/tests/qemu-iotests-quick.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# We don't know which of the system emulator binaries there is (or if there is
+# any at all), so the 'quick' group doesn't contain any tests that require
+# running qemu proper. Assign a fake binary name so that qemu-iotests doesn't
+# complain about the missing binary.
+export QEMU_PROG="this_should_be_unused"
+
+export QEMU_IMG_PROG="$(pwd)/qemu-img"
+export QEMU_IO_PROG="$(pwd)/qemu-io"
+
+cd $SRC_PATH/tests/qemu-iotests
+
+ret=0
+./check -T -nocache -qcow2 -g quick || ret=1
+
+exit $ret
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index 33e7da6abe..1602ccd2a5 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -87,6 +87,12 @@ _make_test_img 1G
 
 echo
 echo "Event: $event; errno: $errno; imm: $imm; once: $once; write $vmstate"
+
+# We want to catch a simple L2 update, not the allocation of the first L2 table
+if [ "$event" == "l2_update" ]; then
+    $QEMU_IO -c "write $vmstate 0 512" $TEST_IMG > /dev/null 2>&1
+fi
+
 $QEMU_IO -c "write $vmstate 0 128k " $BLKDBG_TEST_IMG | _filter_qemu_io
 
 # l2_load is not called on allocation, so issue a second write
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
index 07c5bb6975..b091ba9f07 100755
--- a/tests/qemu-iotests/028
+++ b/tests/qemu-iotests/028
@@ -96,6 +96,11 @@ io_zero readv $(( offset + 32 * 1024 )) 512 1024 32
 
 _check_test_img
 
+# Rebase it on top of its base image
+$QEMU_IMG rebase -b $TEST_IMG.base $TEST_IMG
+
+_check_test_img
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out
index f4290298c8..fe007887e3 100644
--- a/tests/qemu-iotests/028.out
+++ b/tests/qemu-iotests/028.out
@@ -465,4 +465,5 @@ qemu-io> read 512/512 bytes at offset 3221257728
 qemu-io> read 512/512 bytes at offset 3221258752
 512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 qemu-io> No errors were found on the image.
+No errors were found on the image.
 *** done
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
new file mode 100755
index 0000000000..1faf984200
--- /dev/null
+++ b/tests/qemu-iotests/030
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+#
+# Tests for image streaming.
+#
+# Copyright (C) 2012 IBM Corp.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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/>.
+#
+
+import os
+import iotests
+from iotests import qemu_img, qemu_io
+
+backing_img = os.path.join(iotests.test_dir, 'backing.img')
+test_img = os.path.join(iotests.test_dir, 'test.img')
+
+class ImageStreamingTestCase(iotests.QMPTestCase):
+    '''Abstract base class for image streaming test cases'''
+
+    def assert_no_active_streams(self):
+        result = self.vm.qmp('query-block-jobs')
+        self.assert_qmp(result, 'return', [])
+
+class TestSingleDrive(ImageStreamingTestCase):
+    image_len = 1 * 1024 * 1024 # MB
+
+    def setUp(self):
+        qemu_img('create', backing_img, str(TestSingleDrive.image_len))
+        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
+        self.vm = iotests.VM().add_drive(test_img)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(test_img)
+        os.remove(backing_img)
+
+    def test_stream(self):
+        self.assert_no_active_streams()
+
+        result = self.vm.qmp('block_stream', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        completed = False
+        while not completed:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_COMPLETED':
+                    self.assert_qmp(event, 'data/type', 'stream')
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp(event, 'data/offset', self.image_len)
+                    self.assert_qmp(event, 'data/len', self.image_len)
+                    completed = True
+
+        self.assert_no_active_streams()
+
+        self.assertFalse('sectors not allocated' in qemu_io('-c', 'map', test_img),
+                         'image file not fully populated after streaming')
+
+    def test_device_not_found(self):
+        result = self.vm.qmp('block_stream', device='nonexistent')
+        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
+
+class TestStreamStop(ImageStreamingTestCase):
+    image_len = 8 * 1024 * 1024 * 1024 # GB
+
+    def setUp(self):
+        qemu_img('create', backing_img, str(TestStreamStop.image_len))
+        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
+        self.vm = iotests.VM().add_drive(test_img)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(test_img)
+        os.remove(backing_img)
+
+    def test_stream_stop(self):
+        import time
+
+        self.assert_no_active_streams()
+
+        result = self.vm.qmp('block_stream', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        time.sleep(1)
+        events = self.vm.get_qmp_events(wait=False)
+        self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
+
+        self.vm.qmp('block_job_cancel', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        cancelled = False
+        while not cancelled:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_CANCELLED':
+                    self.assert_qmp(event, 'data/type', 'stream')
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    cancelled = True
+
+        self.assert_no_active_streams()
+
+# This is a short performance test which is not run by default.
+# Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_set_speed"
+class TestSetSpeed(ImageStreamingTestCase):
+    image_len = 80 * 1024 * 1024 # MB
+
+    def setUp(self):
+        qemu_img('create', backing_img, str(TestSetSpeed.image_len))
+        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
+        self.vm = iotests.VM().add_drive(test_img)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(test_img)
+        os.remove(backing_img)
+
+    def perf_test_set_speed(self):
+        self.assert_no_active_streams()
+
+        result = self.vm.qmp('block_stream', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('block_job_set_speed', device='drive0', value=8 * 1024 * 1024)
+        self.assert_qmp(result, 'return', {})
+
+        completed = False
+        while not completed:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_COMPLETED':
+                    self.assert_qmp(event, 'data/type', 'stream')
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp(event, 'data/offset', self.image_len)
+                    self.assert_qmp(event, 'data/len', self.image_len)
+                    completed = True
+
+        self.assert_no_active_streams()
+
+if __name__ == '__main__':
+    iotests.main(supported_fmts=['qcow2', 'qed'])
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
new file mode 100644
index 0000000000..8d7e996700
--- /dev/null
+++ b/tests/qemu-iotests/030.out
@@ -0,0 +1,5 @@
+...
+----------------------------------------------------------------------
+Ran 3 tests
+
+OK
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 8499a04d3e..aae1378998 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -243,7 +243,7 @@ do
 		echo " - no qualified output"
 		err=true
 	    else
-		if diff $seq.out $tmp.out >/dev/null 2>&1
+		if diff -w $seq.out $tmp.out >/dev/null 2>&1
 		then
 		    echo ""
 		    if $err
@@ -255,7 +255,7 @@ do
 		else
 		    echo " - output mismatch (see $seq.out.bad)"
 		    mv $tmp.out $seq.out.bad
-		    $diff $seq.out $seq.out.bad
+		    $diff -w $seq.out $seq.out.bad
 		    err=true
 		fi
 	    fi
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
index d07f435696..a220684b0f 100644
--- a/tests/qemu-iotests/common.config
+++ b/tests/qemu-iotests/common.config
@@ -121,6 +121,8 @@ if [ ! -d "$TEST_DIR" ]; then
     exit 1
 fi
 
+export TEST_DIR
+
 _readlink()
 {
     if [ $# -ne 1 ]; then
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index da77ede25f..fa26b62dd3 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -140,10 +140,16 @@ _filter_imgfmt()
     sed -e "s#$IMGFMT#IMGFMT#g"
 }
 
+# Removes \r from messages
+_filter_win32()
+{
+    sed -e 's/\r//g'
+}
+
 # sanitize qemu-io output
 _filter_qemu_io()
 {
-    sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/"
+    _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/"
 }
 
 # make sure this script returns success
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 0a5c866014..b549f10f17 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -8,31 +8,32 @@
 # test-group association ... one line per test
 #
 001 rw auto
-002 rw auto
+002 rw auto quick
 003 rw auto
-004 rw auto
+004 rw auto quick
 005 img auto
 006 img auto
 007 snapshot auto
 008 rw auto
 009 rw auto
 010 rw auto
-011 rw auto
-012 auto
+011 rw auto quick
+012 auto quick
 013 rw auto
 014 rw auto
 015 rw snapshot auto
-016 rw auto
-017 rw backing auto
+016 rw auto quick
+017 rw backing auto quick
 018 rw backing auto
-019 rw backing auto
-020 rw backing auto
+019 rw backing auto quick
+020 rw backing auto quick
 021 io auto
 022 rw snapshot auto
 023 rw auto
-024 rw backing auto
-025 rw auto
+024 rw backing auto quick
+025 rw auto quick
 026 rw blkdbg auto
-027 rw auto
+027 rw auto quick
 028 rw backing auto
-029 rw auto
+029 rw auto quick
+030 rw auto
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
new file mode 100644
index 0000000000..ec1a86a632
--- /dev/null
+++ b/tests/qemu-iotests/iotests.py
@@ -0,0 +1,164 @@
+# Common utilities and Python wrappers for qemu-iotests
+#
+# Copyright (C) 2012 IBM Corp.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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/>.
+#
+
+import os
+import re
+import subprocess
+import unittest
+import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'QMP'))
+import qmp
+
+__all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io',
+           'VM', 'QMPTestCase', 'notrun', 'main']
+
+# This will not work if arguments or path contain spaces but is necessary if we
+# want to support the override options that ./check supports.
+qemu_img_args = os.environ.get('QEMU_IMG', 'qemu-img').split(' ')
+qemu_io_args = os.environ.get('QEMU_IO', 'qemu-io').split(' ')
+qemu_args = os.environ.get('QEMU', 'qemu').split(' ')
+
+imgfmt = os.environ.get('IMGFMT', 'raw')
+imgproto = os.environ.get('IMGPROTO', 'file')
+test_dir = os.environ.get('TEST_DIR', '/var/tmp')
+
+def qemu_img(*args):
+    '''Run qemu-img and return the exit code'''
+    devnull = open('/dev/null', 'r+')
+    return subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull)
+
+def qemu_io(*args):
+    '''Run qemu-io and return the stdout data'''
+    args = qemu_io_args + list(args)
+    return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
+
+class VM(object):
+    '''A QEMU VM'''
+
+    def __init__(self):
+        self._monitor_path = os.path.join(test_dir, 'qemu-mon.%d' % os.getpid())
+        self._qemu_log_path = os.path.join(test_dir, 'qemu-log.%d' % os.getpid())
+        self._args = qemu_args + ['-chardev',
+                     'socket,id=mon,path=' + self._monitor_path,
+                     '-mon', 'chardev=mon,mode=control', '-nographic']
+        self._num_drives = 0
+
+    def add_drive(self, path, opts=''):
+        '''Add a virtio-blk drive to the VM'''
+        options = ['if=virtio',
+                   'format=%s' % imgfmt,
+                   'cache=none',
+                   'file=%s' % path,
+                   'id=drive%d' % self._num_drives]
+        if opts:
+            options.append(opts)
+
+        self._args.append('-drive')
+        self._args.append(','.join(options))
+        self._num_drives += 1
+        return self
+
+    def launch(self):
+        '''Launch the VM and establish a QMP connection'''
+        devnull = open('/dev/null', 'rb')
+        qemulog = open(self._qemu_log_path, 'wb')
+        try:
+            self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True)
+            self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog,
+                                           stderr=subprocess.STDOUT)
+            self._qmp.accept()
+        except:
+            os.remove(self._monitor_path)
+            raise
+
+    def shutdown(self):
+        '''Terminate the VM and clean up'''
+        self._qmp.cmd('quit')
+        self._popen.wait()
+        os.remove(self._monitor_path)
+        os.remove(self._qemu_log_path)
+
+    def qmp(self, cmd, **args):
+        '''Invoke a QMP command and return the result dict'''
+        return self._qmp.cmd(cmd, args=args)
+
+    def get_qmp_events(self, wait=False):
+        '''Poll for queued QMP events and return a list of dicts'''
+        events = self._qmp.get_events(wait=wait)
+        self._qmp.clear_events()
+        return events
+
+index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
+
+class QMPTestCase(unittest.TestCase):
+    '''Abstract base class for QMP test cases'''
+
+    def dictpath(self, d, path):
+        '''Traverse a path in a nested dict'''
+        for component in path.split('/'):
+            m = index_re.match(component)
+            if m:
+                component, idx = m.groups()
+                idx = int(idx)
+
+            if not isinstance(d, dict) or component not in d:
+                self.fail('failed path traversal for "%s" in "%s"' % (path, str(d)))
+            d = d[component]
+
+            if m:
+                if not isinstance(d, list):
+                    self.fail('path component "%s" in "%s" is not a list in "%s"' % (component, path, str(d)))
+                try:
+                    d = d[idx]
+                except IndexError:
+                    self.fail('invalid index "%s" in path "%s" in "%s"' % (idx, path, str(d)))
+        return d
+
+    def assert_qmp(self, d, path, value):
+        '''Assert that the value for a specific path in a QMP dict matches'''
+        result = self.dictpath(d, path)
+        self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value)))
+
+def notrun(reason):
+    '''Skip this test suite'''
+    # Each test in qemu-iotests has a number ("seq")
+    seq = os.path.basename(sys.argv[0])
+
+    open('%s.notrun' % seq, 'wb').write(reason + '\n')
+    print '%s not run: %s' % (seq, reason)
+    sys.exit(0)
+
+def main(supported_fmts=[]):
+    '''Run tests'''
+
+    if supported_fmts and (imgfmt not in supported_fmts):
+        notrun('not suitable for this image format: %s' % imgfmt)
+
+    # We need to filter out the time taken from the output so that qemu-iotest
+    # can reliably diff the results against master output.
+    import StringIO
+    output = StringIO.StringIO()
+
+    class MyTestRunner(unittest.TextTestRunner):
+        def __init__(self, stream=output, descriptions=True, verbosity=1):
+            unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity)
+
+    # unittest.main() will use sys.exit() so expect a SystemExit exception
+    try:
+        unittest.main(testRunner=MyTestRunner)
+    finally:
+        sys.stderr.write(re.sub(r'Ran (\d+) test[s] in [\d.]+s', r'Ran \1 tests', output.getvalue()))
diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile
index 8713af16eb..7e1e619d23 100644
--- a/tests/tcg/xtensa/Makefile
+++ b/tests/tcg/xtensa/Makefile
@@ -23,6 +23,7 @@ CRT        = crt.o vectors.o
 TESTCASES += test_b.tst
 TESTCASES += test_bi.tst
 #TESTCASES += test_boolean.tst
+TESTCASES += test_break.tst
 TESTCASES += test_bz.tst
 TESTCASES += test_clamps.tst
 TESTCASES += test_fail.tst
diff --git a/tests/tcg/xtensa/test_break.S b/tests/tcg/xtensa/test_break.S
new file mode 100644
index 0000000000..8a8db8033b
--- /dev/null
+++ b/tests/tcg/xtensa/test_break.S
@@ -0,0 +1,223 @@
+.include "macros.inc"
+
+#define debug_level 6
+#define debug_vector level6
+
+test_suite break
+
+test break
+    set_vector debug_vector, 0
+    rsil    a2, debug_level
+    _break  0, 0
+
+    set_vector debug_vector, 2f
+    rsil    a2, debug_level - 1
+1:
+    _break  0, 0
+    test_fail
+2:
+    rsr     a2, ps
+    movi    a3, 0x1f
+    and     a2, a2, a3
+    movi    a3, 0x10 | debug_level
+    assert  eq, a2, a3
+    rsr     a2, epc6
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, debugcause
+    movi    a3, 0x8
+    assert  eq, a2, a3
+test_end
+
+test breakn
+    set_vector debug_vector, 0
+    rsil    a2, debug_level
+    _break.n  0
+
+    set_vector debug_vector, 2f
+    rsil    a2, debug_level - 1
+1:
+    _break.n  0
+    test_fail
+2:
+    rsr     a2, ps
+    movi    a3, 0x1f
+    and     a2, a2, a3
+    movi    a3, 0x10 | debug_level
+    assert  eq, a2, a3
+    rsr     a2, epc6
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, debugcause
+    movi    a3, 0x10
+    assert  eq, a2, a3
+test_end
+
+test ibreak
+    set_vector debug_vector, 0
+    rsil    a2, debug_level
+    movi    a2, 1f
+    wsr     a2, ibreaka0
+    movi    a2, 1
+    wsr     a2, ibreakenable
+    isync
+1:
+    rsil    a2, debug_level - 1
+    movi    a2, 1f
+    wsr     a2, ibreaka0
+    movi    a2, 0
+    wsr     a2, ibreakenable
+    isync
+1:
+    set_vector debug_vector, 2f
+    movi    a2, 1f
+    wsr     a2, ibreaka0
+    movi    a2, 1
+    wsr     a2, ibreakenable
+    isync
+1:
+    test_fail
+2:
+    rsr     a2, ps
+    movi    a3, 0x1f
+    and     a2, a2, a3
+    movi    a3, 0x10 | debug_level
+    assert  eq, a2, a3
+    rsr     a2, epc6
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, debugcause
+    movi    a3, 0x2
+    assert  eq, a2, a3
+test_end
+
+test ibreak_priority
+    set_vector debug_vector, 2f
+    rsil    a2, debug_level - 1
+    movi    a2, 1f
+    wsr     a2, ibreaka0
+    movi    a2, 1
+    wsr     a2, ibreakenable
+    isync
+1:
+    break   0, 0
+    test_fail
+2:
+    rsr     a2, debugcause
+    movi    a3, 0x2
+    assert  eq, a2, a3
+test_end
+
+test icount
+    set_vector debug_vector, 2f
+    rsil    a2, debug_level - 1
+    movi    a2, -2
+    wsr     a2, icount
+    movi    a2, 1
+    wsr     a2, icountlevel
+    isync
+    rsil    a2, 0
+    nop
+1:
+    break   0, 0
+    test_fail
+2:
+    movi    a2, 0
+    wsr     a2, icountlevel
+    rsr     a2, epc6
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, debugcause
+    movi    a3, 0x1
+    assert  eq, a2, a3
+test_end
+
+.macro check_dbreak dr
+    rsr     a2, epc6
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, debugcause
+    movi    a3, 0x4 | (\dr << 8)
+    assert  eq, a2, a3
+    movi    a2, 0
+    wsr     a2, dbreakc\dr
+.endm
+
+.macro dbreak_test dr, ctl, break, access, op
+    set_vector debug_vector, 2f
+    rsil    a2, debug_level - 1
+    movi    a2, \ctl
+    wsr     a2, dbreakc\dr
+    movi    a2, \break
+    wsr     a2, dbreaka\dr
+    movi    a2, \access
+    isync
+1:
+    \op     a3, a2, 0
+    test_fail
+2:
+    check_dbreak \dr
+    reset_ps
+.endm
+
+test dbreak_exact
+    dbreak_test 0, 0x4000003f, 0xd000007f, 0xd000007f, l8ui
+    dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007e, l16ui
+    dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007c, l32i
+
+    dbreak_test 1, 0x8000003f, 0xd000007f, 0xd000007f, s8i
+    dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007e, s16i
+    dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s32i
+test_end
+
+test dbreak_overlap
+    dbreak_test 0, 0x4000003f, 0xd000007d, 0xd000007c, l16ui
+    dbreak_test 1, 0x4000003f, 0xd000007d, 0xd000007c, l32i
+
+    dbreak_test 0, 0x4000003e, 0xd000007e, 0xd000007f, l8ui
+    dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007c, l32i
+
+    dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007d, l8ui
+    dbreak_test 1, 0x4000003c, 0xd000007c, 0xd000007c, l16ui
+
+    dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007b, l8ui
+    dbreak_test 1, 0x40000038, 0xd0000078, 0xd000007a, l16ui
+    dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007c, l32i
+
+    dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000075, l8ui
+    dbreak_test 0, 0x40000030, 0xd0000070, 0xd0000076, l16ui
+    dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000078, l32i
+
+    dbreak_test 0, 0x40000020, 0xd0000060, 0xd000006f, l8ui
+    dbreak_test 1, 0x40000020, 0xd0000060, 0xd0000070, l16ui
+    dbreak_test 0, 0x40000020, 0xd0000060, 0xd0000074, l32i
+
+
+    dbreak_test 0, 0x8000003f, 0xd000007d, 0xd000007c, s16i
+    dbreak_test 1, 0x8000003f, 0xd000007d, 0xd000007c, s32i
+
+    dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007f, s8i
+    dbreak_test 1, 0x8000003e, 0xd000007e, 0xd000007c, s32i
+
+    dbreak_test 0, 0x8000003c, 0xd000007c, 0xd000007d, s8i
+    dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s16i
+
+    dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007b, s8i
+    dbreak_test 1, 0x80000038, 0xd0000078, 0xd000007a, s16i
+    dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007c, s32i
+
+    dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000075, s8i
+    dbreak_test 0, 0x80000030, 0xd0000070, 0xd0000076, s16i
+    dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000078, s32i
+
+    dbreak_test 0, 0x80000020, 0xd0000060, 0xd000006f, s8i
+    dbreak_test 1, 0x80000020, 0xd0000060, 0xd0000070, s16i
+    dbreak_test 0, 0x80000020, 0xd0000060, 0xd0000074, s32i
+test_end
+
+test dbreak_invalid
+    dbreak_test 0, 0x40000030, 0xd0000071, 0xd0000070, l16ui
+    dbreak_test 1, 0x40000035, 0xd0000072, 0xd0000070, l32i
+test_end
+
+test_suite_end