From 352367e8bb53bd4e16abaecbcb9fc0bcadf5881b Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Tue, 22 Oct 2013 02:12:37 +0200 Subject: target-openrisc: Speed up move instruction The OpenRISC architecture does not have its own move register instruction. Instead it uses either "l.addi rd, r0, x" or "l.ori rd, rs, 0" or "l.or rd, rx, r0" The l.ori instruction is automatically optimized but not the l.addi instruction. This patch optimizes for this special case. Signed-off-by: Sebastian Macke Reviewed-by: Jia Liu Signed-off-by: Jia Liu --- target-openrisc/translate.c | 50 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index 8908a2e32b..8276ce73a2 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -904,29 +904,33 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x27: /* l.addi */ LOG_DIS("l.addi r%d, r%d, %d\n", rd, ra, I16); { - int lab = gen_new_label(); - TCGv_i64 ta = tcg_temp_new_i64(); - TCGv_i64 td = tcg_temp_local_new_i64(); - TCGv_i32 res = tcg_temp_local_new_i32(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); - tcg_gen_trunc_i64_i32(res, td); - tcg_gen_shri_i64(td, td, 32); - tcg_gen_andi_i64(td, td, 0x3); - /* Jump to lab when no overflow. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); - tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_gen_mov_i32(cpu_R[rd], res); - tcg_temp_free_i64(ta); - tcg_temp_free_i64(td); - tcg_temp_free_i32(res); - tcg_temp_free_i32(sr_ove); + if (I16 == 0) { + tcg_gen_mov_tl(cpu_R[rd], cpu_R[ra]); + } else { + int lab = gen_new_label(); + TCGv_i64 ta = tcg_temp_new_i64(); + TCGv_i64 td = tcg_temp_local_new_i64(); + TCGv_i32 res = tcg_temp_local_new_i32(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + tcg_gen_extu_i32_i64(ta, cpu_R[ra]); + tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); + tcg_gen_trunc_i64_i32(res, td); + tcg_gen_shri_i64(td, td, 32); + tcg_gen_andi_i64(td, td, 0x3); + /* Jump to lab when no overflow. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); + tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_gen_mov_i32(cpu_R[rd], res); + tcg_temp_free_i64(ta); + tcg_temp_free_i64(td); + tcg_temp_free_i32(res); + tcg_temp_free_i32(sr_ove); + } } break; -- cgit v1.2.1 From da1d77597b29f45bfd290d251ee459a2794112c6 Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Tue, 22 Oct 2013 02:12:38 +0200 Subject: target-openrisc: Remove unnecessary code generated by jump instructions The sr_f variable is only used for the l.bf and l.bnf instructions. For clarity the code is also rewritten using a switch statement instead of if chaining. Signed-off-by: Sebastian Macke Reviewed-by: Jia Liu Signed-off-by: Jia Liu --- target-openrisc/translate.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index 8276ce73a2..91c60ebaae 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -209,42 +209,49 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) static void gen_jump(DisasContext *dc, uint32_t imm, uint32_t reg, uint32_t op0) { target_ulong tmp_pc; - int lab = gen_new_label(); - TCGv sr_f = tcg_temp_new(); /* N26, 26bits imm */ tmp_pc = sign_extend((imm<<2), 26) + dc->pc; - tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); - if (op0 == 0x00) { /* l.j */ + switch (op0) { + case 0x00: /* l.j */ tcg_gen_movi_tl(jmp_pc, tmp_pc); - } else if (op0 == 0x01) { /* l.jal */ + break; + case 0x01: /* l.jal */ tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8)); tcg_gen_movi_tl(jmp_pc, tmp_pc); - } else if (op0 == 0x03) { /* l.bnf */ - tcg_gen_movi_tl(jmp_pc, dc->pc+8); - tcg_gen_brcondi_i32(TCG_COND_EQ, sr_f, SR_F, lab); - tcg_gen_movi_tl(jmp_pc, tmp_pc); - gen_set_label(lab); - } else if (op0 == 0x04) { /* l.bf */ - tcg_gen_movi_tl(jmp_pc, dc->pc+8); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_f, SR_F, lab); - tcg_gen_movi_tl(jmp_pc, tmp_pc); - gen_set_label(lab); - } else if (op0 == 0x11) { /* l.jr */ + break; + case 0x03: /* l.bnf */ + case 0x04: /* l.bf */ + { + int lab = gen_new_label(); + TCGv sr_f = tcg_temp_new(); + tcg_gen_movi_tl(jmp_pc, dc->pc+8); + tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); + tcg_gen_brcondi_i32(op0 == 0x03 ? TCG_COND_EQ : TCG_COND_NE, + sr_f, SR_F, lab); + tcg_gen_movi_tl(jmp_pc, tmp_pc); + gen_set_label(lab); + tcg_temp_free(sr_f); + } + break; + case 0x11: /* l.jr */ tcg_gen_mov_tl(jmp_pc, cpu_R[reg]); - } else if (op0 == 0x12) { /* l.jalr */ + break; + case 0x12: /* l.jalr */ tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8)); tcg_gen_mov_tl(jmp_pc, cpu_R[reg]); - } else { + break; + default: gen_illegal_exception(dc); + break; } - tcg_temp_free(sr_f); dc->delayed_branch = 2; dc->tb_flags |= D_FLAG; gen_sync_flags(dc); } + static void dec_calc(DisasContext *dc, uint32_t insn) { uint32_t op0, op1, op2; -- cgit v1.2.1 From 04359e6bb7f2841031aae645a770583f9c5df3cd Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Tue, 22 Oct 2013 02:12:39 +0200 Subject: target-openrisc: Remove executable flag for every page Pages should be flagged executable only if the tlb executable flag is set or the mmu is off. Signed-off-by: Sebastian Macke Reviewed-by: Jia Liu Signed-off-by: Jia Liu --- target-openrisc/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c index 22d7cbec18..dd487bd0d1 100644 --- a/target-openrisc/mmu.c +++ b/target-openrisc/mmu.c @@ -32,7 +32,7 @@ int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu, int *prot, target_ulong address, int rw) { *physical = address; - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return TLBRET_MATCH; } @@ -187,7 +187,7 @@ int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, if (ret == TLBRET_MATCH) { tlb_set_page(env, address & TARGET_PAGE_MASK, - physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, + physical & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); ret = 0; } else if (ret < 0) { -- cgit v1.2.1 From ae52bd96ceaea36c486d8ffeb798e160f31d3be8 Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Tue, 22 Oct 2013 02:12:40 +0200 Subject: target-openrisc: Correct wrong epcr register in interrupt handler This patch corrects several misbehaviors during an interrupt process. Most of the time the pc is already correct and therefore no special treatment of the exceptions is necessary. Tested by checking crashing programs which otherwise work in or1ksim. Signed-off-by: Sebastian Macke Reviewed-by: Jia Liu Signed-off-by: Jia Liu --- target-openrisc/interrupt.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/target-openrisc/interrupt.c b/target-openrisc/interrupt.c index 16ef4b3e79..2153e7ea7e 100644 --- a/target-openrisc/interrupt.c +++ b/target-openrisc/interrupt.c @@ -30,26 +30,15 @@ void openrisc_cpu_do_interrupt(CPUState *cs) OpenRISCCPU *cpu = OPENRISC_CPU(cs); CPUOpenRISCState *env = &cpu->env; #ifndef CONFIG_USER_ONLY - if (env->flags & D_FLAG) { /* Delay Slot insn */ + + env->epcr = env->pc; + if (env->flags & D_FLAG) { env->flags &= ~D_FLAG; env->sr |= SR_DSX; - if (env->exception_index == EXCP_TICK || - env->exception_index == EXCP_INT || - env->exception_index == EXCP_SYSCALL || - env->exception_index == EXCP_FPE) { - env->epcr = env->jmp_pc; - } else { - env->epcr = env->pc - 4; - } - } else { - if (env->exception_index == EXCP_TICK || - env->exception_index == EXCP_INT || - env->exception_index == EXCP_SYSCALL || - env->exception_index == EXCP_FPE) { - env->epcr = env->npc; - } else { - env->epcr = env->pc; - } + env->epcr -= 4; + } + if (env->exception_index == EXCP_SYSCALL) { + env->epcr += 4; } /* For machine-state changed between user-mode and supervisor mode, -- cgit v1.2.1 From d51552176a2ab5e80a211514aa1339fe2575ec2a Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Tue, 22 Oct 2013 02:12:41 +0200 Subject: openrisc-timer: Reduce overhead, Separate clock update functions The clock value is only evaluated when really necessary reducing the overhead of the timer handling. This also solves a problem in the way the Linux kernel handles the timer and the expected accuracy. The old version could lead to inaccurate timings. Signed-off-by: Sebastian Macke Reviewed-by: Jia Liu Signed-off-by: Jia Liu --- hw/openrisc/cputimer.c | 29 +++++++++++++++++++---------- target-openrisc/cpu.h | 1 + target-openrisc/sys_helper.c | 38 ++++++++++++++++++-------------------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 988ca20898..9c54945107 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -30,19 +30,28 @@ static int is_counting; void cpu_openrisc_count_update(OpenRISCCPU *cpu) { - uint64_t now, next; - uint32_t wait; + uint64_t now; - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (!is_counting) { - timer_del(cpu->env.timer); - last_clk = now; return; } - + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ, get_ticks_per_sec()); last_clk = now; +} + +void cpu_openrisc_timer_update(OpenRISCCPU *cpu) +{ + uint32_t wait; + uint64_t now, next; + + if (!is_counting) { + return; + } + + cpu_openrisc_count_update(cpu); + now = last_clk; if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) { wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1; @@ -50,7 +59,6 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu) } else { wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP); } - next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); timer_mod(cpu->env.timer, next); } @@ -63,8 +71,9 @@ void cpu_openrisc_count_start(OpenRISCCPU *cpu) void cpu_openrisc_count_stop(OpenRISCCPU *cpu) { - is_counting = 0; + timer_del(cpu->env.timer); cpu_openrisc_count_update(cpu); + is_counting = 0; } static void openrisc_timer_cb(void *opaque) @@ -84,15 +93,15 @@ static void openrisc_timer_cb(void *opaque) break; case TIMER_INTR: cpu->env.ttcr = 0; - cpu_openrisc_count_start(cpu); break; case TIMER_SHOT: cpu_openrisc_count_stop(cpu); break; case TIMER_CONT: - cpu_openrisc_count_start(cpu); break; } + + cpu_openrisc_timer_update(cpu); } void cpu_openrisc_clock_init(OpenRISCCPU *cpu) diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index 8fd0bc0bf0..0f9efdf6de 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -373,6 +373,7 @@ void cpu_openrisc_pic_init(OpenRISCCPU *cpu); /* hw/openrisc_timer.c */ void cpu_openrisc_clock_init(OpenRISCCPU *cpu); void cpu_openrisc_count_update(OpenRISCCPU *cpu); +void cpu_openrisc_timer_update(OpenRISCCPU *cpu); void cpu_openrisc_count_start(OpenRISCCPU *cpu); void cpu_openrisc_count_stop(OpenRISCCPU *cpu); diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c index cccbc0e939..f1165885d9 100644 --- a/target-openrisc/sys_helper.c +++ b/target-openrisc/sys_helper.c @@ -127,33 +127,31 @@ void HELPER(mtspr)(CPUOpenRISCState *env, break; case TO_SPR(10, 0): /* TTMR */ { + if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { + switch (rb & TTMR_M) { + case TIMER_NONE: + cpu_openrisc_count_stop(cpu); + break; + case TIMER_INTR: + case TIMER_SHOT: + case TIMER_CONT: + cpu_openrisc_count_start(cpu); + break; + default: + break; + } + } + int ip = env->ttmr & TTMR_IP; if (rb & TTMR_IP) { /* Keep IP bit. */ - env->ttmr = (rb & ~TTMR_IP) + ip; + env->ttmr = (rb & ~TTMR_IP) | ip; } else { /* Clear IP bit. */ env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_count_update(cpu); - - switch (env->ttmr & TTMR_M) { - case TIMER_NONE: - cpu_openrisc_count_stop(cpu); - break; - case TIMER_INTR: - cpu_openrisc_count_start(cpu); - break; - case TIMER_SHOT: - cpu_openrisc_count_start(cpu); - break; - case TIMER_CONT: - cpu_openrisc_count_start(cpu); - break; - default: - break; - } + cpu_openrisc_timer_update(cpu); } break; @@ -162,7 +160,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, if (env->ttmr & TIMER_NONE) { return; } - cpu_openrisc_count_start(cpu); + cpu_openrisc_timer_update(cpu); break; default: -- cgit v1.2.1 From 93147a180c10b97bf9575a87e01c9a1c93e6c9ce Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Tue, 22 Oct 2013 02:12:42 +0200 Subject: target-openrisc: Correct memory bounds checking for the tlb buffers The mtspr and mfspr routines didn't check for the correct memory boundaries. This fixes a segmentation fault while booting Linux. Signed-off-by: Sebastian Macke Reviewed-by: Jia Liu Signed-off-by: Jia Liu --- target-openrisc/sys_helper.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c index f1165885d9..be06c4565b 100644 --- a/target-openrisc/sys_helper.c +++ b/target-openrisc/sys_helper.c @@ -81,7 +81,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, case TO_SPR(0, 64): /* ESR */ env->esr = rb; break; - case TO_SPR(1, 512) ... TO_SPR(1, 639): /* DTLBW0MR 0-127 */ + case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */ idx = spr - TO_SPR(1, 512); if (!(rb & 1)) { tlb_flush_page(env, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK); @@ -89,7 +89,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, env->tlb->dtlb[0][idx].mr = rb; break; - case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */ + case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */ idx = spr - TO_SPR(1, 640); env->tlb->dtlb[0][idx].tr = rb; break; @@ -100,7 +100,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */ case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ break; - case TO_SPR(2, 512) ... TO_SPR(2, 639): /* ITLBW0MR 0-127 */ + case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */ idx = spr - TO_SPR(2, 512); if (!(rb & 1)) { tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK); @@ -108,7 +108,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, env->tlb->itlb[0][idx].mr = rb; break; - case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */ + case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */ idx = spr - TO_SPR(2, 640); env->tlb->itlb[0][idx].tr = rb; break; @@ -212,11 +212,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(0, 64): /* ESR */ return env->esr; - case TO_SPR(1, 512) ... TO_SPR(1, 639): /* DTLBW0MR 0-127 */ + case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */ idx = spr - TO_SPR(1, 512); return env->tlb->dtlb[0][idx].mr; - case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */ + case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */ idx = spr - TO_SPR(1, 640); return env->tlb->dtlb[0][idx].tr; @@ -228,11 +228,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ break; - case TO_SPR(2, 512) ... TO_SPR(2, 639): /* ITLBW0MR 0-127 */ + case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */ idx = spr - TO_SPR(2, 512); return env->tlb->itlb[0][idx].mr; - case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */ + case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */ idx = spr - TO_SPR(2, 640); return env->tlb->itlb[0][idx].tr; -- cgit v1.2.1 From 14a650ec25ca93a626397783d6c6e840ec2502c6 Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Tue, 22 Oct 2013 02:12:45 +0200 Subject: target-openrisc: Correct carry flag check of l.addc and l.addic test cases The test cases did not correctly test for the carry flag. Signed-off-by: Sebastian Macke Reviewed-by: Jia Liu Signed-off-by: Jia Liu --- tests/tcg/openrisc/test_addc.c | 8 +++++--- tests/tcg/openrisc/test_addic.c | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/tcg/openrisc/test_addc.c b/tests/tcg/openrisc/test_addc.c index 05d18f8ce5..a8f756a69b 100644 --- a/tests/tcg/openrisc/test_addc.c +++ b/tests/tcg/openrisc/test_addc.c @@ -7,9 +7,10 @@ int main(void) b = 0x01; c = 0xffffffff; - result = 1; + result = 0; __asm - ("l.addc %0, %1, %2\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addc %0, %1, %2\n\t" : "=r"(a) : "r"(b), "r"(c) ); @@ -22,7 +23,8 @@ int main(void) c = 0xffffffff; result = 0x80000001; __asm - ("l.addc %0, %1, %2\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addc %0, %1, %2\n\t" "l.movhi %2, 0x7fff\n\t" "l.ori %2, %2, 0xffff\n\t" "l.addc %0, %1, %2\n\t" diff --git a/tests/tcg/openrisc/test_addic.c b/tests/tcg/openrisc/test_addic.c index 4ba7432521..857aaa1330 100644 --- a/tests/tcg/openrisc/test_addic.c +++ b/tests/tcg/openrisc/test_addic.c @@ -6,9 +6,10 @@ int main(void) int result; a = 1; - result = 0x1; + result = 0x0; __asm - ("l.addic %0, %0, 0xffff\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addic %0, %0, 0xffff\n\t" : "+r"(a) ); if (a != result) { @@ -16,10 +17,11 @@ int main(void) return -1; } - a = 0x1; + a = -1; result = 0x201; __asm - ("l.addic %0, %0, 0xffff\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addic %0, %0, 0x1\n\t" "l.ori %0, r0, 0x100\n\t" "l.addic %0, %0, 0x100\n\t" : "+r"(a) -- cgit v1.2.1