WIP
This commit is contained in:
parent
56c6e249b6
commit
005bf105aa
32 changed files with 2814 additions and 1 deletions
4
configs/devices/cr16c-softmmu/default.mak
Normal file
4
configs/devices/cr16c-softmmu/default.mak
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Default configuration for cr16c-softmmu
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_SC14450=y
|
||||
2
configs/targets/cr16c-softmmu.mak
Normal file
2
configs/targets/cr16c-softmmu.mak
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
TARGET_ARCH=cr16c
|
||||
TARGET_LONG_BITS=32
|
||||
|
|
@ -51,6 +51,7 @@ source arm/Kconfig
|
|||
source cpu/Kconfig
|
||||
source alpha/Kconfig
|
||||
source avr/Kconfig
|
||||
source cr16c/Kconfig
|
||||
source hppa/Kconfig
|
||||
source i386/Kconfig
|
||||
source loongarch/Kconfig
|
||||
|
|
|
|||
2
hw/cr16c/Kconfig
Normal file
2
hw/cr16c/Kconfig
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
config SC14450
|
||||
bool
|
||||
22
hw/cr16c/boot.c
Normal file
22
hw/cr16c/boot.c
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include "boot.h"
|
||||
#include "hw/loader.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
bool cr16c_load_firmware(CR16CCPU *cpu, MachineState *ms, MemoryRegion *mr, const char *firmware) {
|
||||
/* Adapted from arm implementation */
|
||||
g_autofree char *filename = NULL;
|
||||
int ret;
|
||||
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware);
|
||||
if (!filename) {
|
||||
error_report("Could not find firmware image");
|
||||
return false;
|
||||
}
|
||||
ret = load_image_mr(filename, mr);
|
||||
if (ret < 0) {
|
||||
error_report("Failed to load firmware image");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
8
hw/cr16c/boot.h
Normal file
8
hw/cr16c/boot.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef HW_CR16C_BOOT_H
|
||||
#define HW_CR16C_BOOT_H
|
||||
|
||||
#include "target/cr16c/cpu.h"
|
||||
|
||||
bool cr16c_load_firmware(CR16CCPU *cpu, MachineState *ms, MemoryRegion *mr, const char *firmware);
|
||||
|
||||
#endif /* HW_CR16C_BOOT_H */
|
||||
5
hw/cr16c/meson.build
Normal file
5
hw/cr16c/meson.build
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
cr16c_ss = ss.source_set()
|
||||
cr16c_ss.add(files('sc14450.c'))
|
||||
cr16c_ss.add(files('sc14450board.c'))
|
||||
cr16c_ss.add(files('boot.c'))
|
||||
hw_arch += {'cr16c': cr16c_ss}
|
||||
56
hw/cr16c/sc14450.c
Normal file
56
hw/cr16c/sc14450.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "sc14450.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/units.h"
|
||||
|
||||
typedef struct SC14450McuClass {
|
||||
SysBusDeviceClass parent_class;
|
||||
|
||||
const char* cpu_type;
|
||||
size_t flash_size;
|
||||
} SC14450McuClass;
|
||||
DECLARE_CLASS_CHECKERS(SC14450McuClass, SC14450_MCU, TYPE_SC14450_MCU)
|
||||
|
||||
static void sc14450_realize(DeviceState* dev, Error** errp)
|
||||
{
|
||||
SC14450McuState* s = SC14450_MCU(dev);
|
||||
const SC14450McuClass* mc = SC14450_MCU_GET_CLASS(dev);
|
||||
|
||||
object_initialize_child(OBJECT(dev), "cpu", &s->cpu, mc->cpu_type);
|
||||
object_property_set_bool(OBJECT(&s->cpu), "realized", true, &error_abort);
|
||||
|
||||
memory_region_init_rom(&s->flash, OBJECT(dev), "flash", mc->flash_size, &error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), 0, &s->flash);
|
||||
}
|
||||
|
||||
static void sc14450_class_init(ObjectClass* oc, void* data)
|
||||
{
|
||||
DeviceClass* dc = DEVICE_CLASS(oc);
|
||||
dc->realize = sc14450_realize;
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static void sc14450s_class_init(ObjectClass* oc, void* data)
|
||||
{
|
||||
SC14450McuClass* sc14450 = SC14450_MCU_CLASS(oc);
|
||||
|
||||
sc14450->cpu_type = CR16C_CPU_TYPE_NAME("SC14450C");
|
||||
sc14450->flash_size = 16 * MiB;
|
||||
}
|
||||
|
||||
static const TypeInfo sc14450_mcu_types[] = {
|
||||
{
|
||||
.name = TYPE_SC14450S_MCU,
|
||||
.parent = TYPE_SC14450_MCU,
|
||||
.class_init = sc14450s_class_init,
|
||||
},
|
||||
{
|
||||
.name = TYPE_SC14450_MCU,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SC14450McuState),
|
||||
.class_size = sizeof(SC14450McuClass),
|
||||
.class_init = sc14450_class_init,
|
||||
.abstract = true,
|
||||
}
|
||||
};
|
||||
DEFINE_TYPES(sc14450_mcu_types)
|
||||
21
hw/cr16c/sc14450.h
Normal file
21
hw/cr16c/sc14450.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef HW_SC14450_H
|
||||
#define HW_SC14450_H
|
||||
|
||||
#include "target/cr16c/cpu.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_SC14450_MCU "SC14450"
|
||||
#define TYPE_SC14450S_MCU "SC14450S"
|
||||
|
||||
typedef struct SC14450McuState SC14450McuState;
|
||||
DECLARE_INSTANCE_CHECKER(SC14450McuState, SC14450_MCU, TYPE_SC14450_MCU)
|
||||
|
||||
struct SC14450McuState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
CR16CCPU cpu;
|
||||
MemoryRegion flash;
|
||||
};
|
||||
|
||||
#endif /* HW_SC14450_H */
|
||||
60
hw/cr16c/sc14450board.c
Normal file
60
hw/cr16c/sc14450board.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#include "boot.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object.h"
|
||||
#include "sc14450.h"
|
||||
|
||||
typedef struct SC14450BoardMachineState {
|
||||
MachineState parent_obj;
|
||||
SC14450McuState mcu;
|
||||
} SC14450BoardMachineState;
|
||||
|
||||
typedef struct SC14450BoardMachineClass {
|
||||
MachineClass parent_class;
|
||||
} SC14450BoardMachineClass;
|
||||
|
||||
#define TYPE_SC14450_BOARD_BASE_MACHINE MACHINE_TYPE_NAME("SC14450-board-base")
|
||||
#define TYPE_SC14450_BOARD_MACHINE MACHINE_TYPE_NAME("SC14450-board")
|
||||
|
||||
DECLARE_OBJ_CHECKERS(SC14450BoardMachineState, SC14450BoardMachineClass, SC14450_BOARD_MACHINE, TYPE_SC14450_BOARD_MACHINE)
|
||||
|
||||
static void sc14450board_init(MachineState* machine)
|
||||
{
|
||||
SC14450BoardMachineState* m_state = SC14450_BOARD_MACHINE(machine);
|
||||
|
||||
object_initialize_child(OBJECT(machine), "mcu", &m_state->mcu, TYPE_SC14450S_MCU);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&m_state->mcu), &error_abort);
|
||||
|
||||
if (machine->firmware) {
|
||||
if (!cr16c_load_firmware(&m_state->mcu.cpu, machine, &m_state->mcu.flash, machine->firmware)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sc14450board_class_init(ObjectClass* oc, void* data)
|
||||
{
|
||||
MachineClass* mc = MACHINE_CLASS(oc);
|
||||
mc->desc = "SC14450 VoIP + DECT Processor Board";
|
||||
mc->alias = "sc14450board";
|
||||
mc->init = sc14450board_init;
|
||||
mc->default_cpus = 1;
|
||||
mc->min_cpus = 1;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
mc->is_default = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo sc14450board_machine_types[] = {
|
||||
{
|
||||
.name = TYPE_SC14450_BOARD_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(SC14450BoardMachineState),
|
||||
.class_size = sizeof(SC14450BoardMachineClass),
|
||||
.class_init = sc14450board_class_init,
|
||||
}
|
||||
};
|
||||
DEFINE_TYPES(sc14450board_machine_types);
|
||||
|
|
@ -49,6 +49,7 @@ subdir('fsi')
|
|||
subdir('alpha')
|
||||
subdir('arm')
|
||||
subdir('avr')
|
||||
subdir('cr16c')
|
||||
subdir('hppa')
|
||||
subdir('i386')
|
||||
subdir('loongarch')
|
||||
|
|
|
|||
|
|
@ -242,6 +242,8 @@ enum bfd_architecture
|
|||
#define bfd_mach_rx_v2 0x76
|
||||
#define bfd_mach_rx_v3 0x77
|
||||
bfd_arch_loongarch,
|
||||
bfd_arch_cr16c,
|
||||
#define bfd_mach_sc14450 0x450
|
||||
bfd_arch_last
|
||||
};
|
||||
#define bfd_mach_s390_31 31
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ enum {
|
|||
QEMU_ARCH_AVR = (1 << 21),
|
||||
QEMU_ARCH_HEXAGON = (1 << 22),
|
||||
QEMU_ARCH_LOONGARCH = (1 << 23),
|
||||
QEMU_ARCH_CR16C = (1 << 24),
|
||||
};
|
||||
|
||||
bool qemu_arch_available(unsigned qemu_arch_mask);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
# Since: 3.0
|
||||
##
|
||||
{ 'enum' : 'SysEmuTarget',
|
||||
'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'hppa', 'i386',
|
||||
'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cr16c', 'hppa', 'i386',
|
||||
'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
|
||||
'mips64el', 'mipsel', 'or1k', 'ppc',
|
||||
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
source alpha/Kconfig
|
||||
source arm/Kconfig
|
||||
source avr/Kconfig
|
||||
source cr16c/Kconfig
|
||||
source hppa/Kconfig
|
||||
source i386/Kconfig
|
||||
source loongarch/Kconfig
|
||||
|
|
|
|||
2
target/cr16c/Kconfig
Normal file
2
target/cr16c/Kconfig
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
config CR16C
|
||||
bool
|
||||
9
target/cr16c/cpu-param.h
Normal file
9
target/cr16c/cpu-param.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef CR16C_CPU_PARAM_H
|
||||
#define CR16C_CPU_PARAM_H
|
||||
|
||||
#define TARGET_PAGE_BITS 12
|
||||
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
|
||||
#endif // CR16C_CPU_PARAM_H
|
||||
22
target/cr16c/cpu-qom.h
Normal file
22
target/cr16c/cpu-qom.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef CR16C_CPU_QOM_H
|
||||
#define CR16C_CPU_QOM_H
|
||||
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
#define TYPE_CR16C_CPU "cr16c-cpu"
|
||||
|
||||
OBJECT_DECLARE_CPU_TYPE(CR16CCPU, CR16CCPUClass, CR16C_CPU)
|
||||
|
||||
typedef struct CR16CCPUDef CR16CCPUDef;
|
||||
struct CR16CCPUClass {
|
||||
/*< private >*/
|
||||
CPUClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
DeviceRealize parent_realize;
|
||||
ResettablePhases parent_phases;
|
||||
|
||||
CR16CCPUDef* cpu_def;
|
||||
};
|
||||
|
||||
#endif // CR16C_CPU_QOM_H
|
||||
236
target/cr16c/cpu.c
Normal file
236
target/cr16c/cpu.c
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "exec/cputlb.h"
|
||||
#include "accel/tcg/cpu-ops.h"
|
||||
#include "hw/resettable.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qom/object.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/dis-asm.h"
|
||||
|
||||
static void cr16c_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) {
|
||||
info->mach = bfd_arch_cr16c;
|
||||
info->endian = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
|
||||
static void cr16c_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState* cs = CPU(dev);
|
||||
CR16CCPUClass* ccc = CR16C_CPU_GET_CLASS(dev);
|
||||
Error *local_err = NULL;
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
cpu_reset(cs);
|
||||
|
||||
ccc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void cr16c_cpu_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
CPUState *cs = CPU(obj);
|
||||
CR16CCPU *cpu = CR16C_CPU(cs);
|
||||
CR16CCPUClass *ccc = CR16C_CPU_GET_CLASS(obj);
|
||||
CPUCR16CState* env = &cpu->env;
|
||||
|
||||
// TODO: Interrupts
|
||||
|
||||
if (ccc->parent_phases.hold) {
|
||||
ccc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
for(int i = 0; i < CR16C_REG_COUNT; i++) {
|
||||
env->r[i] = 0;
|
||||
}
|
||||
|
||||
env->r[0] = env->pc;
|
||||
env->r[1] = env->pc >> 16;
|
||||
|
||||
env->f_n = 0;
|
||||
env->f_z = 0;
|
||||
env->f_f = 0;
|
||||
env->f_l = 0;
|
||||
env->f_c = 0;
|
||||
// TODO: Rest of flags from PSR once implemented
|
||||
|
||||
env->pc = 0;
|
||||
}
|
||||
|
||||
static ObjectClass* cr16c_cpu_class_by_name(const char *cpu_model) {
|
||||
return object_class_by_name(CR16C_CPU_TYPE_NAME("SC14450C"));
|
||||
}
|
||||
|
||||
static bool cr16c_cpu_has_work(CPUState *cs)
|
||||
{
|
||||
CR16CCPU *cpu = CR16C_CPU(cs);
|
||||
CPUCR16CState *env = &cpu->env;
|
||||
|
||||
return (cs->interrupt_request & CPU_INTERRUPT_HARD) && cpu_interrupts_enabled(env);
|
||||
}
|
||||
|
||||
static void cr16c_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
{
|
||||
CPUCR16CState* env = cpu_env(cs);
|
||||
qemu_fprintf(f, "-- Special purpose registers --\n");
|
||||
qemu_fprintf(f, "PC: " TARGET_FMT_lx "\n", env->pc);
|
||||
qemu_fprintf(f, "RA: " TARGET_FMT_lx "\n", env->ra);
|
||||
qemu_fprintf(f, "SP: " TARGET_FMT_lx "\n", env->sp);
|
||||
|
||||
qemu_fprintf(f, "-- General purpose registers --\n");
|
||||
for(int i = 0; i < 10; i++) {
|
||||
qemu_fprintf(f, "R%d: %04x\n", i, env->r[i]);
|
||||
}
|
||||
for(int i = 10; i < CR16C_FIRST_32B_REG; i++) {
|
||||
qemu_fprintf(f, "R%d: %04x\n", i, env->r[i]);
|
||||
}
|
||||
for(int i = CR16C_FIRST_32B_REG; i < CR16C_REG_COUNT; i++) {
|
||||
qemu_fprintf(f, "R%d: %08x\n", i, env->r[i]);
|
||||
}
|
||||
|
||||
qemu_fprintf(f, "-- Flags --\n");
|
||||
qemu_fprintf(f, "N: %2d\n", env->f_n);
|
||||
qemu_fprintf(f, "Z: %2d\n", env->f_z);
|
||||
qemu_fprintf(f, "F: %2d\n", env->f_f);
|
||||
qemu_fprintf(f, "L: %2d\n", env->f_l);
|
||||
qemu_fprintf(f, "C: %2d\n", env->f_c);
|
||||
|
||||
qemu_fprintf(f, "\n");
|
||||
}
|
||||
|
||||
/* For debugging only, until tracing and exceptions are implemented */
|
||||
void cr16c_debug_dump_state(CPUState *cs) {
|
||||
cr16c_cpu_dump_state(cs, stdout, 0);
|
||||
}
|
||||
|
||||
static void cr16c_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
CR16CCPU *cpu = CR16C_CPU(cs);
|
||||
|
||||
cpu->env.pc = value;
|
||||
}
|
||||
|
||||
static int cr16c_cpu_mmu_index(CPUState *cs, bool ifetch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool cr16c_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
hwaddr cr16c_cpu_get_phys_page_debug(CPUState* cs, vaddr addr) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
bool cr16c_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
/* Copied from rx */
|
||||
uint32_t address, physical, prot;
|
||||
|
||||
/* Linear mapping */
|
||||
address = physical = addr & TARGET_PAGE_MASK;
|
||||
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#include "hw/core/sysemu-cpu-ops.h"
|
||||
|
||||
static const struct SysemuCPUOps cr16c_sysemu_ops = {
|
||||
.get_phys_page_debug = cr16c_cpu_get_phys_page_debug,
|
||||
.has_work = cr16c_cpu_has_work,
|
||||
};
|
||||
|
||||
static const struct TCGCPUOps cr16c_tcg_ops = {
|
||||
.initialize = cr16c_translate_init,
|
||||
.cpu_exec_interrupt = cr16c_cpu_exec_interrupt,
|
||||
.translate_code = cr16c_translate_code,
|
||||
.tlb_fill = cr16c_cpu_tlb_fill,
|
||||
.cpu_exec_halt = cr16c_cpu_has_work,
|
||||
};
|
||||
|
||||
|
||||
static void cr16c_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
CR16CCPUClass *acc = CR16C_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(cc);
|
||||
|
||||
device_class_set_parent_realize(dc, cr16c_cpu_realizefn, &acc->parent_realize);
|
||||
resettable_class_set_parent_phases(rc, NULL, cr16c_cpu_reset_hold, NULL, &acc->parent_phases);
|
||||
|
||||
cc->class_by_name = cr16c_cpu_class_by_name;
|
||||
|
||||
cc->dump_state = cr16c_cpu_dump_state;
|
||||
cc->set_pc = cr16c_cpu_set_pc;
|
||||
cc->mmu_index = cr16c_cpu_mmu_index;
|
||||
cc->sysemu_ops = &cr16c_sysemu_ops;
|
||||
cc->disas_set_info = cr16c_cpu_disas_set_info;
|
||||
cc->tcg_ops = &cr16c_tcg_ops;
|
||||
}
|
||||
|
||||
static const CR16CCPUDef cr16c_cpu_defs[] = {
|
||||
{
|
||||
.name = "SC14450C",
|
||||
.parent_microarch = TYPE_CR16C_CPU,
|
||||
}
|
||||
};
|
||||
|
||||
static void cr16c_cpu_cpudef_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
CR16CCPUClass* acc = CR16C_CPU_CLASS(oc);
|
||||
acc->cpu_def = data;
|
||||
}
|
||||
|
||||
static char* cr16c_cpu_type_name(const char* model_name)
|
||||
{
|
||||
return g_strdup_printf(CR16C_CPU_TYPE_NAME("%s"), model_name);
|
||||
}
|
||||
|
||||
static void cr16c_register_cpudef_type(const struct CR16CCPUDef* def)
|
||||
{
|
||||
char* cpu_model_name = cr16c_cpu_type_name(def->name);
|
||||
TypeInfo ti = {
|
||||
.name = cpu_model_name,
|
||||
.parent = def->parent_microarch,
|
||||
.class_init = cr16c_cpu_cpudef_class_init,
|
||||
.class_data = (void *)def,
|
||||
};
|
||||
|
||||
type_register_static(&ti);
|
||||
g_free(cpu_model_name);
|
||||
}
|
||||
|
||||
static const TypeInfo cr16c_cpu_arch = {
|
||||
.name = TYPE_CR16C_CPU,
|
||||
.parent = TYPE_CPU,
|
||||
.instance_size = sizeof(CR16CCPU),
|
||||
.abstract = true,
|
||||
.class_size = sizeof(CR16CCPUClass),
|
||||
.class_init = cr16c_cpu_class_init,
|
||||
};
|
||||
|
||||
static void cr16c_cpu_register_types(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
type_register_static(&cr16c_cpu_arch);
|
||||
for (i = 0; i < ARRAY_SIZE(cr16c_cpu_defs); i++) {
|
||||
cr16c_register_cpudef_type(&cr16c_cpu_defs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
type_init(cr16c_cpu_register_types)
|
||||
81
target/cr16c/cpu.h
Normal file
81
target/cr16c/cpu.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef QEMU_CR16C_CPU_H
|
||||
#define QEMU_CR16C_CPU_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu-qom.h"
|
||||
#include "exec/cpu-defs.h"
|
||||
|
||||
#define CR16C_REG_COUNT 14
|
||||
#define CR16C_FIRST_32B_REG 12
|
||||
|
||||
|
||||
struct CR16CCPUDef {
|
||||
const char* name;
|
||||
const char* parent_microarch;
|
||||
size_t core_type;
|
||||
size_t series_type;
|
||||
size_t clock_speed;
|
||||
};
|
||||
#define CR16C_CPU_TYPE_SUFFIX "-" TYPE_CR16C_CPU
|
||||
#define CR16C_CPU_TYPE_NAME(name) (name CR16C_CPU_TYPE_SUFFIX)
|
||||
#define CPU_RESOLVING_TYPE TYPE_CR16C_CPU
|
||||
|
||||
// TODO: Interrupt mask?
|
||||
// TODO: Instruction mask?
|
||||
|
||||
static const char cr16c_cpu_r_names[CR16C_REG_COUNT][8] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13"
|
||||
};
|
||||
|
||||
typedef struct CPUArchState {
|
||||
uint32_t pc;
|
||||
uint32_t ra;
|
||||
uint32_t sp;
|
||||
|
||||
uint32_t r[CR16C_REG_COUNT]; /* General purpose registers: 12x16-bit + 2x32-bit */
|
||||
|
||||
uint32_t f_n;
|
||||
uint32_t f_z;
|
||||
uint32_t f_f;
|
||||
uint32_t f_l;
|
||||
uint32_t f_c;
|
||||
} CPUCR16CState;
|
||||
|
||||
struct ArchCPU {
|
||||
/*< private >*/
|
||||
CPUState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
CPUCR16CState env;
|
||||
CPUNegativeOffsetState neg;
|
||||
};
|
||||
|
||||
int cr16c_print_insn(bfd_vma addr, disassemble_info *info);
|
||||
|
||||
static inline int cpu_interrupts_enabled(CPUCR16CState* env) {
|
||||
return false; // TODO: Interrupts
|
||||
}
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUCR16CState *env, vaddr *pc, uint64_t *cs_base, uint32_t *pflags) {
|
||||
*pc = env->pc;
|
||||
*cs_base = 0;
|
||||
*pflags = 0;
|
||||
}
|
||||
|
||||
void cr16c_translate_init(void);
|
||||
bool cr16c_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr);
|
||||
void cr16c_cpu_do_interrupt(CPUState *cpu);
|
||||
void cr16c_cpu_setint(void *opaque, int irq, int level);
|
||||
hwaddr cr16c_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
|
||||
int cr16c_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, int len, bool is_write);
|
||||
|
||||
void cr16c_debug_dump_state(CPUState *cs);
|
||||
|
||||
void cr16c_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb);
|
||||
|
||||
void cr16c_translate_code(CPUState *cs, TranslationBlock *tb,
|
||||
int *max_insns, vaddr pc, void *host_pc);
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
#endif // !QEMU_CR16C_CPU_H
|
||||
16
target/cr16c/helper.c
Normal file
16
target/cr16c/helper.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include "cpu.h"
|
||||
#include "exec/cpu-common.h"
|
||||
#include "qapi-types-run-state.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "system/runstate.h"
|
||||
|
||||
void helper_raise_illegal_instruction(CPUCR16CState* env) {
|
||||
qemu_printf("Illegal instruction, CPU state was:\n");
|
||||
cr16c_debug_dump_state(env_cpu(env));
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
|
||||
void helper_exit(CPUCR16CState *env) {
|
||||
exit(env->r[0]);
|
||||
}
|
||||
2
target/cr16c/helper.h
Normal file
2
target/cr16c/helper.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
DEF_HELPER_1(raise_illegal_instruction, void, env);
|
||||
DEF_HELPER_1(exit, void, env);
|
||||
68
target/cr16c/insn.decode
Normal file
68
target/cr16c/insn.decode
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
%param84_dest 56:4 48:4
|
||||
|
||||
@escape2_opc .... .... .... .... .... rd:4 rs1:4 rs2:4
|
||||
|
||||
@param4 .... .... .... imm:4
|
||||
@param4_20 .... .... rd:4 imm:20
|
||||
|
||||
@param44 .... .... rs:4 rd:4
|
||||
@param44_imm .... .... imm:4 rd:4
|
||||
@param44_cmp_imm .... .... imm:4 rs:4
|
||||
@param44_cmp .... .... rs2:4 rs1:4
|
||||
|
||||
@param84 .... .... cond:4 .... dest=%param84_dest
|
||||
|
||||
@param4_32 .... .... .... rd:4 imm:32
|
||||
|
||||
### Moves ###
|
||||
MOVB_imm4_16 0101 1000 .... .... @param44_imm
|
||||
MOVB_reg 0101 1001 .... .... @param44
|
||||
MOVD_imm20 0000 0101 .... .... .... .... .... .... @param4_20
|
||||
MOVD_imm32 0000 0000 0111 .... .... .... .... .... .... .... .... .... @param4_32
|
||||
MOVD_imm4_16 0101 0100 .... .... @param44_imm
|
||||
MOVD_reg 0101 0101 .... .... @param44
|
||||
MOVW_imm4_16 0101 1010 .... .... @param44_imm
|
||||
MOVW_reg 0101 1011 .... .... @param44
|
||||
MOVXB 0101 1100 .... .... @param44
|
||||
MOVXW 0101 1110 .... .... @param44
|
||||
MOVZB 0101 1101 .... .... @param44
|
||||
MOVZW 0101 1111 .... .... @param44
|
||||
|
||||
### Integer Arithmetic ###
|
||||
ADDB_imm4_16 0011 0000 .... .... @param44_imm
|
||||
ADDB_reg 0011 0001 .... .... @param44
|
||||
ADDCB_imm4_16 0011 0100 .... .... @param44_imm
|
||||
ADDCB_reg 0011 0101 .... .... @param44
|
||||
ADDCW_imm4_16 0011 0110 .... .... @param44_imm
|
||||
ADDCW_reg 0011 0111 .... .... @param44
|
||||
ADDD_imm20 0000 0100 .... .... .... .... .... .... @param4_20
|
||||
ADDD_imm32 0000 0000 0010 .... .... .... .... .... .... .... .... .... @param4_32
|
||||
ADDD_imm4_16 0110 0000 .... .... @param44_imm
|
||||
ADDD_rp 0110 0001 .... .... @param44
|
||||
ADDUB_imm4_16 0010 1100 .... .... @param44_imm
|
||||
ADDUB_reg 0010 1101 .... .... @param44
|
||||
ADDUW_imm4_16 0010 1110 .... .... @param44_imm
|
||||
ADDUW_reg 0010 1111 .... .... @param44
|
||||
ADDW_imm4_16 0011 0010 .... .... @param44_imm
|
||||
ADDW_reg 0011 0011 .... .... @param44
|
||||
MACQW 0000 0000 0001 0100 1101 .... .... .... @escape2_opc
|
||||
MACUW 0000 0000 0001 0100 1110 .... .... .... @escape2_opc
|
||||
MACSW 0000 0000 0001 0100 1111 .... .... .... @escape2_opc
|
||||
MULB_imm4_16 0110 0100 .... .... @param44_imm
|
||||
MULB_reg 0110 0101 .... .... @param44
|
||||
MULSB_reg 0000 1011 .... .... @param44
|
||||
MULSW_reg 0110 0010 .... .... @param44
|
||||
MULUW_reg 0110 0011 .... .... @param44
|
||||
MULW_imm4_16 0110 0110 .... .... @param44_imm
|
||||
MULW_reg 0110 0111 .... .... @param44
|
||||
|
||||
### Integer Comparison
|
||||
|
||||
CMPW_imm4_16 0101 0010 .... .... @param44_cmp_imm
|
||||
CMPW_reg 0101 0011 .... .... @param44_cmp
|
||||
|
||||
### Jumps and Linkeage
|
||||
|
||||
BRCOND_disp8 0001 .... .... .... @param84
|
||||
|
||||
EXCP 0000 0000 1100 .... @param4
|
||||
20
target/cr16c/machine.c
Normal file
20
target/cr16c/machine.c
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "cpu.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
const VMStateDescription vms_cr16c_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(env.sp, CR16CCPU),
|
||||
VMSTATE_UINT32(env.ra, CR16CCPU),
|
||||
VMSTATE_UINT32(env.pc, CR16CCPU),
|
||||
VMSTATE_UINT32_ARRAY(env.r, CR16CCPU, CR16C_REG_COUNT),
|
||||
VMSTATE_UINT32(env.f_n, CR16CCPU),
|
||||
VMSTATE_UINT32(env.f_z, CR16CCPU),
|
||||
VMSTATE_UINT32(env.f_f, CR16CCPU),
|
||||
VMSTATE_UINT32(env.f_l, CR16CCPU),
|
||||
VMSTATE_UINT32(env.f_c, CR16CCPU),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
17
target/cr16c/meson.build
Normal file
17
target/cr16c/meson.build
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
gen = [
|
||||
decodetree.process('insn.decode', extra_args: '--varinsnwidth=64'),
|
||||
]
|
||||
|
||||
cr16c_ss = ss.source_set()
|
||||
cr16c_ss.add(gen)
|
||||
cr16c_ss.add(files(
|
||||
'cpu.c',
|
||||
'helper.c',
|
||||
'translate.c',
|
||||
))
|
||||
|
||||
cr16c_system_ss = ss.source_set()
|
||||
cr16c_system_ss.add(files('machine.c'))
|
||||
|
||||
target_arch += {'cr16c': cr16c_ss}
|
||||
target_system_arch += {'cr16c': cr16c_system_ss}
|
||||
805
target/cr16c/translate.c
Normal file
805
target/cr16c/translate.c
Normal file
|
|
@ -0,0 +1,805 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "qemu/compiler.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/translator.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "qemu/typedefs.h"
|
||||
#include "tcg/tcg-cond.h"
|
||||
#include "tcg/tcg-op-common.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/helper-gen.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
#define HELPER_H "helper.h"
|
||||
#include "exec/helper-info.c.inc"
|
||||
#undef HELPER_H
|
||||
|
||||
enum {
|
||||
CR16C_COND_EQ,
|
||||
CR16C_COND_NE,
|
||||
CR16C_COND_CS,
|
||||
CR16C_COND_CC,
|
||||
CR16C_COND_HI,
|
||||
CR16C_COND_LS,
|
||||
CR16C_COND_GT,
|
||||
CR16C_COND_LE,
|
||||
CR16C_COND_FS,
|
||||
CR16C_COND_FC,
|
||||
CR16C_COND_LO,
|
||||
CR16C_COND_HS,
|
||||
CR16C_COND_LT,
|
||||
CR16C_COND_GE,
|
||||
CR16C_COND_ALWAYS,
|
||||
CR16C_COND_UC,
|
||||
};
|
||||
|
||||
typedef struct DisasContext {
|
||||
DisasContextBase base;
|
||||
CPUCR16CState* env;
|
||||
} DisasContext;
|
||||
|
||||
|
||||
static TCGv pc;
|
||||
static TCGv sp;
|
||||
static TCGv f_n;
|
||||
static TCGv f_z;
|
||||
static TCGv f_f;
|
||||
static TCGv f_l;
|
||||
static TCGv f_c;
|
||||
static TCGv r[CR16C_REG_COUNT];
|
||||
|
||||
|
||||
static void cr16c_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) {
|
||||
DisasContext* ctx = container_of(dcbase, DisasContext, base);
|
||||
CPUCR16CState* env = cpu_env(cs);
|
||||
|
||||
ctx->env = env;
|
||||
}
|
||||
|
||||
static void cr16c_tr_tb_start(DisasContextBase *base, CPUState *cs) { }
|
||||
|
||||
static void cr16c_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) {
|
||||
DisasContext* ctx = container_of(dcbase, DisasContext, base);
|
||||
|
||||
tcg_gen_insn_start(ctx->base.pc_next);
|
||||
}
|
||||
|
||||
static uint64_t decode_load_bytes(DisasContext *ctx, uint64_t insn, int i, int n) {
|
||||
for(; i < n; i+=2) {
|
||||
insn |= (uint64_t)translator_lduw(ctx->env, &ctx->base, ctx->base.pc_next) << (48 - i * 8);
|
||||
ctx->base.pc_next += 2;
|
||||
}
|
||||
if (i == n)
|
||||
return insn;
|
||||
else {
|
||||
gen_helper_raise_illegal_instruction(tcg_env);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Include generated decodetree function declarations
|
||||
#include "decode-insn.c.inc"
|
||||
|
||||
static uint32_t get_imm4(DisasContext* ctx, uint8_t imm) {
|
||||
if (imm == 11) {
|
||||
uint16_t imm_esc = cpu_lduw_code(ctx->env, ctx->base.pc_next);
|
||||
ctx->base.pc_next += 2;
|
||||
return imm_esc;
|
||||
}
|
||||
else if (imm == 9) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return imm;
|
||||
}
|
||||
}
|
||||
|
||||
static bool trans_MOVB_imm4_16(DisasContext* ctx, arg_MOVB_imm4_16* a) {
|
||||
uint32_t imm = get_imm4(ctx, a->imm) & 0xFF;
|
||||
|
||||
tcg_gen_andi_i32(r[a->rd], r[a->rd], 0xFF00);
|
||||
tcg_gen_ori_i32(r[a->rd], r[a->rd], imm);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVB_reg(DisasContext* ctx, arg_MOVB_reg* a) {
|
||||
tcg_gen_deposit_i32(r[a->rd], r[a->rd], r[a->rs], 0, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVD_imm20(DisasContext* ctx, arg_MOVD_imm20* a) {
|
||||
tcg_gen_movi_i32(r[a->rd], a->imm);
|
||||
tcg_gen_movi_i32(r[a->rd + 1], a->imm >> 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVD_imm32(DisasContext* ctx, arg_MOVD_imm32* a) {
|
||||
tcg_gen_movi_i32(r[a->rd], a->imm);
|
||||
tcg_gen_movi_i32(r[a->rd + 1], a->imm >> 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVD_imm4_16(DisasContext* ctx, arg_MOVD_imm4_16* a) {
|
||||
uint32_t imm = get_imm4(ctx, a->imm);
|
||||
|
||||
tcg_gen_movi_i32(r[a->rd], imm);
|
||||
tcg_gen_movi_i32(r[a->rd + 1], 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVD_reg(DisasContext* ctx, arg_MOVD_reg* a) {
|
||||
tcg_gen_mov_i32(r[a->rd], r[a->rs]);
|
||||
tcg_gen_mov_i32(r[a->rd+1], r[a->rs+1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVW_imm4_16(DisasContext* ctx, arg_MOVW_imm4_16* a) {
|
||||
uint32_t imm = get_imm4(ctx, a->imm) & 0xFFFF;
|
||||
tcg_gen_movi_i32(r[a->rd], imm);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVW_reg(DisasContext* ctx, arg_MOVW_reg* a) {
|
||||
tcg_gen_mov_i32(r[a->rd], r[a->rs]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVXB(DisasContext* ctx, arg_MOVXB* a) {
|
||||
tcg_gen_ext8s_i32(r[a->rd], r[a->rs]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVXW(DisasContext* ctx, arg_MOVXW* a) {
|
||||
tcg_gen_ext16s_i32(r[a->rd], r[a->rs]);
|
||||
tcg_gen_shri_i32(r[a->rd+1], r[a->rd], 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVZB(DisasContext* ctx, arg_MOVZB* a) {
|
||||
tcg_gen_ext8u_i32(r[a->rd], r[a->rs]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MOVZW(DisasContext* ctx, arg_MOVZW* a) {
|
||||
tcg_gen_mov_i32(r[a->rd], r[a->rs]);
|
||||
tcg_gen_movi_i32(r[a->rd+1], 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Integer Arithmetic */
|
||||
|
||||
static bool gen_ADDB_imm4_16(DisasContext* ctx, TCGv reg, uint16_t imm_raw, bool plus_carry) {
|
||||
uint32_t imm = get_imm4(ctx, imm_raw) & 0xFF;
|
||||
TCGv temp = tcg_temp_new();
|
||||
|
||||
tcg_gen_andi_i32(temp, reg, 0xFF);
|
||||
tcg_gen_addi_i32(temp, temp, imm);
|
||||
|
||||
if(plus_carry) {
|
||||
tcg_gen_andi_i32(f_c, f_c, 1);
|
||||
tcg_gen_add_i32(temp, temp, f_c);
|
||||
}
|
||||
|
||||
/* Carry flag */
|
||||
tcg_gen_shri_i32(f_c, temp, 8);
|
||||
|
||||
/* Overflow flag */
|
||||
tcg_gen_xor_i32(f_f, temp, reg);
|
||||
if(imm & 0x80) {
|
||||
tcg_gen_and_i32(f_f, f_f, reg);
|
||||
}
|
||||
else {
|
||||
tcg_gen_andc_i32(f_f, f_f, reg);
|
||||
}
|
||||
tcg_gen_shri_i32(f_f, f_f, 7);
|
||||
|
||||
tcg_gen_deposit_i32(reg, reg, temp, 0, 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_ADDB_reg(DisasContext* ctx, TCGv reg1, TCGv reg2, bool plus_carry) {
|
||||
TCGv temp1 = tcg_temp_new_i32();
|
||||
TCGv temp2 = tcg_temp_new_i32();
|
||||
TCGv tempf_f = tcg_temp_new_i32();
|
||||
|
||||
/* If bit 8 shouldn't change without signed overflow */
|
||||
tcg_gen_eqv_i32(tempf_f, reg1, reg2);
|
||||
|
||||
/* Clear potential top bits */
|
||||
tcg_gen_andi_i32(temp1, reg1, 0x00FF);
|
||||
tcg_gen_andi_i32(temp2, reg2, 0x00FF);
|
||||
|
||||
tcg_gen_add_i32(temp1, temp1, temp2);
|
||||
|
||||
if(plus_carry) {
|
||||
tcg_gen_andi_i32(f_c, f_c, 1);
|
||||
tcg_gen_add_i32(temp1, temp1, f_c);
|
||||
}
|
||||
|
||||
tcg_gen_deposit_i32(reg1, reg1, temp1, 0, 8);
|
||||
|
||||
/* Carry flag */
|
||||
tcg_gen_shri_i32(f_c, temp1, 8);
|
||||
|
||||
/* Overflow flag */
|
||||
tcg_gen_xor_i32(f_f, reg1, reg2);
|
||||
tcg_gen_and_i32(f_f, f_f, tempf_f);
|
||||
tcg_gen_shri_i32(f_f, f_f, 7);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_ADDW_imm4_16(DisasContext *ctx, TCGv reg1, uint16_t imm_raw, bool plus_carry) {
|
||||
uint32_t imm = get_imm4(ctx, imm_raw) & 0xFFFF;
|
||||
|
||||
TCGv temp = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_andi_i32(reg1, reg1, 0xFFFF);
|
||||
|
||||
tcg_gen_addi_i32(temp, reg1, imm);
|
||||
|
||||
|
||||
if(plus_carry) {
|
||||
tcg_gen_andi_i32(f_c, f_c, 1);
|
||||
tcg_gen_add_i32(temp, temp, f_c);
|
||||
}
|
||||
|
||||
/* Carry flag */
|
||||
tcg_gen_shri_i32(f_c, temp, 16);
|
||||
|
||||
/* Overflow flag */
|
||||
tcg_gen_xor_i32(f_f, temp, reg1);
|
||||
if(imm & 0x8000) {
|
||||
tcg_gen_and_i32(f_f, f_f, reg1);
|
||||
}
|
||||
else {
|
||||
tcg_gen_andc_i32(f_f, f_f, reg1);
|
||||
}
|
||||
tcg_gen_shri_i32(f_f, f_f, 15);
|
||||
|
||||
tcg_gen_mov_i32(reg1, temp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_ADDW_reg(DisasContext* ctx, TCGv reg1, TCGv reg2, bool plus_carry) {
|
||||
TCGv tempf_f = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_eqv_i32(tempf_f, reg1, reg2);
|
||||
|
||||
tcg_gen_andi_i32(reg1, reg1, 0xFFFF);
|
||||
tcg_gen_andi_i32(reg2, reg2, 0xFFFF);
|
||||
|
||||
tcg_gen_add_i32(reg1, reg1, reg2);
|
||||
|
||||
if(plus_carry) {
|
||||
tcg_gen_andi_i32(f_c, f_c, 1);
|
||||
tcg_gen_add_i32(reg1, reg1, f_c);
|
||||
}
|
||||
|
||||
/* Carry flag */
|
||||
tcg_gen_shri_i32(f_c, reg1, 16);
|
||||
|
||||
/* Overflow flag */
|
||||
tcg_gen_xor_i32(f_f, reg1, reg2);
|
||||
tcg_gen_and_i32(f_f, f_f, tempf_f);
|
||||
tcg_gen_shri_i32(f_f, f_f, 15);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDB_imm4_16(DisasContext *ctx, arg_ADDB_imm4_16 *a) {
|
||||
return gen_ADDB_imm4_16(ctx, r[a->rd], a->imm, false);
|
||||
}
|
||||
|
||||
static bool trans_ADDB_reg(DisasContext *ctx, arg_ADDB_reg *a) {
|
||||
return gen_ADDB_reg(ctx, r[a->rd], r[a->rs], false);
|
||||
}
|
||||
|
||||
static bool trans_ADDCB_imm4_16(DisasContext *ctx, arg_ADDCB_imm4_16 *a) {
|
||||
return gen_ADDB_imm4_16(ctx, r[a->rd], a->imm, true);
|
||||
}
|
||||
|
||||
static bool trans_ADDCB_reg(DisasContext *ctx, arg_ADDCB_reg *a) {
|
||||
return gen_ADDB_reg(ctx, r[a->rd], r[a->rs], true);
|
||||
}
|
||||
|
||||
static bool trans_ADDCW_imm4_16(DisasContext *ctx, arg_ADDCW_imm4_16 *a) {
|
||||
return gen_ADDW_imm4_16(ctx, r[a->rd], a->imm, true);
|
||||
}
|
||||
|
||||
static bool trans_ADDCW_reg(DisasContext *ctx, arg_ADDCW_reg *a) {
|
||||
return gen_ADDW_reg(ctx, r[a->rd], r[a->rs], true);
|
||||
}
|
||||
|
||||
static bool gen_ADDD_imm(TCGv regl, TCGv regh, uint32_t imm) {
|
||||
TCGv_i64 temp = tcg_temp_new_i64();
|
||||
|
||||
/* Move param registers into 64 bit temporary */
|
||||
tcg_gen_shli_i32(regh, regh, 16);
|
||||
tcg_gen_andi_i32(regl, regl, 0xFFFF);
|
||||
tcg_gen_or_i32(regl, regh, regl);
|
||||
tcg_gen_extu_i32_i64(temp, regl);
|
||||
|
||||
tcg_gen_addi_i64(temp, temp, imm);
|
||||
tcg_gen_extrl_i64_i32(regl, temp);
|
||||
|
||||
/* Carry flag */
|
||||
tcg_gen_extrh_i64_i32(f_c, temp);
|
||||
|
||||
/* Overflow flag */
|
||||
if (imm & 0x80000000) {
|
||||
tcg_gen_andc_i32(f_f, regh, regl);
|
||||
}
|
||||
else {
|
||||
tcg_gen_andc_i32(f_f, regl, regh);
|
||||
}
|
||||
tcg_gen_shri_i32(f_f, f_f, 31);
|
||||
|
||||
tcg_gen_shri_i32(regh, regl, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDD_imm20(DisasContext* ctx, arg_ADDD_imm20 *a) {
|
||||
return gen_ADDD_imm(r[a->rd], r[a->rd+1], a->imm);
|
||||
}
|
||||
|
||||
static bool trans_ADDD_imm32(DisasContext *ctx, arg_ADDD_imm32 *a) {
|
||||
return gen_ADDD_imm(r[a->rd], r[a->rd+1], a->imm);
|
||||
}
|
||||
|
||||
static bool trans_ADDD_imm4_16(DisasContext *ctx, arg_ADDD_imm4_16 *a) {
|
||||
uint32_t imm = get_imm4(ctx, a->imm);
|
||||
return gen_ADDD_imm(r[a->rd], r[a->rd+1], imm);
|
||||
}
|
||||
|
||||
static bool trans_ADDD_rp(DisasContext *ctx, arg_ADDD_rp *a) {
|
||||
TCGv rdl = r[a->rd];
|
||||
TCGv rdh = r[a->rd+1];
|
||||
TCGv rsl = r[a->rs];
|
||||
TCGv rsh = r[a->rs+1];
|
||||
TCGv temp2_32 = tcg_temp_new_i32();
|
||||
TCGv_i64 temp1 = tcg_temp_new_i64();
|
||||
TCGv_i64 temp2 = tcg_temp_new_i64();
|
||||
|
||||
/* Move param registers into 64 bit temporaries */
|
||||
tcg_gen_shli_i32(temp2_32, rsh, 16);
|
||||
tcg_gen_andi_i32(rsl, rsl, 0xFFFF);
|
||||
tcg_gen_or_i32(temp2_32, temp2_32, rsl);
|
||||
tcg_gen_extu_i32_i64(temp2, temp2_32);
|
||||
|
||||
tcg_gen_shli_i32(rdh, rdh, 16);
|
||||
tcg_gen_andi_i32(rdl, rdl, 0xFFFF);
|
||||
tcg_gen_or_i32(rdl, rdh, rdl);
|
||||
tcg_gen_extu_i32_i64(temp1, rdl);
|
||||
|
||||
/* Prepare overflow flag */
|
||||
tcg_gen_xor_i32(f_f, rdl, temp2_32);
|
||||
|
||||
tcg_gen_add_i64(temp1, temp1, temp2);
|
||||
tcg_gen_extrl_i64_i32(rdl, temp1);
|
||||
tcg_gen_shri_i32(rdh, rdl, 16);
|
||||
|
||||
/* Carry flag */
|
||||
tcg_gen_extrh_i64_i32(f_c, temp1);
|
||||
|
||||
/* Overflow flag */
|
||||
tcg_gen_xor_i32(temp2_32, temp2_32, rdl);
|
||||
tcg_gen_andc_i32(f_f, temp2_32, f_f);
|
||||
tcg_gen_shri_i32(f_f, f_f, 31);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDUB_imm4_16(DisasContext *ctx, arg_ADDUB_imm4_16 *a) {
|
||||
TCGv temp = tcg_temp_new_i32();
|
||||
uint16_t imm = a->imm;
|
||||
|
||||
tcg_gen_addi_i32(temp, r[a->rd], imm);
|
||||
tcg_gen_deposit_i32(r[a->rd], r[a->rd], temp, 0, 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDUB_reg(DisasContext *ctx, arg_ADDUB_reg *a) {
|
||||
TCGv temp = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_add_i32(temp, r[a->rd], r[a->rs]);
|
||||
tcg_gen_deposit_i32(r[a->rd], r[a->rd], temp, 0, 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDUW_imm4_16(DisasContext *ctx, arg_ADDUW_imm4_16 *a) {
|
||||
uint32_t imm = get_imm4(ctx, a->imm) & 0xFFFF;
|
||||
|
||||
tcg_gen_addi_i32(r[a->rd], r[a->rd], imm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDUW_reg(DisasContext *ctx, arg_ADDUW_reg *a) {
|
||||
tcg_gen_add_i32(r[a->rd], r[a->rd], r[a->rs]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDW_imm4_16(DisasContext *ctx, arg_ADDW_imm4_16 *a) {
|
||||
return gen_ADDW_imm4_16(ctx, r[a->rd], a->imm, false);
|
||||
}
|
||||
|
||||
static bool trans_ADDW_reg(DisasContext *ctx, arg_ADDW_reg *a) {
|
||||
return gen_ADDW_reg(ctx, r[a->rd], r[a->rs], false);
|
||||
}
|
||||
|
||||
/* TODO: This is quite certainly a bad implementation */
|
||||
static bool trans_MACQW(DisasContext *ctx, arg_MACQW *a) {
|
||||
TCGv temp_l = tcg_temp_new_i32();
|
||||
TCGv temp_h = tcg_temp_new_i32();
|
||||
TCGv temp_mul = temp_l;
|
||||
TCGv temp_mul_sign = temp_h;
|
||||
TCGv temp_neg = tcg_temp_new_i32();
|
||||
TCGv temp_dest = tcg_temp_new_i32();
|
||||
TCGv temp_of = temp_mul_sign;
|
||||
TCGv temp_of2 = tcg_temp_new_i32();
|
||||
|
||||
|
||||
tcg_gen_andi_i32(temp_l, r[a->rs1], 0x7FFF);
|
||||
tcg_gen_shli_i32(temp_l, temp_l, 1);
|
||||
tcg_gen_andi_i32(temp_h, r[a->rs2], 0x7FFF);
|
||||
|
||||
tcg_gen_mul_i32(temp_mul, temp_l, temp_h);
|
||||
|
||||
/* Replace with negative value in two's complement if result is negative */
|
||||
tcg_gen_neg_i32(temp_neg, temp_mul);
|
||||
tcg_gen_xor_i32(temp_mul_sign, r[a->rs1], r[a->rs2]);
|
||||
tcg_gen_movcond_i32(TCG_COND_TSTNE, temp_mul, temp_mul_sign, tcg_constant_i32(0x8000), temp_neg, temp_mul);
|
||||
|
||||
/* Load destination register */
|
||||
tcg_gen_shli_i32(temp_dest, r[a->rd+1], 16);
|
||||
tcg_gen_andi_i32(r[a->rd], r[a->rd], 0xFFFF);
|
||||
tcg_gen_or_i32(temp_dest, temp_dest, r[a->rd]);
|
||||
|
||||
/* Convert dest to two's complement */
|
||||
tcg_gen_andi_i32(temp_neg, temp_dest, 0x7FFFFFFF);
|
||||
tcg_gen_neg_i32(temp_neg, temp_neg);
|
||||
tcg_gen_movcond_i32(TCG_COND_TSTNE, temp_dest, temp_dest, tcg_constant_i32(0x80000000), temp_neg, temp_dest);
|
||||
|
||||
/* If sign change needs to be checked */
|
||||
tcg_gen_eqv_i32(temp_of, temp_dest, temp_mul);
|
||||
|
||||
/* Add to the result register pair */
|
||||
tcg_gen_add_i32(temp_dest, temp_dest, temp_mul);
|
||||
|
||||
/* Calculate overflow flag */
|
||||
tcg_gen_xor_i32(temp_of2, temp_dest, temp_mul);
|
||||
tcg_gen_and_i32(temp_of, temp_of, temp_of2);
|
||||
|
||||
/* Convert back from two's complement */
|
||||
tcg_gen_sub_i32(temp_neg, tcg_constant_i32(0x8000), temp_dest);
|
||||
tcg_gen_movcond_i32(TCG_COND_TSTNE, temp_dest, temp_dest, tcg_constant_i32(0x80000000), temp_neg, temp_dest);
|
||||
|
||||
/* Handle overflow */
|
||||
tcg_gen_movcond_i32(TCG_COND_TSTNE, temp_of2, r[a->rd+1], tcg_constant_i32(0x8000), tcg_constant_i32(0xFFFFFFFF), tcg_constant_i32(0x7FFFFFFF));
|
||||
tcg_gen_movcond_i32(TCG_COND_TSTNE, temp_dest, temp_of, tcg_constant_i32(0x80000000), temp_of2, temp_dest);
|
||||
|
||||
tcg_gen_andi_i32(r[a->rd], temp_dest, 0xFFFF);
|
||||
tcg_gen_shri_i32(r[a->rd+1], temp_dest, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MACUW(DisasContext *ctx, arg_MACUW *a) {
|
||||
TCGv rdl = r[a->rd];
|
||||
TCGv rdh = r[a->rd+1];
|
||||
TCGv temp = tcg_temp_new_i32();
|
||||
|
||||
/* Zero potential junk in higher bits */
|
||||
tcg_gen_andi_i32(r[a->rs1], r[a->rs1], 0xFFFF);
|
||||
tcg_gen_andi_i32(r[a->rs2], r[a->rs2], 0xFFFF);
|
||||
|
||||
tcg_gen_mul_i32(temp, r[a->rs1], r[a->rs2]);
|
||||
|
||||
tcg_gen_shli_i32(rdh, rdh, 16);
|
||||
tcg_gen_andi_i32(rdl, rdl, 0xFFFF);
|
||||
tcg_gen_or_i32(rdl, rdl, rdh);
|
||||
|
||||
tcg_gen_add2_i32(rdl, temp, rdl, tcg_constant_i32(0), temp, tcg_constant_i32(0));
|
||||
|
||||
tcg_gen_movcond_i32(TCG_COND_NE, rdl, temp, tcg_constant_i32(0), tcg_constant_i32(0xFFFFFFFF), rdl);
|
||||
tcg_gen_shri_i32(rdh, rdl, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MACSW(DisasContext *ctx, arg_MACSW *a) {
|
||||
TCGv rdl = r[a->rd];
|
||||
TCGv rdh = r[a->rd+1];
|
||||
TCGv temp = tcg_temp_new_i32();
|
||||
TCGv temp_of = tcg_temp_new_i32();
|
||||
TCGv temp_of2 = tcg_temp_new_i32();
|
||||
|
||||
/* Zero potential junk in higher bits */
|
||||
tcg_gen_ext16s_i32(r[a->rs1], r[a->rs1]);
|
||||
tcg_gen_ext16s_i32(r[a->rs2], r[a->rs2]);
|
||||
|
||||
tcg_gen_mul_i32(temp, r[a->rs1], r[a->rs2]);
|
||||
|
||||
tcg_gen_shli_i32(rdh, rdh, 16);
|
||||
tcg_gen_andi_i32(rdl, rdl, 0xFFFF);
|
||||
tcg_gen_or_i32(rdl, rdl, rdh);
|
||||
|
||||
tcg_gen_eqv_i32(temp_of, rdl, temp);
|
||||
|
||||
tcg_gen_add_i32(rdl, rdl, temp);
|
||||
|
||||
tcg_gen_xor_i32(temp_of2, rdl, temp);
|
||||
tcg_gen_and_i32(temp_of, temp_of, temp_of2);
|
||||
|
||||
tcg_gen_movcond_i32(TCG_COND_TSTNE, temp, temp, tcg_constant_i32(0x8000), tcg_constant_i32(0x80000000), tcg_constant_i32(0x7FFFFFFF));
|
||||
tcg_gen_movcond_i32(TCG_COND_TSTNE, rdl, temp_of, tcg_constant_i32(0x80000000), temp, rdl);
|
||||
tcg_gen_shri_i32(rdh, rdl, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MULB_imm4_16(DisasContext *ctx, arg_MULB_imm4_16 *a) {
|
||||
int32_t imm = (get_imm4(ctx, a->imm) << 24) >> 24;
|
||||
TCGv_i32 temp = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_andi_i32(temp, r[a->rd], 0xFF);
|
||||
tcg_gen_muli_i32(temp, temp, imm);
|
||||
tcg_gen_deposit_i32(r[a->rd], r[a->rd], temp, 0, 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MULB_reg(DisasContext *ctx, arg_MULB_reg *a) {
|
||||
TCGv_i32 temp1 = tcg_temp_new_i32();
|
||||
TCGv_i32 temp2 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_andi_i32(temp1, r[a->rd], 0xFF);
|
||||
tcg_gen_andi_i32(temp2, r[a->rs], 0xFF);
|
||||
tcg_gen_mul_i32(temp1, temp1, temp2);
|
||||
tcg_gen_deposit_i32(r[a->rd], r[a->rd], temp1, 0, 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MULSB_reg(DisasContext *ctx, arg_MULSB_reg *a) {
|
||||
TCGv_i32 temp = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_ext8s_i32(r[a->rd], r[a->rd]);
|
||||
tcg_gen_ext8s_i32(temp, r[a->rs]);
|
||||
tcg_gen_mul_i32(r[a->rd], r[a->rd], temp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MULSW_reg(DisasContext *ctx, arg_MULSW_reg *a) {
|
||||
TCGv_i32 rdl = r[a->rd];
|
||||
TCGv_i32 rdh = r[a->rd+1];
|
||||
|
||||
tcg_gen_ext16s_i32(rdl, rdl);
|
||||
tcg_gen_ext16s_i32(r[a->rs], r[a->rs]);
|
||||
tcg_gen_mul_i32(rdl, rdl, r[a->rs]);
|
||||
tcg_gen_shri_i32(rdh, rdl, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MULUW_reg(DisasContext *ctx, arg_MULUW_reg *a) {
|
||||
TCGv_i32 rdl = r[a->rd];
|
||||
TCGv_i32 rdh = r[a->rd+1];
|
||||
|
||||
tcg_gen_andi_i32(rdl, rdl, 0xFFFF);
|
||||
tcg_gen_andi_i32(r[a->rs], r[a->rs], 0xFFFF);
|
||||
tcg_gen_mul_i32(rdl, rdl, r[a->rs]);
|
||||
tcg_gen_shri_i32(rdh, rdl, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MULW_imm4_16(DisasContext *ctx, arg_MULW_imm4_16 *a) {
|
||||
int32_t imm = get_imm4(ctx, a->imm);
|
||||
|
||||
tcg_gen_muli_i32(r[a->rd], r[a->rd], imm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_MULW_reg(DisasContext *ctx, arg_MULW_reg *a) {
|
||||
tcg_gen_mul_i32(r[a->rd], r[a->rd], r[a->rs]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Integer Comparison */
|
||||
|
||||
static bool trans_CMPW_imm4_16(DisasContext *ctx, arg_CMPW_imm4_16 *a) {
|
||||
uint32_t imm = get_imm4(ctx, a->imm) & 0xFFFF;
|
||||
|
||||
tcg_gen_andi_i32(r[a->rs], r[a->rs], 0xFFFF);
|
||||
|
||||
tcg_gen_setcondi_i32(TCG_COND_EQ, f_z, r[a->rs], imm);
|
||||
tcg_gen_setcondi_i32(TCG_COND_LT, f_n, r[a->rs], imm);
|
||||
tcg_gen_setcondi_i32(TCG_COND_LTU, f_l, r[a->rs], imm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_CMPW_reg(DisasContext *ctx, arg_CMPW_reg *a) {
|
||||
tcg_gen_andi_i32(r[a->rs1], r[a->rs1], 0xFFFF);
|
||||
tcg_gen_andi_i32(r[a->rs2], r[a->rs1], 0xFFFF);
|
||||
|
||||
tcg_gen_setcond_i32(TCG_COND_EQ, f_z, r[a->rs1], r[a->rs2]);
|
||||
tcg_gen_setcond_i32(TCG_COND_LT, f_n, r[a->rs1], r[a->rs2]);
|
||||
tcg_gen_setcond_i32(TCG_COND_LTU, f_l, r[a->rs1], r[a->rs2]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Jumps and Linkage */
|
||||
|
||||
/* For now this instruction is abused as semihosting instruction for tests */
|
||||
static bool trans_EXCP(DisasContext *ctx, arg_EXCP *a) {
|
||||
gen_helper_exit(tcg_env);
|
||||
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint16_t get_disp(DisasContext* ctx, uint8_t disp) {
|
||||
if (disp == 0x80) {
|
||||
uint16_t disp_esc = cpu_lduw_code(ctx->env, ctx->base.pc_next) >> 1;
|
||||
ctx->base.pc_next += 2;
|
||||
return disp_esc;
|
||||
}
|
||||
else {
|
||||
return disp;
|
||||
}
|
||||
};
|
||||
|
||||
static bool trans_BRCOND_disp8(DisasContext* ctx, arg_BRCOND_disp8 *a) {
|
||||
TCGLabel* l = gen_new_label();
|
||||
TCGv temp;
|
||||
uint32_t pc_this = ctx->base.pc_next - 2;
|
||||
uint16_t disp = get_disp(ctx, a->dest);
|
||||
uint32_t dest = pc_this + disp*2;
|
||||
|
||||
/* Flags may have higher bits set */
|
||||
tcg_gen_andi_i32(f_n, f_n, 1);
|
||||
tcg_gen_andi_i32(f_z, f_z, 1);
|
||||
tcg_gen_andi_i32(f_f, f_f, 1);
|
||||
tcg_gen_andi_i32(f_l, f_l, 1);
|
||||
tcg_gen_andi_i32(f_c, f_c, 1);
|
||||
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
switch (a->cond) {
|
||||
case CR16C_COND_EQ:
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, f_z, 0, l);
|
||||
break;
|
||||
case CR16C_COND_NE:
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, f_z, 0, l);
|
||||
break;
|
||||
case CR16C_COND_CS:
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, f_c, 0, l);
|
||||
break;
|
||||
case CR16C_COND_CC:
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, f_c, 0, l);
|
||||
break;
|
||||
case CR16C_COND_HI:
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, f_l, 0, l);
|
||||
break;
|
||||
case CR16C_COND_LS:
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, f_l, 0, l);
|
||||
break;
|
||||
case CR16C_COND_GT:
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, f_l, 0, l);
|
||||
break;
|
||||
case CR16C_COND_LE:
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, f_l, 0, l);
|
||||
break;
|
||||
case CR16C_COND_FS:
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, f_f, 0, l);
|
||||
break;
|
||||
case CR16C_COND_FC:
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, f_f, 0, l);
|
||||
break;
|
||||
case CR16C_COND_LO:
|
||||
temp = tcg_temp_new_i32();
|
||||
tcg_gen_and_i32(temp, f_z, f_l);
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l);
|
||||
break;
|
||||
case CR16C_COND_HS:
|
||||
temp = tcg_temp_new_i32();
|
||||
tcg_gen_and_i32(temp, f_z, f_l);
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l);
|
||||
break;
|
||||
case CR16C_COND_LT:
|
||||
temp = tcg_temp_new_i32();
|
||||
tcg_gen_and_i32(temp, f_z, f_l);
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l);
|
||||
break;
|
||||
case CR16C_COND_GE:
|
||||
temp = tcg_temp_new_i32();
|
||||
tcg_gen_and_i32(temp, f_z, f_n);
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l);
|
||||
break;
|
||||
}
|
||||
|
||||
tcg_gen_movi_i32(f_f, 1);
|
||||
tcg_gen_movi_i32(pc, dest);
|
||||
tcg_gen_exit_tb(ctx->base.tb, 0);
|
||||
|
||||
gen_set_label(l);
|
||||
|
||||
tcg_gen_movi_i32(f_c, 1);
|
||||
tcg_gen_movi_i32(pc, ctx->base.pc_next);
|
||||
tcg_gen_exit_tb(ctx->base.tb, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void cr16c_tr_translate_insn(DisasContextBase *base, CPUState *cs) {
|
||||
DisasContext *ctx = container_of(base, DisasContext, base);
|
||||
|
||||
tcg_gen_movi_tl(pc, ctx->base.pc_next);
|
||||
|
||||
uint64_t insn = decode_load(ctx);
|
||||
if(!decode(ctx, insn)) {
|
||||
// TOOD: Illegal Instruction
|
||||
gen_helper_raise_illegal_instruction(tcg_env);
|
||||
base->is_jmp = DISAS_NORETURN;
|
||||
base->pc_next += 2;
|
||||
};
|
||||
}
|
||||
|
||||
static void cr16c_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) {
|
||||
DisasContext* ctx = container_of(dcbase, DisasContext, base);
|
||||
|
||||
|
||||
switch (ctx->base.is_jmp) {
|
||||
case DISAS_NORETURN:
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static const TranslatorOps cr16c_tr_ops = {
|
||||
.init_disas_context = cr16c_tr_init_disas_context,
|
||||
.tb_start = cr16c_tr_tb_start,
|
||||
.insn_start = cr16c_tr_insn_start,
|
||||
.translate_insn = cr16c_tr_translate_insn,
|
||||
.tb_stop = cr16c_tr_tb_stop,
|
||||
};
|
||||
|
||||
void cr16c_translate_init(void) {
|
||||
for(int i = 0; i < CR16C_REG_COUNT; i++) {
|
||||
r[i] = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, r[i]), cr16c_cpu_r_names[i]);
|
||||
}
|
||||
pc = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, pc), "pc");
|
||||
sp = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, sp), "sp");
|
||||
f_n = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, f_n), "f_n");
|
||||
f_z = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, f_z), "f_z");
|
||||
f_f = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, f_f), "f_f");
|
||||
f_l = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, f_l), "f_l");
|
||||
f_c = tcg_global_mem_new_i32(tcg_env, offsetof(CPUCR16CState, f_c), "f_c");
|
||||
}
|
||||
|
||||
void cr16c_translate_code(CPUState *cs, TranslationBlock *tb,
|
||||
int *max_insns, vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
translator_loop(cs, tb, max_insns, pc, host_pc, &cr16c_tr_ops, &ctx.base);
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
subdir('alpha')
|
||||
subdir('arm')
|
||||
subdir('avr')
|
||||
subdir('cr16c')
|
||||
subdir('hexagon')
|
||||
subdir('hppa')
|
||||
subdir('i386')
|
||||
|
|
|
|||
25
tests/tcg/cr16c/Makefile.softmmu-target
Normal file
25
tests/tcg/cr16c/Makefile.softmmu-target
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
# CR16C system tests
|
||||
#
|
||||
|
||||
CR16C_SRC = $(SRC_PATH)/tests/tcg/cr16c
|
||||
CR16C_ALL = $(wildcard $(CR16C_SRC)/*.S)
|
||||
CR16C_TESTS = $(patsubst $(CR16C_SRC)/%.S, %, $(CR16C_ALL))
|
||||
|
||||
|
||||
# add to the list of tests
|
||||
TESTS += $(CR16C_TESTS)
|
||||
VPATH += $(CR16C_SRC)
|
||||
|
||||
QEMU_OPTS+=-M sc14450board -nographic $(EXTFLAGS) -bios
|
||||
|
||||
LDFLAGS = -nostdlib -static
|
||||
|
||||
%: %.S macros.inc Makefile.softmmu-target
|
||||
$(CC) $(EXTRA_CFLAGS) $< -o $@.elf $(LDFLAGS)
|
||||
# TODO: There seems to be a linker bug with the binary format for cr16
|
||||
# For now we extract the text section with a hardcoded objcopy command name :/
|
||||
cr16-unknown-elf-objcopy --dump-section .text=$@ $@.elf /dev/null
|
||||
|
||||
# We don't support the multiarch system tests yet
|
||||
undefine MULTIARCH_TESTS
|
||||
64
tests/tcg/cr16c/macros.inc
Normal file
64
tests/tcg/cr16c/macros.inc
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
.macro RESET
|
||||
movw $0x0B00, r0
|
||||
movw $0x0A01, r1
|
||||
movw $0x0902, r2
|
||||
movw $0x0803, r3
|
||||
movw $0x0704, r4
|
||||
movw $0x0605, r5
|
||||
movw $0x0506, r6
|
||||
movw $0x0407, r7
|
||||
movw $0x0308, r8
|
||||
movw $0x0209, r9
|
||||
movw $0x010A, r10
|
||||
movw $0x000B, r11
|
||||
.endm
|
||||
|
||||
.macro EXPECT expected, in
|
||||
cmpw $\expected, \in
|
||||
bne .fail
|
||||
.endm
|
||||
|
||||
.macro EXPECT_COND cond
|
||||
b\cond 1f
|
||||
br .fail
|
||||
1:
|
||||
.endm
|
||||
|
||||
.macro ENDING
|
||||
movw $0, r0
|
||||
excp UND
|
||||
.endm
|
||||
|
||||
.macro FAIL_HANDLER
|
||||
.fail:
|
||||
movw $1, r0
|
||||
excp UND
|
||||
.endm
|
||||
|
||||
/* Helper macro to set the carry flag */
|
||||
/* Sets r10 to one */
|
||||
.macro SETC
|
||||
movw $-1, r10
|
||||
addw $2, r10
|
||||
.endm
|
||||
|
||||
/* Helper macro to clear the carry flag */
|
||||
/* Sets r10 to one */
|
||||
.macro CLEARC
|
||||
movw $0, r10
|
||||
addw $1, r10
|
||||
.endm
|
||||
|
||||
/* Helper macro to set the signed overflow flag */
|
||||
/* Sets r11 to zero */
|
||||
.macro SETF
|
||||
movw $-0x8000, r11
|
||||
addw $-0x8000, r11
|
||||
.endm
|
||||
|
||||
/* Helper macro to clear the signed overflow flag */
|
||||
/* Sets r11 to zero */
|
||||
.macro CLEARF
|
||||
movw $-1, r11
|
||||
addb $1, r11
|
||||
.endm
|
||||
100
tests/tcg/cr16c/test00-moves.S
Normal file
100
tests/tcg/cr16c/test00-moves.S
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* TODO: 32 bit registers */
|
||||
|
||||
#include "macros.inc"
|
||||
|
||||
|
||||
.global _start
|
||||
|
||||
.text
|
||||
_start:
|
||||
/* Initialize registers */
|
||||
RESET
|
||||
|
||||
/*** MOVB imm4_16 ***/
|
||||
movb $0x07, r0
|
||||
movb $0x4e, r1
|
||||
EXPECT 0x0B07, r0
|
||||
EXPECT 0x0A4e, r1
|
||||
RESET
|
||||
|
||||
/*** MOVB reg ***/
|
||||
movb r0, r1
|
||||
EXPECT 0x0A00, r1
|
||||
RESET
|
||||
|
||||
/*** MOVD imm20 ***/
|
||||
movd $0x10010, (r1,r0)
|
||||
EXPECT 0x0010, r0
|
||||
EXPECT 0x0001, r1
|
||||
RESET
|
||||
|
||||
/*** MOVD imm32 ***/
|
||||
movd $0x110110, (r1,r0)
|
||||
EXPECT 0x0110, r0
|
||||
EXPECT 0x0011, r1
|
||||
RESET
|
||||
|
||||
/*** MOVD imm4_16 ***/
|
||||
movd $0x07, (r1,r0)
|
||||
movd $0x4e, (r3,r2)
|
||||
EXPECT 0x0007, r0
|
||||
EXPECT 0x0000, r1
|
||||
EXPECT 0x004e, r2
|
||||
EXPECT 0x0000, r3
|
||||
RESET
|
||||
|
||||
/*** MOVD reg ***/
|
||||
movd (r1,r0), (r3,r2)
|
||||
EXPECT 0x0B00, r2
|
||||
EXPECT 0x0A01, r3
|
||||
RESET
|
||||
|
||||
/*** MOVW imm4_16 ***/
|
||||
movw $0x07, r0
|
||||
movw $0x734e, r1
|
||||
EXPECT 0x0007, r0
|
||||
EXPECT 0x734e, r1
|
||||
RESET
|
||||
|
||||
/*** MOVW reg ***/
|
||||
movw r0, r1
|
||||
EXPECT 0x0B00, r1
|
||||
RESET
|
||||
|
||||
/*** MOVXB ***/
|
||||
movxb r1, r0
|
||||
EXPECT 0x0001, r0
|
||||
movw $0x00FF, r2
|
||||
movxb r2, r3
|
||||
EXPECT -1, r3
|
||||
RESET
|
||||
|
||||
/*** MOVXW ***/
|
||||
movxw r1, (r3,r2)
|
||||
EXPECT 0x0A01, r2
|
||||
EXPECT 0x0000, r3
|
||||
movw $-1, r4
|
||||
movxw r4, (r6,r5)
|
||||
EXPECT -1, r5
|
||||
EXPECT -1, r6
|
||||
RESET
|
||||
|
||||
/*** MOVZB ***/
|
||||
movzb r1, r0
|
||||
EXPECT 0x0001, r0
|
||||
movw $0x00FF, r2
|
||||
movzb r2, r3
|
||||
EXPECT 0x00FF, r3
|
||||
RESET
|
||||
|
||||
/*** MOVZW ***/
|
||||
movzw r1, (r3,r2)
|
||||
EXPECT 0x0A01, r2
|
||||
EXPECT 0x0000, r3
|
||||
movw $-1, r4
|
||||
movzw r4, (r6,r5)
|
||||
EXPECT -1, r5
|
||||
EXPECT 0x0000, r6
|
||||
|
||||
ENDING
|
||||
FAIL_HANDLER
|
||||
922
tests/tcg/cr16c/test01-adds.S
Normal file
922
tests/tcg/cr16c/test01-adds.S
Normal file
|
|
@ -0,0 +1,922 @@
|
|||
#include "macros.inc"
|
||||
|
||||
.global _start
|
||||
|
||||
.text
|
||||
_start:
|
||||
/* Initialize registers */
|
||||
RESET
|
||||
|
||||
/*** ADDB imm4_16 ***/
|
||||
/* Basic case, no overflow, imm4 */
|
||||
addb $0x07, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B07, r0
|
||||
addb $0x07, r1
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0A08, r1
|
||||
/* Basic case, no overflow, imm16 */
|
||||
addb $0x4e, r2
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0950, r2
|
||||
addb $0x4e, r3
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0851, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
addb $-1, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0703, r4
|
||||
addb $-1, r5
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0604, r5
|
||||
/* No unsigned overflow, signed overflow */
|
||||
addb $0x7F, r7
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0486, r7
|
||||
addb $0x7F, r8
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0387, r8
|
||||
/* Unsigned and signed overflow */
|
||||
movw $0x80, r10
|
||||
addb $0x80, r10
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r10
|
||||
movw $0x80, r10
|
||||
addb $0x80, r10
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r10
|
||||
RESET
|
||||
|
||||
/*** ADDB reg ***/
|
||||
/* Basic 2 regs, no overflow */
|
||||
addb r1, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B01, r0
|
||||
addb r1, r9
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x020a, r9
|
||||
/* Same reg, no overflow */
|
||||
addb r10, r10
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0114, r10
|
||||
addb r11, r11
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0016, r11
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movb $-1, r4
|
||||
addb r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0701, r4
|
||||
movb $-1, r4
|
||||
addb r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0701, r4
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7F, r4
|
||||
addb r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0081, r4
|
||||
movw $0x7F, r4
|
||||
addb r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0081, r4
|
||||
/* Unsigned and signed overflow */
|
||||
movw $0x80, r4
|
||||
movw $0x80, r3
|
||||
addb r3, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r4
|
||||
movw $0x80, r4
|
||||
movw $0x80, r3
|
||||
addb r3, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r4
|
||||
RESET
|
||||
|
||||
/*** ADDCB imm4_16 ***/
|
||||
/* Basic case, no overflow, imm4 */
|
||||
SETC
|
||||
addcb $0x07, r0
|
||||
EXPECT 0x0B08, r0
|
||||
CLEARC
|
||||
addcb $0x07, r1
|
||||
EXPECT 0x0A08, r1
|
||||
/* Unsigned overflow by carry */
|
||||
SETC
|
||||
addcb $-1, r2
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0902, r2
|
||||
CLEARC
|
||||
addcb $-1, r3
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0802, r3
|
||||
/* Signed overflow by carry */
|
||||
SETC
|
||||
addcb $0x7B, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0780, r4
|
||||
CLEARC
|
||||
addcb $0x7B, r5
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0680, r5
|
||||
RESET
|
||||
|
||||
/*** ADDCB reg ***/
|
||||
/* Basic 2 regs, no overflow */
|
||||
SETC
|
||||
addcb r1, r0
|
||||
EXPECT 0x0B02, r0
|
||||
CLEARC
|
||||
addcb r1, r9
|
||||
EXPECT 0x020a, r9
|
||||
/* Unsigned overflow by carry */
|
||||
movb $-3, r4
|
||||
SETC
|
||||
addcb r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0700, r4
|
||||
movb $-3, r4
|
||||
SETC
|
||||
addcb r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0700, r4
|
||||
/* Signed overflow by carry */
|
||||
movw $0x7D, r4
|
||||
SETC
|
||||
addcb r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0080, r4
|
||||
movw $0x7D, r4
|
||||
SETC
|
||||
addcb r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0080, r4
|
||||
RESET
|
||||
|
||||
/*** ADDW imm4_16 ***/
|
||||
/* Basic case, no overflow, imm4 */
|
||||
addw $0x07, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B07, r0
|
||||
addw $0x07, r1
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0A08, r1
|
||||
/* Basic case, no overflow, imm16 */
|
||||
addw $0x4e, r2
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0950, r2
|
||||
addw $0x4e, r3
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0851, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
addw $-1, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0703, r4
|
||||
addw $-1, r5
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0604, r5
|
||||
/* No unsigned overflow, signed overflow */
|
||||
addw $0x7BF9, r7
|
||||
EXPECT_COND cc
|
||||
EXPECT -0x8000, r7
|
||||
addw $0x7CF8, r8
|
||||
EXPECT_COND fs
|
||||
EXPECT -0x8000, r8
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r10
|
||||
addw $-0x8000, r10
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r10
|
||||
movw $-0x8000, r10
|
||||
addw $-0x8000, r10
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r10
|
||||
RESET
|
||||
|
||||
/*** ADDW reg ***/
|
||||
/* Basic 2 regs, no overflow */
|
||||
addw r1, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x1501, r0
|
||||
addw r1, r9
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0C0A, r9
|
||||
/* Same reg, no overflow */
|
||||
addw r10, r10
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0214, r10
|
||||
addw r11, r11
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0016, r11
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movw $-1, r4
|
||||
addw r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0901, r4
|
||||
movw $-1, r4
|
||||
addw r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0901, r4
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7FFF, r4
|
||||
addw r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT -0x76FF, r4
|
||||
movw $0x7FFF, r4
|
||||
addw r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT -0x76FF, r4
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r4
|
||||
movw $-0x8000, r3
|
||||
addw r3, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r4
|
||||
movw $-0x8000, r4
|
||||
movw $-0x8000, r3
|
||||
addw r3, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r4
|
||||
RESET
|
||||
|
||||
/*** ADDCW imm4_16 ***/
|
||||
/* Basic case, no overflow, imm4 */
|
||||
SETC
|
||||
addcw $0x07, r0
|
||||
EXPECT 0x0B08, r0
|
||||
CLEARC
|
||||
addcw $0x0207, r1
|
||||
EXPECT 0x0C08, r1
|
||||
/* Unsigned overflow by carry */
|
||||
SETC
|
||||
addcw $-1, r2
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0902, r2
|
||||
CLEARC
|
||||
addcw $-1, r3
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0802, r3
|
||||
/* Signed overflow by carry */
|
||||
SETC
|
||||
addcw $0x78FB, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT -0x8000, r4
|
||||
SETC
|
||||
addcw $0x79FA, r5
|
||||
EXPECT_COND fs
|
||||
EXPECT -0x8000, r5
|
||||
RESET
|
||||
|
||||
/*** ADDCW reg ***/
|
||||
/* Basic 2 regs, no overflow */
|
||||
SETC
|
||||
addcw r1, r0
|
||||
EXPECT 0x1502, r0
|
||||
CLEARC
|
||||
addcw r1, r9
|
||||
EXPECT 0x0C0A, r9
|
||||
/* Unsigned overflow by carry */
|
||||
movw $-0x0903, r4
|
||||
SETC
|
||||
addcw r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r4
|
||||
movw $-0x0903, r4
|
||||
SETC
|
||||
addcw r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0000, r4
|
||||
/* Signed overflow by carry */
|
||||
movw $0x76FD, r4
|
||||
SETC
|
||||
addcw r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT -0x8000, r4
|
||||
movw $0x76FD, r4
|
||||
SETC
|
||||
addcw r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT -0x8000, r4
|
||||
RESET
|
||||
|
||||
/*** ADDD imm20 ***/
|
||||
/* Basic case, no overflow */
|
||||
addd $0x10001, (r1,r0)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B01, r0
|
||||
EXPECT 0x0A02, r1
|
||||
addd $0x10001, (r3,r2)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0903, r2
|
||||
EXPECT 0x0804, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movw $-1, r5
|
||||
addd $0x10001, (r5,r4)
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0705, r4
|
||||
EXPECT 0x00000, r5
|
||||
movw $-1, r7
|
||||
addd $0x10001, (r7,r6)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0507, r6
|
||||
EXPECT 0x0000, r7
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7FFF, r9
|
||||
addd $0x10001, (r9,r8)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0309, r8
|
||||
EXPECT -0x8000, r9
|
||||
movw $0x7FFF, r11
|
||||
addd $0x10001, (r11,r10)
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x010B, r10
|
||||
EXPECT -0x8000, r11
|
||||
RESET
|
||||
|
||||
/*** ADDD imm32 ***/
|
||||
/* Basic case, no overflow */
|
||||
addd $0x70001000, (r1,r0)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x1B00, r0
|
||||
EXPECT 0x7A01, r1
|
||||
addd $0x70001000, (r3,r2)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x1902, r2
|
||||
EXPECT 0x7803, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
addd $-0x00100001, (r5,r4)
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0703, r4
|
||||
EXPECT 0x05F5, r5
|
||||
addd $-0x00100001, (r7,r6)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0505, r6
|
||||
EXPECT 0x03F7, r7
|
||||
/* No unsigned overflow, signed overflow */
|
||||
addd $0x7DF6FCF8, (r9,r8)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0000, r8
|
||||
EXPECT -0x8000, r9
|
||||
addd $0x7FF4FEF6, (r11,r10)
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r10
|
||||
EXPECT -0x8000, r11
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r10
|
||||
addw $-0x8000, r10
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r10
|
||||
movw $-0x8000, r10
|
||||
addw $-0x8000, r10
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r10
|
||||
RESET
|
||||
|
||||
/*** ADDD imm16_4 ***/
|
||||
/* Basic case, no overflow, imm4 */
|
||||
addd $0x07, (r1,r0)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B07, r0
|
||||
EXPECT 0x0A01, r1
|
||||
addd $0x07, (r3,r2)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0909, r2
|
||||
EXPECT 0x0803, r3
|
||||
/* Basic case, no overflow, imm16 */
|
||||
addd $0x4e, (r5,r4)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0752, r4
|
||||
EXPECT 0x0605, r5
|
||||
addd $0x4e, (r7,r6)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0554, r6
|
||||
EXPECT 0x0407, r7
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
addd $-1, (r9,r8)
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0307, r8
|
||||
EXPECT 0x0209, r9
|
||||
addd $-1, (r11,r10)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0109, r10
|
||||
EXPECT 0x000B, r11
|
||||
RESET
|
||||
/* No unsigned overflow, signed overflow */
|
||||
addd $0x75FEF500, (r1,r0)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0000, r0
|
||||
EXPECT -0x8000, r1
|
||||
addd $0x77FCF6FE, (r3,r2)
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r2
|
||||
EXPECT -0x8000, r3
|
||||
/* Unsigned and signed overflow */
|
||||
movw $0x0000, r4
|
||||
movw $-0x8000, r5
|
||||
addd $-1, (r5,r4)
|
||||
EXPECT_COND cs
|
||||
EXPECT -1, r4
|
||||
EXPECT 0x7FFF, r5
|
||||
movw $0x0000, r4
|
||||
movw $-0x8000, r5
|
||||
addd $-1, (r5,r4)
|
||||
EXPECT_COND fs
|
||||
EXPECT -1, r4
|
||||
EXPECT 0x7FFF, r5
|
||||
RESET
|
||||
|
||||
/*** ADDD rp ***/
|
||||
/* Basic 2 rps, no overflow */
|
||||
addd (r1,r0), (r3,r2)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x1402, r2
|
||||
EXPECT 0x1204, r3
|
||||
addd (r5,r4), (r7,r6)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0C0A, r6
|
||||
EXPECT 0x0A0C, r7
|
||||
/* Same rp, no overflow */
|
||||
addd (r9,r8), (r9,r8)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0610, r8
|
||||
EXPECT 0x0412, r9
|
||||
addd (r11,r10), (r11,r10)
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0214, r10
|
||||
EXPECT 0x0016, r11
|
||||
RESET
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movw $-1, r0
|
||||
movw $-1, r1
|
||||
movw $-1, r2
|
||||
movw $-1, r3
|
||||
addd (r1,r0), (r3,r2)
|
||||
EXPECT_COND cs
|
||||
EXPECT -2, r2
|
||||
EXPECT -1, r3
|
||||
movw $-1, r0
|
||||
movw $-1, r1
|
||||
movw $-1, r2
|
||||
movw $-1, r3
|
||||
addd (r1,r0), (r3,r2)
|
||||
EXPECT_COND fc
|
||||
EXPECT -2, r2
|
||||
EXPECT -1, r3
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7FFF, r5
|
||||
movw $1, r7
|
||||
addd (r5,r4), (r7,r6)
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0C0A, r6
|
||||
EXPECT -0x8000, r7
|
||||
movw $0x7FFF, r9
|
||||
movw $1, r11
|
||||
addd (r9,r8), (r11,r10)
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0412, r10
|
||||
EXPECT -0x8000, r11
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-1, r0
|
||||
movw $-0x8000, r1
|
||||
movw $-2, r2
|
||||
movw $-0x8000, r3
|
||||
addd (r1,r0), (r3,r2)
|
||||
EXPECT_COND cs
|
||||
EXPECT -3, r2
|
||||
EXPECT 0x0001, r3
|
||||
movw $-1, r0
|
||||
movw $-0x8000, r1
|
||||
movw $-2, r2
|
||||
movw $-0x8000, r3
|
||||
addd (r1,r0), (r3,r2)
|
||||
EXPECT_COND fs
|
||||
EXPECT -3, r2
|
||||
EXPECT 0x0001, r3
|
||||
RESET
|
||||
|
||||
/*** ADDUB imm4_16 ***/
|
||||
/* Flags set */
|
||||
/* Basic case, no overflow, imm4 */
|
||||
SETC
|
||||
adduw $0x07, r0
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0B07, r0
|
||||
SETF
|
||||
adduw $0x07, r1
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0A08, r1
|
||||
/* Basic case, no overflow, imm16 */
|
||||
SETC
|
||||
adduw $0x4e, r2
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0950, r2
|
||||
SETF
|
||||
adduw $0x4e, r3
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0851, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
SETC
|
||||
adduw $-1, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0703, r4
|
||||
SETF
|
||||
adduw $-1, r5
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0604, r5
|
||||
/* No unsigned overflow, signed overflow */
|
||||
SETC
|
||||
adduw $0x7BF9, r7
|
||||
EXPECT_COND cs
|
||||
EXPECT -0x8000, r7
|
||||
SETF
|
||||
adduw $0x7CF8, r8
|
||||
EXPECT_COND fs
|
||||
EXPECT -0x8000, r8
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r11
|
||||
SETC
|
||||
adduw $-0x8000, r11
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r11
|
||||
movw $-0x8000, r10
|
||||
SETF
|
||||
adduw $-0x8000, r10
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r10
|
||||
RESET
|
||||
/* Flags cleared */
|
||||
/* Basic case, no overflow, imm4 */
|
||||
CLEARC
|
||||
adduw $0x07, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B07, r0
|
||||
CLEARF
|
||||
adduw $0x07, r1
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0A08, r1
|
||||
/* Basic case, no overflow, imm16 */
|
||||
CLEARC
|
||||
adduw $0x4e, r2
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0950, r2
|
||||
CLEARF
|
||||
adduw $0x4e, r3
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0851, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
CLEARC
|
||||
adduw $-1, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0703, r4
|
||||
CLEARF
|
||||
adduw $-1, r5
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0604, r5
|
||||
/* No unsigned overflow, signed overflow */
|
||||
CLEARC
|
||||
adduw $0x7BF9, r7
|
||||
EXPECT_COND cc
|
||||
EXPECT -0x8000, r7
|
||||
CLEARF
|
||||
adduw $0x7CF8, r8
|
||||
EXPECT_COND fc
|
||||
EXPECT -0x8000, r8
|
||||
/* Unsigned and signed overflow */
|
||||
CLEARC
|
||||
movw $-0x8000, r11
|
||||
adduw $-0x8000, r11
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0000, r11
|
||||
movw $-0x8000, r10
|
||||
CLEARF
|
||||
adduw $-0x8000, r10
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0000, r10
|
||||
RESET
|
||||
|
||||
/*** ADDUB reg ***/
|
||||
/* Flags set */
|
||||
/* Basic 2 regs, no overflow */
|
||||
SETC
|
||||
addub r1, r0
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0B01, r0
|
||||
SETF
|
||||
addub r1, r9
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x020a, r9
|
||||
/* Same reg, no overflow */
|
||||
SETC
|
||||
addub r5, r5
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x060A, r5
|
||||
SETF
|
||||
addub r6, r6
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x050C, r6
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movb $-1, r4
|
||||
SETC
|
||||
addub r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0701, r4
|
||||
movb $-1, r4
|
||||
SETF
|
||||
addub r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0701, r4
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7F, r4
|
||||
SETC
|
||||
addub r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0081, r4
|
||||
movw $0x7F, r4
|
||||
SETF
|
||||
addub r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0081, r4
|
||||
/* Unsigned and signed overflow */
|
||||
movw $0x80, r4
|
||||
movw $0x80, r3
|
||||
SETC
|
||||
addub r3, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r4
|
||||
movw $0x80, r4
|
||||
movw $0x80, r3
|
||||
SETF
|
||||
addub r3, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r4
|
||||
RESET
|
||||
/* Flags cleared */
|
||||
/* Basic 2 regs, no overflow */
|
||||
CLEARC
|
||||
addub r1, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B01, r0
|
||||
CLEARF
|
||||
addub r1, r9
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x020a, r9
|
||||
/* Same reg, no overflow */
|
||||
CLEARC
|
||||
addub r5, r5
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x060A, r5
|
||||
CLEARF
|
||||
addub r6, r6
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x050C, r6
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movb $-1, r4
|
||||
CLEARC
|
||||
addub r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0701, r4
|
||||
movb $-1, r4
|
||||
CLEARF
|
||||
addub r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0701, r4
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7F, r4
|
||||
CLEARC
|
||||
addub r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0081, r4
|
||||
movw $0x7F, r4
|
||||
CLEARF
|
||||
addub r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0081, r4
|
||||
/* Unsigned and signed overflow */
|
||||
movw $0x80, r4
|
||||
movw $0x80, r3
|
||||
CLEARC
|
||||
addub r3, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0000, r4
|
||||
movw $0x80, r4
|
||||
movw $0x80, r3
|
||||
CLEARF
|
||||
addub r3, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0000, r4
|
||||
RESET
|
||||
|
||||
/*** ADDUW imm4_16 ***/
|
||||
/* Flags set */
|
||||
/* Basic case, no overflow, imm4 */
|
||||
SETC
|
||||
adduw $0x07, r0
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0B07, r0
|
||||
SETF
|
||||
adduw $0x07, r1
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0A08, r1
|
||||
/* Basic case, no overflow, imm16 */
|
||||
SETC
|
||||
adduw $0x4e, r2
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0950, r2
|
||||
SETF
|
||||
adduw $0x4e, r3
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0851, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
SETC
|
||||
adduw $-1, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0703, r4
|
||||
SETF
|
||||
adduw $-1, r5
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0604, r5
|
||||
/* No unsigned overflow, signed overflow */
|
||||
SETC
|
||||
adduw $0x7BF9, r7
|
||||
EXPECT_COND cs
|
||||
EXPECT -0x8000, r7
|
||||
SETF
|
||||
adduw $0x7CF8, r8
|
||||
EXPECT_COND fs
|
||||
EXPECT -0x8000, r8
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r11
|
||||
SETC
|
||||
adduw $-0x8000, r11
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r11
|
||||
movw $-0x8000, r10
|
||||
SETF
|
||||
adduw $-0x8000, r10
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r10
|
||||
RESET
|
||||
/* Flags cleared */
|
||||
/* Basic case, no overflow, imm4 */
|
||||
CLEARC
|
||||
adduw $0x07, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0B07, r0
|
||||
CLEARF
|
||||
adduw $0x07, r1
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0A08, r1
|
||||
/* Basic case, no overflow, imm16 */
|
||||
CLEARC
|
||||
adduw $0x4e, r2
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0950, r2
|
||||
CLEARF
|
||||
adduw $0x4e, r3
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0851, r3
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
CLEARC
|
||||
adduw $-1, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0703, r4
|
||||
CLEARF
|
||||
adduw $-1, r5
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0604, r5
|
||||
/* No unsigned overflow, signed overflow */
|
||||
CLEARC
|
||||
adduw $0x7BF9, r7
|
||||
EXPECT_COND cc
|
||||
EXPECT -0x8000, r7
|
||||
CLEARF
|
||||
adduw $0x7CF8, r8
|
||||
EXPECT_COND fc
|
||||
EXPECT -0x8000, r8
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r11
|
||||
CLEARC
|
||||
adduw $-0x8000, r11
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0000, r11
|
||||
movw $-0x8000, r10
|
||||
CLEARF
|
||||
adduw $-0x8000, r10
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0000, r10
|
||||
RESET
|
||||
|
||||
/*** ADDUW reg ***/
|
||||
/* Flags set */
|
||||
/* Basic 2 regs, no overflow */
|
||||
SETC
|
||||
adduw r1, r0
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x1501, r0
|
||||
SETF
|
||||
adduw r1, r9
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0C0A, r9
|
||||
/* Same reg, no overflow */
|
||||
SETC
|
||||
adduw r5, r5
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0C0A, r5
|
||||
SETF
|
||||
adduw r6, r6
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0A0C, r6
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movw $-1, r4
|
||||
SETC
|
||||
adduw r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0901, r4
|
||||
movw $-1, r4
|
||||
SETF
|
||||
adduw r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0901, r4
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7FFF, r4
|
||||
SETC
|
||||
adduw r2, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT -0x76FF, r4
|
||||
movw $0x7FFF, r4
|
||||
SETF
|
||||
adduw r2, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT -0x76FF, r4
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r4
|
||||
movw $-0x8000, r3
|
||||
SETC
|
||||
adduw r3, r4
|
||||
EXPECT_COND cs
|
||||
EXPECT 0x0000, r4
|
||||
movw $-0x8000, r4
|
||||
movw $-0x8000, r3
|
||||
SETF
|
||||
adduw r3, r4
|
||||
EXPECT_COND fs
|
||||
EXPECT 0x0000, r4
|
||||
RESET
|
||||
/* Flags Cleared */
|
||||
/* Basic 2 regs, no overflow */
|
||||
CLEARC
|
||||
adduw r1, r0
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x1501, r0
|
||||
CLEARF
|
||||
adduw r1, r9
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0C0A, r9
|
||||
/* Same reg, no overflow */
|
||||
CLEARC
|
||||
adduw r5, r5
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0C0A, r5
|
||||
CLEARF
|
||||
adduw r6, r6
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0A0C, r6
|
||||
/* Unsigned overflow, no signed overflow */
|
||||
movw $-1, r4
|
||||
CLEARC
|
||||
adduw r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0901, r4
|
||||
movw $-1, r4
|
||||
CLEARF
|
||||
adduw r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0901, r4
|
||||
/* No unsigned overflow, signed overflow */
|
||||
movw $0x7FFF, r4
|
||||
CLEARC
|
||||
adduw r2, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT -0x76FF, r4
|
||||
movw $0x7FFF, r4
|
||||
CLEARF
|
||||
adduw r2, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT -0x76FF, r4
|
||||
/* Unsigned and signed overflow */
|
||||
movw $-0x8000, r4
|
||||
movw $-0x8000, r3
|
||||
CLEARC
|
||||
adduw r3, r4
|
||||
EXPECT_COND cc
|
||||
EXPECT 0x0000, r4
|
||||
movw $-0x8000, r4
|
||||
movw $-0x8000, r3
|
||||
CLEARF
|
||||
adduw r3, r4
|
||||
EXPECT_COND fc
|
||||
EXPECT 0x0000, r4
|
||||
RESET
|
||||
|
||||
ENDING
|
||||
FAIL_HANDLER
|
||||
237
tests/tcg/cr16c/test02-muls.S
Normal file
237
tests/tcg/cr16c/test02-muls.S
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
#include "macros.inc"
|
||||
|
||||
.global _start
|
||||
|
||||
.text
|
||||
_start:
|
||||
/* Initialize registers */
|
||||
RESET
|
||||
|
||||
/*** MACQW ***/
|
||||
/* Two positives, no overflow */
|
||||
macqw r0, r1, (r3,r2)
|
||||
EXPECT 0x1F02, r2
|
||||
EXPECT 0x08DF, r3
|
||||
/* Two negatives, no overflow */
|
||||
movw $-0x4000, r0 /* -0.5 -> r0 */
|
||||
movw $-0x6000, r1 /* -0.25 -> r1 */
|
||||
macqw r0, r1, (r5, r4)
|
||||
EXPECT 0x0704, r4
|
||||
EXPECT 0x1605, r5
|
||||
/* One negative, no overflow */
|
||||
movw $-0x7F80, r0
|
||||
movw $0x4000, r1
|
||||
macqw r0, r1, (r7, r6)
|
||||
EXPECT 0x0506, r6
|
||||
EXPECT 0x03C7, r7
|
||||
/* Positive overflow */
|
||||
movw $0x7FFF, r0
|
||||
movw $0x7FFF, r1
|
||||
macqw r0, r1, (r9,r8)
|
||||
EXPECT -1, r8
|
||||
EXPECT 0x7FFF, r9
|
||||
/* Negative overflow */
|
||||
movw $-1, r0
|
||||
movw $0x7FFF, r1
|
||||
movw $-1, r11
|
||||
macqw r0, r1, (r11,r10)
|
||||
EXPECT -1, r10
|
||||
EXPECT -1, r11
|
||||
/* Same reg */
|
||||
movw $0x0000, r0
|
||||
movw $0x4000, r1
|
||||
macqw r1, r1, (r1,r0)
|
||||
EXPECT 0x0000, r0
|
||||
EXPECT 0x6000, r1
|
||||
RESET
|
||||
|
||||
/*** MACUW ***/
|
||||
/* No overflow */
|
||||
macuw r0, r1, (r3,r2)
|
||||
EXPECT 0x1402, r2
|
||||
EXPECT 0x0871, r3
|
||||
/* Unsigned overflow */
|
||||
movw $-1, r5
|
||||
macuw r7, r8, (r5,r4)
|
||||
EXPECT -1, r4
|
||||
EXPECT -1, r5
|
||||
/* Ignore signed overflow */
|
||||
movw $-0x8000, r0
|
||||
movw $-0x8000, r1
|
||||
movw $0x4000, r7
|
||||
macuw r0, r1, (r7,r6)
|
||||
EXPECT 0x0506, r6
|
||||
EXPECT -0x8000, r7
|
||||
/* Same reg */
|
||||
macuw r8, r8, (r9,r8)
|
||||
EXPECT 0x3348, r8
|
||||
EXPECT 0x0212, r9
|
||||
RESET
|
||||
|
||||
/*** MACSW ***/
|
||||
/* No overflow */
|
||||
macsw r0, r1, (r3,r2)
|
||||
EXPECT 0x1402, r2
|
||||
EXPECT 0x0871, r3
|
||||
/* Signed overflow */
|
||||
movw $90, r0
|
||||
movw $42, r1
|
||||
movw $-1, r6
|
||||
movw $0x7FFF, r7
|
||||
macsw r0, r1, (r7,r6)
|
||||
EXPECT -0x1, r6
|
||||
EXPECT 0x7FFF, r7
|
||||
/* Signed underflow */
|
||||
movw $-50, r0
|
||||
movw $3, r1
|
||||
movw $0, r8
|
||||
movw $-0x8000, r9
|
||||
macsw r0, r1, (r9,r8)
|
||||
EXPECT 0, r8
|
||||
EXPECT -0x8000, r9
|
||||
/* Ignore unsigned overflow */
|
||||
movw $3, r0
|
||||
movw $2, r1
|
||||
movw $-1, r2
|
||||
movw $-1, r3
|
||||
macsw r0, r1, (r3,r2)
|
||||
EXPECT 5, r2
|
||||
EXPECT 0, r3
|
||||
/* Same reg */
|
||||
macuw r10, r10, (r11,r10)
|
||||
EXPECT 0x156E, r10
|
||||
EXPECT 0x000C, r11
|
||||
RESET
|
||||
|
||||
/*** MULB imm4/16 ***/
|
||||
/* imm4 */
|
||||
mulb $4, r0
|
||||
mulb $6, r1
|
||||
EXPECT 0x0B00, r0
|
||||
EXPECT 0x0A06, r1
|
||||
/* imm16 */
|
||||
mulb $0x34, r2
|
||||
mulb $0x15, r3
|
||||
EXPECT 0x0968, r2
|
||||
EXPECT 0x083F, r3
|
||||
/* negative */
|
||||
mulb $-3, r4
|
||||
mulb $-1, r5
|
||||
EXPECT 0x07F4, r4
|
||||
EXPECT 0x06FB, r5
|
||||
RESET
|
||||
|
||||
/*** MULB reg ***/
|
||||
/* No overflow / All positive */
|
||||
mulb r1, r0
|
||||
mulb r11, r10
|
||||
EXPECT 0x0B00, r0
|
||||
EXPECT 0x016E, r10
|
||||
/* Overflow / Negative */
|
||||
movw $0x03FF, r0
|
||||
movw $0x01FE, r1
|
||||
mulb r2, r0
|
||||
mulb r3, r1
|
||||
EXPECT 0x03FE, r0
|
||||
EXPECT 0x01FA, r1
|
||||
/* Same reg */
|
||||
mulb r4, r4
|
||||
EXPECT 0x0710, r4
|
||||
RESET
|
||||
|
||||
/*** MULSB ***/
|
||||
/* Positive params */
|
||||
mulsb r1, r0
|
||||
mulsb r11, r10
|
||||
EXPECT 0x0000, r0
|
||||
EXPECT 0x006E, r10
|
||||
/* Negative params */
|
||||
movw $0x03FF, r0
|
||||
movw $0x01FE, r1
|
||||
mulsb r2, r0
|
||||
mulsb r3, r1
|
||||
EXPECT -2, r0
|
||||
EXPECT -6, r1
|
||||
/* Same reg */
|
||||
mulsb r3, r3
|
||||
EXPECT 0x0009, r3
|
||||
RESET
|
||||
|
||||
/*** MULSW ***/
|
||||
/* No overflow / All positive */
|
||||
mulsw r0, (r2,r1)
|
||||
mulsw r9, (r11,r10)
|
||||
EXPECT 0x0B00, r1
|
||||
EXPECT 0x006E, r2
|
||||
EXPECT 0x1D5A, r10
|
||||
EXPECT 0x0002, r11
|
||||
/* Params interpreted as signed */
|
||||
movw $2, r0
|
||||
movw $-4, r1
|
||||
mulsw r0, (r2,r1)
|
||||
EXPECT -8, r1
|
||||
EXPECT -1, r2
|
||||
/* Same reg */
|
||||
mulsw r3, (r4,r3)
|
||||
EXPECT 0x3009, r3
|
||||
EXPECT 0x0040, r4
|
||||
RESET
|
||||
|
||||
/*** MULUW ***/
|
||||
/* No overflow / All positive */
|
||||
muluw r0, (r2,r1)
|
||||
muluw r9, (r11,r10)
|
||||
EXPECT 0x0B00, r1
|
||||
EXPECT 0x006E, r2
|
||||
EXPECT 0x1D5A, r10
|
||||
EXPECT 0x0002, r11
|
||||
/* Params interpreted as unsigned */
|
||||
movw $2, r0
|
||||
movw $-1, r1
|
||||
muluw r0, (r2,r1)
|
||||
EXPECT -2, r1
|
||||
EXPECT 1, r2
|
||||
/* Same reg */
|
||||
muluw r3, (r4,r3)
|
||||
EXPECT 0x3009, r3
|
||||
EXPECT 0x0040, r4
|
||||
RESET
|
||||
|
||||
/*** MULW imm4/16 ***/
|
||||
/* imm4 */
|
||||
mulw $4, r0
|
||||
mulw $6, r1
|
||||
EXPECT 0x2C00, r0
|
||||
EXPECT 0x3C06, r1
|
||||
/* imm16 */
|
||||
mulw $0x34, r2
|
||||
mulw $0x15, r3
|
||||
EXPECT -0x2B98, r2
|
||||
EXPECT -0x57C1, r3
|
||||
/* negative */
|
||||
mulw $-3, r4
|
||||
mulw $-1, r5
|
||||
EXPECT -0x150C, r4
|
||||
EXPECT -0x0605, r5
|
||||
RESET
|
||||
|
||||
/*** MULW reg ***/
|
||||
/* Positive args */
|
||||
mulw r1, r0
|
||||
mulw r11, r10
|
||||
EXPECT 0x0B00, r0
|
||||
EXPECT 0x0B6E, r10
|
||||
/* Negative args */
|
||||
movw $-1, r0
|
||||
movw $-2, r1
|
||||
mulw r2, r0
|
||||
mulw r3, r1
|
||||
EXPECT -0x0902, r0
|
||||
EXPECT -0x1006, r1
|
||||
/* Same reg */
|
||||
mulw r4, r4
|
||||
EXPECT 0x3810, r4
|
||||
RESET
|
||||
|
||||
ENDING
|
||||
FAIL_HANDLER
|
||||
Loading…
Add table
Add a link
Reference in a new issue