mirror of
https://github.com/xemu-project/xemu.git
synced 2025-03-03 01:56:10 +00:00
Merge remote-tracking branch 'remotes/mwalle/tags/lm32-semihosting/20140524' into staging
* remotes/mwalle/tags/lm32-semihosting/20140524: lm32: remove lm32_sys test: lm32: use semihosting for testing target-lm32: add semihosting support test: lm32: make test cases independent Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2f21ff25c0
@ -29,7 +29,6 @@ obj-$(CONFIG_NSERIES) += cbus.o
|
||||
obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
|
||||
obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
|
||||
obj-$(CONFIG_IMX) += imx_ccm.o
|
||||
obj-$(CONFIG_LM32) += lm32_sys.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
|
||||
obj-$(CONFIG_MAINSTONE) += mst_fpga.o
|
||||
|
@ -1,179 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the LatticeMico32 system control block.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This model is mainly intended for testing purposes and doesn't fit to any
|
||||
* real hardware. On the one hand it provides a control register (R_CTRL) on
|
||||
* the other hand it supports the lm32 tests.
|
||||
*
|
||||
* A write to the control register causes a system shutdown.
|
||||
* Tests first write the pointer to a test name to the test name register
|
||||
* (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
|
||||
* the test is passed or any non-zero value to it if the test is failed.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
enum {
|
||||
R_CTRL = 0,
|
||||
R_PASSFAIL,
|
||||
R_TESTNAME,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
#define MAX_TESTNAME_LEN 32
|
||||
|
||||
#define TYPE_LM32_SYS "lm32-sys"
|
||||
#define LM32_SYS(obj) OBJECT_CHECK(LM32SysState, (obj), TYPE_LM32_SYS)
|
||||
|
||||
struct LM32SysState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint32_t base;
|
||||
uint32_t regs[R_MAX];
|
||||
uint8_t testname[MAX_TESTNAME_LEN];
|
||||
};
|
||||
typedef struct LM32SysState LM32SysState;
|
||||
|
||||
static void copy_testname(LM32SysState *s)
|
||||
{
|
||||
cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
|
||||
MAX_TESTNAME_LEN);
|
||||
s->testname[MAX_TESTNAME_LEN - 1] = '\0';
|
||||
}
|
||||
|
||||
static void sys_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LM32SysState *s = opaque;
|
||||
char *testname;
|
||||
|
||||
trace_lm32_sys_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTRL:
|
||||
qemu_system_shutdown_request();
|
||||
break;
|
||||
case R_PASSFAIL:
|
||||
s->regs[addr] = value;
|
||||
testname = (char *)s->testname;
|
||||
fprintf(stderr, "TC %-*s %s\n", MAX_TESTNAME_LEN,
|
||||
testname, (value) ? "FAILED" : "OK");
|
||||
if (value) {
|
||||
cpu_dump_state(qemu_get_cpu(0), stderr, fprintf, 0);
|
||||
}
|
||||
break;
|
||||
case R_TESTNAME:
|
||||
s->regs[addr] = value;
|
||||
copy_testname(s);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("lm32_sys: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool sys_ops_accepts(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write)
|
||||
{
|
||||
return is_write && size == 4;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sys_ops = {
|
||||
.write = sys_write,
|
||||
.valid.accepts = sys_ops_accepts,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void sys_reset(DeviceState *d)
|
||||
{
|
||||
LM32SysState *s = LM32_SYS(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
memset(s->testname, 0, MAX_TESTNAME_LEN);
|
||||
}
|
||||
|
||||
static int lm32_sys_init(SysBusDevice *dev)
|
||||
{
|
||||
LM32SysState *s = LM32_SYS(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &sys_ops , s,
|
||||
"sys", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
/* Note: This device is not created in the board initialization,
|
||||
* instead it has to be added with the -device parameter. Therefore,
|
||||
* the device maps itself. */
|
||||
sysbus_mmio_map(dev, 0, s->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm32_sys = {
|
||||
.name = "lm32-sys",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
|
||||
VMSTATE_BUFFER(testname, LM32SysState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property lm32_sys_properties[] = {
|
||||
DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void lm32_sys_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = lm32_sys_init;
|
||||
dc->reset = sys_reset;
|
||||
dc->vmsd = &vmstate_lm32_sys;
|
||||
dc->props = lm32_sys_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_sys_info = {
|
||||
.name = TYPE_LM32_SYS,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LM32SysState),
|
||||
.class_init = lm32_sys_class_init,
|
||||
};
|
||||
|
||||
static void lm32_sys_register_types(void)
|
||||
{
|
||||
type_register_static(&lm32_sys_info);
|
||||
}
|
||||
|
||||
type_init(lm32_sys_register_types)
|
@ -3071,7 +3071,8 @@ STEXI
|
||||
Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
|
||||
ETEXI
|
||||
DEF("semihosting", 0, QEMU_OPTION_semihosting,
|
||||
"-semihosting semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA)
|
||||
"-semihosting semihosting mode\n",
|
||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
|
||||
STEXI
|
||||
@item -semihosting
|
||||
@findex -semihosting
|
||||
|
@ -1,3 +1,4 @@
|
||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||
obj-y += gdbstub.o
|
||||
obj-y += lm32-semi.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o
|
||||
|
@ -16,14 +16,13 @@ This will make serial0 (the lm32_uart) and serial1 (the JTAG UART)
|
||||
available as virtual consoles.
|
||||
|
||||
|
||||
Programmatically terminate the emulator
|
||||
----------------------------------------
|
||||
Originally neither the LatticeMico32 nor its peripherals support a
|
||||
mechanism to shut down the machine. Emulation aware programs can write to a
|
||||
to a special register within the system control block to shut down the
|
||||
virtual machine. For more details see hw/lm32_sys.c. The lm32-evr is the
|
||||
first BSP which instantiate this model. A (32 bit) write to 0xfff0000
|
||||
causes a vm shutdown.
|
||||
Semihosting
|
||||
-----------
|
||||
Semihosting on this target is supported. Some system calls like read, write
|
||||
and exit are executed on the host if semihosting is enabled. See
|
||||
target/lm32-semi.c for all supported system calls. Emulation aware programs
|
||||
can use this mechanism to shut down the virtual machine and print to the
|
||||
host console. See the tcg tests for an example.
|
||||
|
||||
|
||||
Special instructions
|
||||
|
@ -217,6 +217,7 @@ void lm32_breakpoint_remove(CPULM32State *env, int index);
|
||||
void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address,
|
||||
lm32_wp_t wp_type);
|
||||
void lm32_watchpoint_remove(CPULM32State *env, int index);
|
||||
bool lm32_cpu_do_semihosting(CPUState *cs);
|
||||
|
||||
static inline CPULM32State *cpu_init(const char *cpu_model)
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* LatticeMico32 helper routines.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
* Copyright (c) 2010-2014 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
#include "cpu.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
int lm32_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
|
||||
int mmu_idx)
|
||||
@ -159,11 +160,20 @@ void lm32_cpu_do_interrupt(CPUState *cs)
|
||||
"exception at pc=%x type=%x\n", env->pc, cs->exception_index);
|
||||
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_SYSTEMCALL:
|
||||
if (unlikely(semihosting_enabled)) {
|
||||
/* do_semicall() returns true if call was handled. Otherwise
|
||||
* do the normal exception handling. */
|
||||
if (lm32_cpu_do_semihosting(cs)) {
|
||||
env->pc += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case EXCP_INSN_BUS_ERROR:
|
||||
case EXCP_DATA_BUS_ERROR:
|
||||
case EXCP_DIVIDE_BY_ZERO:
|
||||
case EXCP_IRQ:
|
||||
case EXCP_SYSTEMCALL:
|
||||
/* non-debug exceptions */
|
||||
env->regs[R_EA] = env->pc;
|
||||
env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
|
||||
|
215
target-lm32/lm32-semi.c
Normal file
215
target-lm32/lm32-semi.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Lattice Mico32 semihosting syscall interface
|
||||
*
|
||||
* Copyright (c) 2014 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* Based on target-m68k/m68k-semi.c, which is
|
||||
* Copyright (c) 2005-2007 CodeSourcery.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include "cpu.h"
|
||||
#include "helper.h"
|
||||
#include "qemu/log.h"
|
||||
#include "exec/softmmu-semi.h"
|
||||
|
||||
enum {
|
||||
TARGET_SYS_exit = 1,
|
||||
TARGET_SYS_open = 2,
|
||||
TARGET_SYS_close = 3,
|
||||
TARGET_SYS_read = 4,
|
||||
TARGET_SYS_write = 5,
|
||||
TARGET_SYS_lseek = 6,
|
||||
TARGET_SYS_fstat = 10,
|
||||
TARGET_SYS_stat = 15,
|
||||
};
|
||||
|
||||
enum {
|
||||
NEWLIB_O_RDONLY = 0x0,
|
||||
NEWLIB_O_WRONLY = 0x1,
|
||||
NEWLIB_O_RDWR = 0x2,
|
||||
NEWLIB_O_APPEND = 0x8,
|
||||
NEWLIB_O_CREAT = 0x200,
|
||||
NEWLIB_O_TRUNC = 0x400,
|
||||
NEWLIB_O_EXCL = 0x800,
|
||||
};
|
||||
|
||||
static int translate_openflags(int flags)
|
||||
{
|
||||
int hf;
|
||||
|
||||
if (flags & NEWLIB_O_WRONLY) {
|
||||
hf = O_WRONLY;
|
||||
} else if (flags & NEWLIB_O_RDWR) {
|
||||
hf = O_RDWR;
|
||||
} else {
|
||||
hf = O_RDONLY;
|
||||
}
|
||||
|
||||
if (flags & NEWLIB_O_APPEND) {
|
||||
hf |= O_APPEND;
|
||||
}
|
||||
|
||||
if (flags & NEWLIB_O_CREAT) {
|
||||
hf |= O_CREAT;
|
||||
}
|
||||
|
||||
if (flags & NEWLIB_O_TRUNC) {
|
||||
hf |= O_TRUNC;
|
||||
}
|
||||
|
||||
if (flags & NEWLIB_O_EXCL) {
|
||||
hf |= O_EXCL;
|
||||
}
|
||||
|
||||
return hf;
|
||||
}
|
||||
|
||||
struct newlib_stat {
|
||||
int16_t newlib_st_dev; /* device */
|
||||
uint16_t newlib_st_ino; /* inode */
|
||||
uint16_t newlib_st_mode; /* protection */
|
||||
uint16_t newlib_st_nlink; /* number of hard links */
|
||||
uint16_t newlib_st_uid; /* user ID of owner */
|
||||
uint16_t newlib_st_gid; /* group ID of owner */
|
||||
int16_t newlib_st_rdev; /* device type (if inode device) */
|
||||
int32_t newlib_st_size; /* total size, in bytes */
|
||||
int32_t newlib_st_atime; /* time of last access */
|
||||
uint32_t newlib_st_spare1;
|
||||
int32_t newlib_st_mtime; /* time of last modification */
|
||||
uint32_t newlib_st_spare2;
|
||||
int32_t newlib_st_ctime; /* time of last change */
|
||||
uint32_t newlib_st_spare3;
|
||||
} QEMU_PACKED;
|
||||
|
||||
static int translate_stat(CPULM32State *env, target_ulong addr,
|
||||
struct stat *s)
|
||||
{
|
||||
struct newlib_stat *p;
|
||||
|
||||
p = lock_user(VERIFY_WRITE, addr, sizeof(struct newlib_stat), 0);
|
||||
if (!p) {
|
||||
return 0;
|
||||
}
|
||||
p->newlib_st_dev = cpu_to_be16(s->st_dev);
|
||||
p->newlib_st_ino = cpu_to_be16(s->st_ino);
|
||||
p->newlib_st_mode = cpu_to_be16(s->st_mode);
|
||||
p->newlib_st_nlink = cpu_to_be16(s->st_nlink);
|
||||
p->newlib_st_uid = cpu_to_be16(s->st_uid);
|
||||
p->newlib_st_gid = cpu_to_be16(s->st_gid);
|
||||
p->newlib_st_rdev = cpu_to_be16(s->st_rdev);
|
||||
p->newlib_st_size = cpu_to_be32(s->st_size);
|
||||
p->newlib_st_atime = cpu_to_be32(s->st_atime);
|
||||
p->newlib_st_mtime = cpu_to_be32(s->st_mtime);
|
||||
p->newlib_st_ctime = cpu_to_be32(s->st_ctime);
|
||||
unlock_user(p, addr, sizeof(struct newlib_stat));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool lm32_cpu_do_semihosting(CPUState *cs)
|
||||
{
|
||||
LM32CPU *cpu = LM32_CPU(cs);
|
||||
CPULM32State *env = &cpu->env;
|
||||
|
||||
int ret = -1;
|
||||
target_ulong nr, arg0, arg1, arg2;
|
||||
void *p;
|
||||
struct stat s;
|
||||
|
||||
nr = env->regs[R_R8];
|
||||
arg0 = env->regs[R_R1];
|
||||
arg1 = env->regs[R_R2];
|
||||
arg2 = env->regs[R_R3];
|
||||
|
||||
switch (nr) {
|
||||
case TARGET_SYS_exit:
|
||||
/* void _exit(int rc) */
|
||||
exit(arg0);
|
||||
|
||||
case TARGET_SYS_open:
|
||||
/* int open(const char *pathname, int flags) */
|
||||
p = lock_user_string(arg0);
|
||||
if (!p) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = open(p, translate_openflags(arg2));
|
||||
unlock_user(p, arg0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SYS_read:
|
||||
/* ssize_t read(int fd, const void *buf, size_t count) */
|
||||
p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
|
||||
if (!p) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = read(arg0, p, arg2);
|
||||
unlock_user(p, arg1, arg2);
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SYS_write:
|
||||
/* ssize_t write(int fd, const void *buf, size_t count) */
|
||||
p = lock_user(VERIFY_READ, arg1, arg2, 1);
|
||||
if (!p) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = write(arg0, p, arg2);
|
||||
unlock_user(p, arg1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SYS_close:
|
||||
/* int close(int fd) */
|
||||
/* don't close stdin/stdout/stderr */
|
||||
if (arg0 > 2) {
|
||||
ret = close(arg0);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SYS_lseek:
|
||||
/* off_t lseek(int fd, off_t offset, int whence */
|
||||
ret = lseek(arg0, arg1, arg2);
|
||||
break;
|
||||
|
||||
case TARGET_SYS_stat:
|
||||
/* int stat(const char *path, struct stat *buf) */
|
||||
p = lock_user_string(arg0);
|
||||
if (!p) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = stat(p, &s);
|
||||
unlock_user(p, arg0, 0);
|
||||
if (translate_stat(env, arg1, &s) == 0) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SYS_fstat:
|
||||
/* int stat(int fd, struct stat *buf) */
|
||||
ret = fstat(arg0, &s);
|
||||
if (ret == 0) {
|
||||
if (translate_stat(env, arg1, &s) == 0) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* unhandled */
|
||||
return false;
|
||||
}
|
||||
|
||||
env->regs[R_R1] = ret;
|
||||
return true;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
CROSS=lm32-elf-
|
||||
|
||||
SIM = qemu-system-lm32
|
||||
SIMFLAGS = -M lm32-evr -nographic -device lm32-sys -net none -kernel
|
||||
SIMFLAGS = -M lm32-evr -nographic -semihosting -net none -kernel
|
||||
|
||||
CC = $(CROSS)gcc
|
||||
AS = $(CROSS)as
|
||||
@ -18,6 +18,7 @@ LDFLAGS = -T$(TSRC_PATH)/linker.ld
|
||||
ASFLAGS += -Wa,-I,$(TSRC_PATH)/
|
||||
|
||||
CRT = crt.o
|
||||
HELPER = helper.o
|
||||
TESTCASES += test_add.tst
|
||||
TESTCASES += test_addi.tst
|
||||
TESTCASES += test_and.tst
|
||||
@ -91,15 +92,15 @@ all: build
|
||||
%.o: $(TSRC_PATH)/%.S
|
||||
$(AS) $(ASFLAGS) -c $< -o $@
|
||||
|
||||
%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT)
|
||||
$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
|
||||
%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT) $(HELPER)
|
||||
$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $(HELPER) $< -o $@
|
||||
|
||||
build: $(CRT) $(TESTCASES)
|
||||
build: $(TESTCASES)
|
||||
|
||||
check: $(TESTCASES:test_%.tst=check_%)
|
||||
|
||||
check_%: test_%.tst $(CRT) $(SYS)
|
||||
$(SIM) $(SIMFLAGS) $<
|
||||
check_%: test_%.tst
|
||||
@$(SIM) $(SIMFLAGS) $<
|
||||
|
||||
clean:
|
||||
$(RM) -fr $(TESTCASES) $(CRT)
|
||||
$(RM) -fr $(TESTCASES) $(CRT) $(HELPER)
|
||||
|
@ -8,9 +8,9 @@ _reset_handler:
|
||||
ori r1, r1, lo(_start)
|
||||
wcsr eba, r1
|
||||
wcsr deba, r1
|
||||
mvhi sp, hi(_fstack)
|
||||
ori sp, sp, lo(_fstack)
|
||||
bi _main
|
||||
nop
|
||||
nop
|
||||
|
||||
_breakpoint_handler:
|
||||
ori r25, r25, 1
|
||||
|
65
tests/tcg/lm32/helper.S
Normal file
65
tests/tcg/lm32/helper.S
Normal file
@ -0,0 +1,65 @@
|
||||
.text
|
||||
.global _start, _write, _exit
|
||||
.global _tc_fail, _tc_pass
|
||||
|
||||
_write:
|
||||
addi sp, sp, -4
|
||||
sw (sp+4), r8
|
||||
mvi r8, 5
|
||||
scall
|
||||
lw r8, (sp+4)
|
||||
addi sp, sp, 4
|
||||
ret
|
||||
|
||||
_exit:
|
||||
mvi r8, 1
|
||||
scall
|
||||
1:
|
||||
bi 1b
|
||||
|
||||
_tc_pass:
|
||||
.data
|
||||
1:
|
||||
.ascii "OK\n"
|
||||
2:
|
||||
.text
|
||||
addi sp, sp, -16
|
||||
sw (sp+4), ra
|
||||
sw (sp+8), r1
|
||||
sw (sp+12), r2
|
||||
sw (sp+16), r3
|
||||
mvi r1, 1
|
||||
mvhi r2, hi(1b)
|
||||
ori r2, r2, lo(1b)
|
||||
mvi r3, (2b - 1b)
|
||||
calli _write
|
||||
lw r3, (sp+16)
|
||||
lw r2, (sp+12)
|
||||
lw r1, (sp+8)
|
||||
lw ra, (sp+4)
|
||||
addi sp, sp, 16
|
||||
ret
|
||||
|
||||
_tc_fail:
|
||||
.data
|
||||
1:
|
||||
.ascii "FAILED\n"
|
||||
2:
|
||||
.text
|
||||
addi sp, sp, -16
|
||||
sw (sp+4), ra
|
||||
sw (sp+8), r1
|
||||
sw (sp+12), r2
|
||||
sw (sp+16), r3
|
||||
sw (sp+4), ra
|
||||
mvi r1, 1
|
||||
mvhi r2, hi(1b)
|
||||
ori r2, r2, lo(1b)
|
||||
mvi r3, (2b - 1b)
|
||||
calli _write
|
||||
lw r3, (sp+16)
|
||||
lw r2, (sp+12)
|
||||
lw r1, (sp+8)
|
||||
lw ra, (sp+4)
|
||||
addi sp, sp, 16
|
||||
ret
|
@ -1,12 +1,26 @@
|
||||
|
||||
.equ MAX_TESTNAME_LEN, 32
|
||||
.macro test_name name
|
||||
.data
|
||||
tn_\name:
|
||||
.asciz "\name"
|
||||
.ascii "\name"
|
||||
.space MAX_TESTNAME_LEN - (. - tn_\name), ' '
|
||||
.text
|
||||
mvhi r13, hi(tn_\name)
|
||||
ori r13, r13, lo(tn_\name)
|
||||
sw (r12+8), r13
|
||||
.global \name
|
||||
\name:
|
||||
addi sp, sp, -12
|
||||
sw (sp+4), r1
|
||||
sw (sp+8), r2
|
||||
sw (sp+12), r3
|
||||
mvi r1, 1
|
||||
mvhi r2, hi(tn_\name)
|
||||
ori r2, r2, lo(tn_\name)
|
||||
mvi r3, MAX_TESTNAME_LEN
|
||||
calli _write
|
||||
lw r3, (sp+12)
|
||||
lw r2, (sp+8)
|
||||
lw r1, (sp+4)
|
||||
addi sp, sp, 12
|
||||
.endm
|
||||
|
||||
.macro load reg val
|
||||
@ -15,13 +29,12 @@ tn_\name:
|
||||
.endm
|
||||
|
||||
.macro tc_pass
|
||||
mvi r13, 0
|
||||
sw (r12+4), r13
|
||||
calli _tc_pass
|
||||
.endm
|
||||
|
||||
.macro tc_fail
|
||||
mvi r13, 1
|
||||
sw (r12+4), r13
|
||||
addi r12, r12, 1
|
||||
calli _tc_fail
|
||||
.endm
|
||||
|
||||
.macro check_r3 val
|
||||
@ -63,14 +76,12 @@ tn_\name:
|
||||
.global _main
|
||||
.text
|
||||
_main:
|
||||
mvhi r12, hi(0xffff0000) # base address of test block
|
||||
ori r12, r12, lo(0xffff0000)
|
||||
mvi r12, 0
|
||||
.endm
|
||||
|
||||
.macro end
|
||||
sw (r12+0), r0
|
||||
1:
|
||||
bi 1b
|
||||
mv r1, r12
|
||||
calli _exit
|
||||
.endm
|
||||
|
||||
# base +
|
||||
|
@ -8,10 +8,12 @@ lb r3, (r1+0)
|
||||
check_r3 0x7e
|
||||
|
||||
test_name LB_2
|
||||
load r1 data
|
||||
lb r3, (r1+1)
|
||||
check_r3 0x7f
|
||||
|
||||
test_name LB_3
|
||||
load r1 data
|
||||
lb r3, (r1+-1)
|
||||
check_r3 0x7d
|
||||
|
||||
@ -21,10 +23,12 @@ lb r3, (r1+0)
|
||||
check_r3 0xfffffffe
|
||||
|
||||
test_name LB_5
|
||||
load r1 data_msb
|
||||
lb r3, (r1+1)
|
||||
check_r3 0xffffffff
|
||||
|
||||
test_name LB_6
|
||||
load r1 data_msb
|
||||
lb r3, (r1+-1)
|
||||
check_r3 0xfffffffd
|
||||
|
||||
|
@ -8,10 +8,12 @@ lbu r3, (r1+0)
|
||||
check_r3 0x7e
|
||||
|
||||
test_name LBU_2
|
||||
load r1 data
|
||||
lbu r3, (r1+1)
|
||||
check_r3 0x7f
|
||||
|
||||
test_name LBU_3
|
||||
load r1 data
|
||||
lbu r3, (r1+-1)
|
||||
check_r3 0x7d
|
||||
|
||||
@ -21,10 +23,12 @@ lbu r3, (r1+0)
|
||||
check_r3 0xfe
|
||||
|
||||
test_name LBU_5
|
||||
load r1 data_msb
|
||||
lbu r3, (r1+1)
|
||||
check_r3 0xff
|
||||
|
||||
test_name LBU_6
|
||||
load r1 data_msb
|
||||
lbu r3, (r1+-1)
|
||||
check_r3 0xfd
|
||||
|
||||
|
@ -8,10 +8,12 @@ lh r3, (r1+0)
|
||||
check_r3 0x7e7f
|
||||
|
||||
test_name LH_2
|
||||
load r1 data
|
||||
lh r3, (r1+2)
|
||||
check_r3 0x7071
|
||||
|
||||
test_name LH_3
|
||||
load r1 data
|
||||
lh r3, (r1+-2)
|
||||
check_r3 0x7c7d
|
||||
|
||||
@ -21,10 +23,12 @@ lh r3, (r1+0)
|
||||
check_r3 0xfffffeff
|
||||
|
||||
test_name LH_5
|
||||
load r1 data_msb
|
||||
lh r3, (r1+2)
|
||||
check_r3 0xfffff0f1
|
||||
|
||||
test_name LH_6
|
||||
load r1 data_msb
|
||||
lh r3, (r1+-2)
|
||||
check_r3 0xfffffcfd
|
||||
|
||||
|
@ -8,10 +8,12 @@ lhu r3, (r1+0)
|
||||
check_r3 0x7e7f
|
||||
|
||||
test_name LHU_2
|
||||
load r1 data
|
||||
lhu r3, (r1+2)
|
||||
check_r3 0x7071
|
||||
|
||||
test_name LHU_3
|
||||
load r1 data
|
||||
lhu r3, (r1+-2)
|
||||
check_r3 0x7c7d
|
||||
|
||||
@ -21,10 +23,12 @@ lhu r3, (r1+0)
|
||||
check_r3 0xfeff
|
||||
|
||||
test_name LHU_5
|
||||
load r1 data_msb
|
||||
lhu r3, (r1+2)
|
||||
check_r3 0xf0f1
|
||||
|
||||
test_name LHU_6
|
||||
load r1 data_msb
|
||||
lhu r3, (r1+-2)
|
||||
check_r3 0xfcfd
|
||||
|
||||
|
@ -8,10 +8,12 @@ lw r3, (r1+0)
|
||||
check_r3 0x7e7f7071
|
||||
|
||||
test_name LW_2
|
||||
load r1 data
|
||||
lw r3, (r1+4)
|
||||
check_r3 0x72737475
|
||||
|
||||
test_name LW_3
|
||||
load r1 data
|
||||
lw r3, (r1+-4)
|
||||
check_r3 0x7a7b7c7d
|
||||
|
||||
|
@ -9,11 +9,13 @@ sb (r1+0), r2
|
||||
check_mem data 0xaa000000
|
||||
|
||||
test_name SB_2
|
||||
load r1 data
|
||||
load r2 0xf0f1f2bb
|
||||
sb (r1+1), r2
|
||||
check_mem data 0xaabb0000
|
||||
|
||||
test_name SB_3
|
||||
load r1 data
|
||||
load r2 0xf0f1f2cc
|
||||
sb (r1+-1), r2
|
||||
check_mem data0 0x000000cc
|
||||
|
@ -5,6 +5,10 @@ start
|
||||
test_name SCALL_1
|
||||
mvi r1, 1
|
||||
wcsr IE, r1
|
||||
# we are running in a semi hosted environment
|
||||
# therefore we have to set r8 to some unused system
|
||||
# call
|
||||
mvi r8, 0
|
||||
insn:
|
||||
scall
|
||||
check_excp 64
|
||||
|
@ -9,11 +9,13 @@ sh (r1+0), r2
|
||||
check_mem data 0xaaaa0000
|
||||
|
||||
test_name SH_2
|
||||
load r1 data
|
||||
load r2 0xf0f1bbbb
|
||||
sh (r1+2), r2
|
||||
check_mem data 0xaaaabbbb
|
||||
|
||||
test_name SH_3
|
||||
load r1 data
|
||||
load r2 0xf0f1cccc
|
||||
sh (r1+-2), r2
|
||||
check_mem data0 0x0000cccc
|
||||
|
@ -9,16 +9,19 @@ sw (r1+0), r2
|
||||
check_mem data 0xaabbccdd
|
||||
|
||||
test_name SW_2
|
||||
load r1 data
|
||||
load r2 0x00112233
|
||||
sw (r1+4), r2
|
||||
check_mem data1 0x00112233
|
||||
|
||||
test_name SW_3
|
||||
load r1 data
|
||||
load r2 0x44556677
|
||||
sw (r1+-4), r2
|
||||
check_mem data0 0x44556677
|
||||
|
||||
test_name SW_4
|
||||
load r1 data
|
||||
sw (r1+0), r1
|
||||
lw r3, (r1+0)
|
||||
check_r3 data
|
||||
|
@ -627,9 +627,6 @@ lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
lm32_uart_irq_state(int level) "irq state %d"
|
||||
|
||||
# hw/misc/lm32_sys.c
|
||||
lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
|
||||
# hw/scsi/megasas.c
|
||||
megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " "
|
||||
megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x"
|
||||
|
Loading…
x
Reference in New Issue
Block a user