This commit is contained in:
Jonas Bewig 2025-03-18 14:15:14 +01:00
parent 56c6e249b6
commit 005bf105aa
No known key found for this signature in database
GPG key ID: 8D99867797A4886F
32 changed files with 2814 additions and 1 deletions

View file

@ -0,0 +1,4 @@
# Default configuration for cr16c-softmmu
# Boards:
#
CONFIG_SC14450=y

View file

@ -0,0 +1,2 @@
TARGET_ARCH=cr16c
TARGET_LONG_BITS=32

View file

@ -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
View file

@ -0,0 +1,2 @@
config SC14450
bool

22
hw/cr16c/boot.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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);

View file

@ -49,6 +49,7 @@ subdir('fsi')
subdir('alpha')
subdir('arm')
subdir('avr')
subdir('cr16c')
subdir('hppa')
subdir('i386')
subdir('loongarch')

View file

@ -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

View file

@ -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);

View file

@ -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',

View file

@ -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
View file

@ -0,0 +1,2 @@
config CR16C
bool

9
target/cr16c/cpu-param.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}

View file

@ -1,6 +1,7 @@
subdir('alpha')
subdir('arm')
subdir('avr')
subdir('cr16c')
subdir('hexagon')
subdir('hppa')
subdir('i386')

View 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

View 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

View 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

View 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

View 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