diff --git a/configs/devices/cr16c-softmmu/default.mak b/configs/devices/cr16c-softmmu/default.mak new file mode 100644 index 0000000000..1a753abac8 --- /dev/null +++ b/configs/devices/cr16c-softmmu/default.mak @@ -0,0 +1,4 @@ +# Default configuration for cr16c-softmmu +# Boards: +# +CONFIG_SC14450=y diff --git a/configs/targets/cr16c-softmmu.mak b/configs/targets/cr16c-softmmu.mak new file mode 100644 index 0000000000..b73a5616df --- /dev/null +++ b/configs/targets/cr16c-softmmu.mak @@ -0,0 +1,2 @@ +TARGET_ARCH=cr16c +TARGET_LONG_BITS=32 diff --git a/hw/Kconfig b/hw/Kconfig index 9a86a6a28a..de09332f40 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -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 diff --git a/hw/cr16c/Kconfig b/hw/cr16c/Kconfig new file mode 100644 index 0000000000..0727b8e41d --- /dev/null +++ b/hw/cr16c/Kconfig @@ -0,0 +1,2 @@ +config SC14450 + bool diff --git a/hw/cr16c/boot.c b/hw/cr16c/boot.c new file mode 100644 index 0000000000..6db1bca13f --- /dev/null +++ b/hw/cr16c/boot.c @@ -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; +} diff --git a/hw/cr16c/boot.h b/hw/cr16c/boot.h new file mode 100644 index 0000000000..1d6b1a3f93 --- /dev/null +++ b/hw/cr16c/boot.h @@ -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 */ diff --git a/hw/cr16c/meson.build b/hw/cr16c/meson.build new file mode 100644 index 0000000000..14194d7976 --- /dev/null +++ b/hw/cr16c/meson.build @@ -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} diff --git a/hw/cr16c/sc14450.c b/hw/cr16c/sc14450.c new file mode 100644 index 0000000000..089e26332a --- /dev/null +++ b/hw/cr16c/sc14450.c @@ -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) diff --git a/hw/cr16c/sc14450.h b/hw/cr16c/sc14450.h new file mode 100644 index 0000000000..cacb7460e0 --- /dev/null +++ b/hw/cr16c/sc14450.h @@ -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 */ diff --git a/hw/cr16c/sc14450board.c b/hw/cr16c/sc14450board.c new file mode 100644 index 0000000000..f17e01986f --- /dev/null +++ b/hw/cr16c/sc14450board.c @@ -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); diff --git a/hw/meson.build b/hw/meson.build index b91f761fe0..d2088b0f69 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -49,6 +49,7 @@ subdir('fsi') subdir('alpha') subdir('arm') subdir('avr') +subdir('cr16c') subdir('hppa') subdir('i386') subdir('loongarch') diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 3b50ecfb54..aa2233b220 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -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 diff --git a/include/system/arch_init.h b/include/system/arch_init.h index 51e24c3091..54b8621cfe 100644 --- a/include/system/arch_init.h +++ b/include/system/arch_init.h @@ -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); diff --git a/qapi/machine.json b/qapi/machine.json index a6b8795b09..d53d6429c5 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -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', diff --git a/target/Kconfig b/target/Kconfig index d0c7b59d9c..2e03f5edd9 100644 --- a/target/Kconfig +++ b/target/Kconfig @@ -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 diff --git a/target/cr16c/Kconfig b/target/cr16c/Kconfig new file mode 100644 index 0000000000..17682b2e4b --- /dev/null +++ b/target/cr16c/Kconfig @@ -0,0 +1,2 @@ +config CR16C + bool diff --git a/target/cr16c/cpu-param.h b/target/cr16c/cpu-param.h new file mode 100644 index 0000000000..279b759ce5 --- /dev/null +++ b/target/cr16c/cpu-param.h @@ -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 diff --git a/target/cr16c/cpu-qom.h b/target/cr16c/cpu-qom.h new file mode 100644 index 0000000000..86370a0058 --- /dev/null +++ b/target/cr16c/cpu-qom.h @@ -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 diff --git a/target/cr16c/cpu.c b/target/cr16c/cpu.c new file mode 100644 index 0000000000..e9ec5857ac --- /dev/null +++ b/target/cr16c/cpu.c @@ -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) diff --git a/target/cr16c/cpu.h b/target/cr16c/cpu.h new file mode 100644 index 0000000000..fed84f2209 --- /dev/null +++ b/target/cr16c/cpu.h @@ -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 diff --git a/target/cr16c/helper.c b/target/cr16c/helper.c new file mode 100644 index 0000000000..42ca0cfd2c --- /dev/null +++ b/target/cr16c/helper.c @@ -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]); +} diff --git a/target/cr16c/helper.h b/target/cr16c/helper.h new file mode 100644 index 0000000000..ce57ec08f0 --- /dev/null +++ b/target/cr16c/helper.h @@ -0,0 +1,2 @@ +DEF_HELPER_1(raise_illegal_instruction, void, env); +DEF_HELPER_1(exit, void, env); diff --git a/target/cr16c/insn.decode b/target/cr16c/insn.decode new file mode 100644 index 0000000000..08f827b2db --- /dev/null +++ b/target/cr16c/insn.decode @@ -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 diff --git a/target/cr16c/machine.c b/target/cr16c/machine.c new file mode 100644 index 0000000000..daf212ec14 --- /dev/null +++ b/target/cr16c/machine.c @@ -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(), + } +}; diff --git a/target/cr16c/meson.build b/target/cr16c/meson.build new file mode 100644 index 0000000000..88ce674ed5 --- /dev/null +++ b/target/cr16c/meson.build @@ -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} diff --git a/target/cr16c/translate.c b/target/cr16c/translate.c new file mode 100644 index 0000000000..c4b9b9464a --- /dev/null +++ b/target/cr16c/translate.c @@ -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); +} diff --git a/target/meson.build b/target/meson.build index b29598e7c5..9dfaf72b96 100644 --- a/target/meson.build +++ b/target/meson.build @@ -1,6 +1,7 @@ subdir('alpha') subdir('arm') subdir('avr') +subdir('cr16c') subdir('hexagon') subdir('hppa') subdir('i386') diff --git a/tests/tcg/cr16c/Makefile.softmmu-target b/tests/tcg/cr16c/Makefile.softmmu-target new file mode 100644 index 0000000000..fa9fac3b72 --- /dev/null +++ b/tests/tcg/cr16c/Makefile.softmmu-target @@ -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 diff --git a/tests/tcg/cr16c/macros.inc b/tests/tcg/cr16c/macros.inc new file mode 100644 index 0000000000..8483357a91 --- /dev/null +++ b/tests/tcg/cr16c/macros.inc @@ -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 diff --git a/tests/tcg/cr16c/test00-moves.S b/tests/tcg/cr16c/test00-moves.S new file mode 100644 index 0000000000..8186324391 --- /dev/null +++ b/tests/tcg/cr16c/test00-moves.S @@ -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 diff --git a/tests/tcg/cr16c/test01-adds.S b/tests/tcg/cr16c/test01-adds.S new file mode 100644 index 0000000000..df3c262a05 --- /dev/null +++ b/tests/tcg/cr16c/test01-adds.S @@ -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 diff --git a/tests/tcg/cr16c/test02-muls.S b/tests/tcg/cr16c/test02-muls.S new file mode 100644 index 0000000000..e492b297e7 --- /dev/null +++ b/tests/tcg/cr16c/test02-muls.S @@ -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