diff options
Diffstat (limited to 'target/avr')
-rw-r--r-- | target/avr/cpu-param.h | 10 | ||||
-rw-r--r-- | target/avr/cpu.c | 20 | ||||
-rw-r--r-- | target/avr/cpu.h | 23 | ||||
-rw-r--r-- | target/avr/helper.c | 251 | ||||
-rw-r--r-- | target/avr/helper.h | 3 | ||||
-rw-r--r-- | target/avr/insn.decode | 7 | ||||
-rw-r--r-- | target/avr/translate.c | 45 |
7 files changed, 173 insertions, 186 deletions
diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h index 81f3f49..f74bfc25 100644 --- a/target/avr/cpu-param.h +++ b/target/avr/cpu-param.h @@ -21,16 +21,10 @@ #ifndef AVR_CPU_PARAM_H #define AVR_CPU_PARAM_H -/* - * TARGET_PAGE_BITS cannot be more than 8 bits because - * 1. all IO registers occupy [0x0000 .. 0x00ff] address range, and they - * should be implemented as a device and not memory - * 2. SRAM starts at the address 0x0100 - */ -#define TARGET_PAGE_BITS 8 +#define TARGET_PAGE_BITS 10 #define TARGET_PHYS_ADDR_SPACE_BITS 24 #define TARGET_VIRT_ADDR_SPACE_BITS 24 -#define TCG_GUEST_DEFAULT_MO 0 +#define TARGET_INSN_START_EXTRA_WORDS 0 #endif diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 834c708..84f3b83 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -23,6 +23,7 @@ #include "qemu/qemu-print.h" #include "exec/exec-all.h" #include "exec/translation-block.h" +#include "system/address-spaces.h" #include "cpu.h" #include "disas/dis-asm.h" #include "tcg/debug-assert.h" @@ -110,6 +111,8 @@ static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) static void avr_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + CPUAVRState *env = cpu_env(cs); + AVRCPU *cpu = env_archcpu(env); AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); Error *local_err = NULL; @@ -122,6 +125,19 @@ static void avr_cpu_realizefn(DeviceState *dev, Error **errp) cpu_reset(cs); mcc->parent_realize(dev, errp); + + /* + * Two blocks in the low data space loop back into cpu registers. + */ + memory_region_init_io(&cpu->cpu_reg1, OBJECT(cpu), &avr_cpu_reg1, env, + "avr-cpu-reg1", 32); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA, &cpu->cpu_reg1); + + memory_region_init_io(&cpu->cpu_reg2, OBJECT(cpu), &avr_cpu_reg2, env, + "avr-cpu-reg2", 8); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA + 0x58, &cpu->cpu_reg2); } static void avr_cpu_set_int(void *opaque, int irq, int level) @@ -208,10 +224,13 @@ static const struct SysemuCPUOps avr_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps avr_tcg_ops = { + .guest_default_memory_order = 0, + .mttcg_supported = false, .initialize = avr_cpu_tcg_init, .translate_code = avr_cpu_translate_code, .synchronize_from_tb = avr_cpu_synchronize_from_tb, .restore_state_to_opc = avr_restore_state_to_opc, + .mmu_index = avr_cpu_mmu_index, .cpu_exec_interrupt = avr_cpu_exec_interrupt, .cpu_exec_halt = avr_cpu_has_work, .tlb_fill = avr_cpu_tlb_fill, @@ -234,7 +253,6 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = avr_cpu_class_by_name; - cc->mmu_index = avr_cpu_mmu_index; cc->dump_state = avr_cpu_dump_state; cc->set_pc = avr_cpu_set_pc; cc->get_pc = avr_cpu_get_pc; diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 06f5ae4..d666617 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -22,7 +22,10 @@ #define QEMU_AVR_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" +#include "system/memory.h" #ifdef CONFIG_USER_ONLY #error "AVR 8-bit does not support user mode" @@ -44,8 +47,16 @@ /* Number of CPU registers */ #define NUMBER_OF_CPU_REGISTERS 32 -/* Number of IO registers accessible by ld/st/in/out */ -#define NUMBER_OF_IO_REGISTERS 64 + +/* CPU registers mapped into i/o ports 0x38-0x3f. */ +#define REG_38_RAMPD 0 +#define REG_38_RAMPX 1 +#define REG_38_RAMPY 2 +#define REG_38_RAMPZ 3 +#define REG_38_EIDN 4 +#define REG_38_SPL 5 +#define REG_38_SPH 6 +#define REG_38_SREG 7 /* * Offsets of AVR memory regions in host memory space. @@ -60,8 +71,6 @@ #define OFFSET_CODE 0x00000000 /* CPU registers, IO registers, and SRAM */ #define OFFSET_DATA 0x00800000 -/* CPU registers specifically, these are mapped at the start of data */ -#define OFFSET_CPU_REGISTERS OFFSET_DATA /* * IO registers, including status register, stack pointer, and memory * mapped peripherals, mapped just after CPU registers @@ -144,6 +153,9 @@ struct ArchCPU { CPUAVRState env; + MemoryRegion cpu_reg1; + MemoryRegion cpu_reg2; + /* Initial value of stack pointer */ uint32_t init_sp; }; @@ -244,6 +256,7 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); -#include "exec/cpu-all.h" +extern const MemoryRegionOps avr_cpu_reg1; +extern const MemoryRegionOps avr_cpu_reg2; #endif /* QEMU_AVR_CPU_H */ diff --git a/target/avr/helper.c b/target/avr/helper.c index 3412312..afa5914 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -23,10 +23,11 @@ #include "qemu/error-report.h" #include "cpu.h" #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/getpc.h" #include "exec/cputlb.h" #include "exec/page-protection.h" -#include "exec/cpu_ldst.h" -#include "exec/address-spaces.h" +#include "exec/target_page.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) @@ -67,6 +68,11 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) return false; } +static void do_stb(CPUAVRState *env, uint32_t addr, uint8_t data, uintptr_t ra) +{ + cpu_stb_mmuidx_ra(env, addr, data, MMU_DATA_IDX, ra); +} + void avr_cpu_do_interrupt(CPUState *cs) { CPUAVRState *env = cpu_env(cs); @@ -83,14 +89,14 @@ void avr_cpu_do_interrupt(CPUState *cs) } if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { - cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); - cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); - cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16); + do_stb(env, env->sp--, ret, 0); + do_stb(env, env->sp--, ret >> 8, 0); + do_stb(env, env->sp--, ret >> 16, 0); } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { - cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); - cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + do_stb(env, env->sp--, ret, 0); + do_stb(env, env->sp--, ret >> 8, 0); } else { - cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + do_stb(env, env->sp--, ret, 0); } env->pc_w = base + vector * size; @@ -108,7 +114,7 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) { - int prot, page_size = TARGET_PAGE_SIZE; + int prot; uint32_t paddr; address &= TARGET_PAGE_MASK; @@ -133,23 +139,9 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, /* Access to memory. */ paddr = OFFSET_DATA + address; prot = PAGE_READ | PAGE_WRITE; - if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { - /* - * Access to CPU registers, exit and rebuilt this TB to use - * full access in case it touches specially handled registers - * like SREG or SP. For probing, set page_size = 1, in order - * to force tlb_fill to be called for the next access. - */ - if (probe) { - page_size = 1; - } else { - cpu_env(cs)->fullacc = 1; - cpu_loop_exit_restore(cs, retaddr); - } - } } - tlb_set_page(cs, address, paddr, prot, mmu_idx, page_size); + tlb_set_page(cs, address, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); return true; } @@ -203,156 +195,129 @@ void helper_wdr(CPUAVRState *env) } /* - * This function implements IN instruction - * - * It does the following - * a. if an IO register belongs to CPU, its value is read and returned - * b. otherwise io address is translated to mem address and physical memory - * is read. - * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation - * + * The first 32 bytes of the data space are mapped to the cpu regs. + * We cannot write these from normal store operations because TCG + * does not expect global temps to be modified -- a global may be + * live in a host cpu register across the store. We can however + * read these, as TCG does make sure the global temps are saved + * in case the load operation traps. */ -target_ulong helper_inb(CPUAVRState *env, uint32_t port) + +static uint64_t avr_cpu_reg1_read(void *opaque, hwaddr addr, unsigned size) { - target_ulong data = 0; + CPUAVRState *env = opaque; - switch (port) { - case 0x38: /* RAMPD */ - data = 0xff & (env->rampD >> 16); - break; - case 0x39: /* RAMPX */ - data = 0xff & (env->rampX >> 16); - break; - case 0x3a: /* RAMPY */ - data = 0xff & (env->rampY >> 16); - break; - case 0x3b: /* RAMPZ */ - data = 0xff & (env->rampZ >> 16); - break; - case 0x3c: /* EIND */ - data = 0xff & (env->eind >> 16); - break; - case 0x3d: /* SPL */ - data = env->sp & 0x00ff; - break; - case 0x3e: /* SPH */ - data = env->sp >> 8; - break; - case 0x3f: /* SREG */ - data = cpu_get_sreg(env); - break; - default: - /* not a special register, pass to normal memory access */ - data = address_space_ldub(&address_space_memory, - OFFSET_IO_REGISTERS + port, - MEMTXATTRS_UNSPECIFIED, NULL); + assert(addr < 32); + return env->r[addr]; +} + +/* + * The range 0x38-0x3f of the i/o space is mapped to cpu regs. + * As above, we cannot write these from normal store operations. + */ + +static uint64_t avr_cpu_reg2_read(void *opaque, hwaddr addr, unsigned size) +{ + CPUAVRState *env = opaque; + + switch (addr) { + case REG_38_RAMPD: + return 0xff & (env->rampD >> 16); + case REG_38_RAMPX: + return 0xff & (env->rampX >> 16); + case REG_38_RAMPY: + return 0xff & (env->rampY >> 16); + case REG_38_RAMPZ: + return 0xff & (env->rampZ >> 16); + case REG_38_EIDN: + return 0xff & (env->eind >> 16); + case REG_38_SPL: + return env->sp & 0x00ff; + case REG_38_SPH: + return 0xff & (env->sp >> 8); + case REG_38_SREG: + return cpu_get_sreg(env); } + g_assert_not_reached(); +} - return data; +static void avr_cpu_trap_write(void *opaque, hwaddr addr, + uint64_t data64, unsigned size) +{ + CPUAVRState *env = opaque; + CPUState *cs = env_cpu(env); + + env->fullacc = true; + cpu_loop_exit_restore(cs, cs->mem_io_pc); } +const MemoryRegionOps avr_cpu_reg1 = { + .read = avr_cpu_reg1_read, + .write = avr_cpu_trap_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 1, +}; + +const MemoryRegionOps avr_cpu_reg2 = { + .read = avr_cpu_reg2_read, + .write = avr_cpu_trap_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 1, +}; + /* - * This function implements OUT instruction - * - * It does the following - * a. if an IO register belongs to CPU, its value is written into the register - * b. otherwise io address is translated to mem address and physical memory - * is written. - * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation - * + * this function implements ST instruction when there is a possibility to write + * into a CPU register */ -void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) { - data &= 0x000000ff; + env->fullacc = false; - switch (port) { - case 0x38: /* RAMPD */ + switch (addr) { + case 0 ... 31: + /* CPU registers */ + env->r[addr] = data; + break; + + case REG_38_RAMPD + 0x38 + NUMBER_OF_CPU_REGISTERS: if (avr_feature(env, AVR_FEATURE_RAMPD)) { - env->rampD = (data & 0xff) << 16; + env->rampD = data << 16; } break; - case 0x39: /* RAMPX */ + case REG_38_RAMPX + 0x38 + NUMBER_OF_CPU_REGISTERS: if (avr_feature(env, AVR_FEATURE_RAMPX)) { - env->rampX = (data & 0xff) << 16; + env->rampX = data << 16; } break; - case 0x3a: /* RAMPY */ + case REG_38_RAMPY + 0x38 + NUMBER_OF_CPU_REGISTERS: if (avr_feature(env, AVR_FEATURE_RAMPY)) { - env->rampY = (data & 0xff) << 16; + env->rampY = data << 16; } break; - case 0x3b: /* RAMPZ */ + case REG_38_RAMPZ + 0x38 + NUMBER_OF_CPU_REGISTERS: if (avr_feature(env, AVR_FEATURE_RAMPZ)) { - env->rampZ = (data & 0xff) << 16; + env->rampZ = data << 16; } break; - case 0x3c: /* EIDN */ - env->eind = (data & 0xff) << 16; + case REG_38_EIDN + 0x38 + NUMBER_OF_CPU_REGISTERS: + env->eind = data << 16; break; - case 0x3d: /* SPL */ - env->sp = (env->sp & 0xff00) | (data); + case REG_38_SPL + 0x38 + NUMBER_OF_CPU_REGISTERS: + env->sp = (env->sp & 0xff00) | data; break; - case 0x3e: /* SPH */ + case REG_38_SPH + 0x38 + NUMBER_OF_CPU_REGISTERS: if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { env->sp = (env->sp & 0x00ff) | (data << 8); } break; - case 0x3f: /* SREG */ + case REG_38_SREG + 0x38 + NUMBER_OF_CPU_REGISTERS: cpu_set_sreg(env, data); break; - default: - /* not a special register, pass to normal memory access */ - address_space_stb(&address_space_memory, OFFSET_IO_REGISTERS + port, - data, MEMTXATTRS_UNSPECIFIED, NULL); - } -} - -/* - * this function implements LD instruction when there is a possibility to read - * from a CPU register - */ -target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) -{ - uint8_t data; - - env->fullacc = false; - - if (addr < NUMBER_OF_CPU_REGISTERS) { - /* CPU registers */ - data = env->r[addr]; - } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { - /* IO registers */ - data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS); - } else { - /* memory */ - data = address_space_ldub(&address_space_memory, OFFSET_DATA + addr, - MEMTXATTRS_UNSPECIFIED, NULL); - } - return data; -} -/* - * this function implements ST instruction when there is a possibility to write - * into a CPU register - */ -void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) -{ - env->fullacc = false; - - /* Following logic assumes this: */ - assert(OFFSET_CPU_REGISTERS == OFFSET_DATA); - assert(OFFSET_IO_REGISTERS == OFFSET_CPU_REGISTERS + - NUMBER_OF_CPU_REGISTERS); - - if (addr < NUMBER_OF_CPU_REGISTERS) { - /* CPU registers */ - env->r[addr] = data; - } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { - /* IO registers */ - helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data); - } else { - /* memory */ - address_space_stb(&address_space_memory, OFFSET_DATA + addr, data, - MEMTXATTRS_UNSPECIFIED, NULL); + default: + do_stb(env, addr, data, GETPC()); + break; } } diff --git a/target/avr/helper.h b/target/avr/helper.h index 4d02e64..e8d13e9 100644 --- a/target/avr/helper.h +++ b/target/avr/helper.h @@ -23,7 +23,4 @@ DEF_HELPER_1(debug, noreturn, env) DEF_HELPER_1(break, noreturn, env) DEF_HELPER_1(sleep, noreturn, env) DEF_HELPER_1(unsupported, noreturn, env) -DEF_HELPER_3(outb, void, env, i32, i32) -DEF_HELPER_2(inb, tl, env, i32) DEF_HELPER_3(fullwr, void, env, i32, i32) -DEF_HELPER_2(fullrd, tl, env, i32) diff --git a/target/avr/insn.decode b/target/avr/insn.decode index 482c23a..cc30224 100644 --- a/target/avr/insn.decode +++ b/target/avr/insn.decode @@ -118,11 +118,8 @@ BRBC 1111 01 ....... ... @op_bit_imm @io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm @ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm -# The 16-bit immediate is completely in the next word. -# Fields cannot be defined with no bits, so we cannot play -# the same trick and append to a zero-bit value. -# Defer reading the immediate until trans_{LDS,STS}. -@ldst_s .... ... rd:5 .... imm=0 +%ldst_imm !function=next_word +@ldst_s .... ... rd:5 .... imm=%ldst_imm MOV 0010 11 . ..... .... @op_rd_rr MOVW 0000 0001 .... .... &rd_rr rd=%rd_d rr=%rr_d diff --git a/target/avr/translate.c b/target/avr/translate.c index 4ab71d8..b9c592c 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -29,6 +29,7 @@ #include "exec/helper-gen.h" #include "exec/log.h" #include "exec/translator.h" +#include "exec/target_page.h" #define HELPER_H "helper.h" #include "exec/helper-info.c.inc" @@ -194,6 +195,9 @@ static bool avr_have_feature(DisasContext *ctx, int feature) static bool decode_insn(DisasContext *ctx, uint16_t insn); #include "decode-insn.c.inc" +static void gen_inb(DisasContext *ctx, TCGv data, int port); +static void gen_outb(DisasContext *ctx, TCGv data, int port); + /* * Arithmetic Instructions */ @@ -1293,9 +1297,8 @@ static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_andi_tl(data, data, 1 << a->bit); ctx->skip_cond = TCG_COND_EQ; ctx->skip_var0 = data; @@ -1311,9 +1314,8 @@ static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_andi_tl(data, data, 1 << a->bit); ctx->skip_cond = TCG_COND_NE; ctx->skip_var0 = data; @@ -1502,11 +1504,18 @@ static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) { - if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { - gen_helper_fullrd(data, tcg_env, addr); - } else { - tcg_gen_qemu_ld_tl(data, addr, MMU_DATA_IDX, MO_UB); - } + tcg_gen_qemu_ld_tl(data, addr, MMU_DATA_IDX, MO_UB); +} + +static void gen_inb(DisasContext *ctx, TCGv data, int port) +{ + gen_data_load(ctx, data, tcg_constant_i32(port + NUMBER_OF_CPU_REGISTERS)); +} + +static void gen_outb(DisasContext *ctx, TCGv data, int port) +{ + gen_helper_fullwr(tcg_env, data, + tcg_constant_i32(port + NUMBER_OF_CPU_REGISTERS)); } /* @@ -1578,7 +1587,6 @@ static bool trans_LDS(DisasContext *ctx, arg_LDS *a) TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_rampD; - a->imm = next_word(ctx); tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ tcg_gen_shli_tl(addr, addr, 16); @@ -1783,7 +1791,6 @@ static bool trans_STS(DisasContext *ctx, arg_STS *a) TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_rampD; - a->imm = next_word(ctx); tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ tcg_gen_shli_tl(addr, addr, 16); @@ -2128,9 +2135,8 @@ static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) static bool trans_IN(DisasContext *ctx, arg_IN *a) { TCGv Rd = cpu_r[a->rd]; - TCGv port = tcg_constant_i32(a->imm); - gen_helper_inb(Rd, tcg_env, port); + gen_inb(ctx, Rd, a->imm); return true; } @@ -2141,9 +2147,8 @@ static bool trans_IN(DisasContext *ctx, arg_IN *a) static bool trans_OUT(DisasContext *ctx, arg_OUT *a) { TCGv Rd = cpu_r[a->rd]; - TCGv port = tcg_constant_i32(a->imm); - gen_helper_outb(tcg_env, port, Rd); + gen_outb(ctx, Rd, a->imm); return true; } @@ -2409,11 +2414,10 @@ static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) static bool trans_SBI(DisasContext *ctx, arg_SBI *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_ori_tl(data, data, 1 << a->bit); - gen_helper_outb(tcg_env, port, data); + gen_outb(ctx, data, a->reg); return true; } @@ -2424,11 +2428,10 @@ static bool trans_SBI(DisasContext *ctx, arg_SBI *a) static bool trans_CBI(DisasContext *ctx, arg_CBI *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_andi_tl(data, data, ~(1 << a->bit)); - gen_helper_outb(tcg_env, port, data); + gen_outb(ctx, data, a->reg); return true; } |