diff mbox

[v9,11/15] target-or32: Add system instructions

Message ID 1342154108-798-12-git-send-email-proljc@gmail.com
State New
Headers show

Commit Message

Jia Liu July 13, 2012, 4:35 a.m. UTC
Add OpenRISC system instructions.

Signed-off-by: Jia Liu <proljc@gmail.com>
---
 target-openrisc/Makefile.objs |    2 +-
 target-openrisc/cpu.h         |    3 +
 target-openrisc/helper.h      |    4 +
 target-openrisc/sys_helper.c  |  287 +++++++++++++++++++++++++++++++++++++++++
 target-openrisc/translate.c   |   10 ++
 5 files changed, 305 insertions(+), 1 deletion(-)
 create mode 100644 target-openrisc/sys_helper.c

Comments

Max Filippov July 13, 2012, 9:27 a.m. UTC | #1
On Fri, Jul 13, 2012 at 8:35 AM, Jia Liu <proljc@gmail.com> wrote:
> Add OpenRISC system instructions.
>
> Signed-off-by: Jia Liu <proljc@gmail.com>
> ---
>  target-openrisc/Makefile.objs |    2 +-
>  target-openrisc/cpu.h         |    3 +
>  target-openrisc/helper.h      |    4 +
>  target-openrisc/sys_helper.c  |  287 +++++++++++++++++++++++++++++++++++++++++
>  target-openrisc/translate.c   |   10 ++
>  5 files changed, 305 insertions(+), 1 deletion(-)
>  create mode 100644 target-openrisc/sys_helper.c
>
> diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
> index 926fc2f..44dc539 100644
> --- a/target-openrisc/Makefile.objs
> +++ b/target-openrisc/Makefile.objs
> @@ -1,4 +1,4 @@
>  obj-$(CONFIG_SOFTMMU) += machine.o
>  obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
>  obj-y += exception_helper.o fpu_helper.o int_helper.o \
> -         interrupt_helper.o mmu_helper.o
> +         interrupt_helper.o mmu_helper.o sys_helper.o
> diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
> index df07eaf..6506665 100644
> --- a/target-openrisc/cpu.h
> +++ b/target-openrisc/cpu.h
> @@ -80,6 +80,9 @@ enum {
>                                        (reg) |= ((v & 0x1f) << 2);\
>                                    } while (0)
>
> +/* Version Register */
> +#define SPR_VR 0xFFFF003F
> +
>  /* Internal flags, delay slot flag */
>  #define D_FLAG    1
>
> diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h
> index 6eb259a..836a70b 100644
> --- a/target-openrisc/helper.h
> +++ b/target-openrisc/helper.h
> @@ -63,4 +63,8 @@ DEF_HELPER_FLAGS_3(mul32, 0, tl, env, tl, tl)
>  /* interrupt */
>  DEF_HELPER_FLAGS_1(rfe, 0, void, env)
>
> +/* sys */
> +DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
> +DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
> +
>  #include "def-helper.h"
> diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
> new file mode 100644
> index 0000000..7ff8e15
> --- /dev/null
> +++ b/target-openrisc/sys_helper.c
> @@ -0,0 +1,287 @@
> +/*
> + * OpenRISC system instructions helper routines
> + *
> + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
> + *                         Zhizhou Zhang <etouzh@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cpu.h"
> +#include "helper.h"
> +
> +#define TO_SPR(group, number) (((group) << 11) + (number))
> +
> +void HELPER(mtspr)(CPUOpenRISCState *env,
> +                   target_ulong ra, target_ulong rb, target_ulong offset)
> +{
> +#ifndef CONFIG_USER_ONLY
> +    int spr = (ra | offset);
> +    int idx;
> +
> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
> +
> +    switch (spr) {
> +    case TO_SPR(0, 0): /* VR */
> +        env->vr = rb;
> +        break;
> +
> +    case TO_SPR(0, 16): /* NPC */
> +        env->npc = rb;
> +        break;
> +
> +    case TO_SPR(0, 17): /* SR */
> +        if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
> +            (rb & (SR_IME | SR_DME | SR_SM))) {
> +            tlb_flush(env, 1);
> +        }
> +        env->sr = rb;
> +        env->sr |= SR_FO;      /* FO is const equal to 1 */
> +        if (env->sr & SR_DME) {
> +            env->tlb->cpu_openrisc_map_address_data =
> +                &cpu_openrisc_get_phys_data;
> +        } else {
> +            env->tlb->cpu_openrisc_map_address_data =
> +                &cpu_openrisc_get_phys_nommu;
> +        }
> +
> +        if (env->sr & SR_IME) {
> +            env->tlb->cpu_openrisc_map_address_code =
> +                &cpu_openrisc_get_phys_code;
> +        } else {
> +            env->tlb->cpu_openrisc_map_address_code =
> +                &cpu_openrisc_get_phys_nommu;
> +        }
> +        break;
> +
> +    case TO_SPR(0, 18): /* PPC */
> +        env->ppc = rb;
> +        break;
> +
> +    case TO_SPR(0, 32): /* EPCR */
> +        env->epcr = rb;
> +        break;
> +
> +    case TO_SPR(0, 48): /* EEAR */
> +        env->eear = rb;
> +        break;
> +
> +    case TO_SPR(0, 64): /* ESR */
> +        env->esr = rb;
> +        break;
> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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);
> +        }
> +        env->tlb->dtlb[0][idx].mr = rb;
> +        break;
> +
> +    case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */
> +        idx = spr - TO_SPR(1, 640);
> +        env->tlb->dtlb[0][idx].tr = rb;
> +        break;
> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
> +    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 */
> +        idx = spr - TO_SPR(2, 512);
> +        if (!(rb & 1)) {
> +            tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
> +        }
> +        env->tlb->itlb[0][idx].mr = rb;
> +        break;
> +
> +    case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */
> +        idx = spr - TO_SPR(2, 640);
> +        env->tlb->itlb[0][idx].tr = rb;
> +        break;
> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
> +        break;
> +    case TO_SPR(9, 0):  /* PICMR */
> +        env->picmr |= rb;
> +        break;
> +    case TO_SPR(9, 2):  /* PICSR */
> +        env->picsr &= ~rb;
> +        break;
> +    case TO_SPR(10, 0): /* TTMR */
> +        {
> +            int ip = env->ttmr & TTMR_IP;
> +
> +            if (rb & TTMR_IP) {    /* Keep IP bit.  */
> +                env->ttmr = (rb & ~TTMR_IP) + ip;
> +            } else {    /* Clear IP bit.  */
> +                env->ttmr = rb & ~TTMR_IP;
> +                env->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;
> +            }
> +        }
> +        break;
> +
> +    case TO_SPR(10, 1): /* TTCR */
> +        env->ttcr = rb;
> +        if (env->ttmr & TIMER_NONE) {
> +            return;
> +        }
> +        cpu_openrisc_count_start(cpu);
> +        break;
> +    default:
> +
> +        break;
> +    }
> +#endif
> +}
> +
> +target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
> +                           target_ulong rd, target_ulong ra, uint32_t offset)
> +{
> +#ifndef CONFIG_USER_ONLY
> +    int spr = (ra | offset);
> +    int idx;
> +
> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
> +
> +    switch (spr) {
> +    case TO_SPR(0, 0): /* VR */
> +        return env->vr & SPR_VR;
> +
> +    case TO_SPR(0, 1): /* UPR */
> +        return env->upr;    /* TT, DM, IM, UP present */
> +
> +    case TO_SPR(0, 2): /* CPUCFGR */
> +        return env->cpucfgr;
> +
> +    case TO_SPR(0, 3): /* DMMUCFGR */
> +        return env->dmmucfgr;    /* 1Way, 64 entries */
> +
> +    case TO_SPR(0, 4): /* IMMUCFGR */
> +        return env->immucfgr;
> +
> +    case TO_SPR(0, 16): /* NPC */
> +        return env->npc;
> +
> +    case TO_SPR(0, 17): /* SR */
> +        return env->sr;
> +
> +    case TO_SPR(0, 18): /* PPC */
> +        return env->ppc;
> +
> +    case TO_SPR(0, 32): /* EPCR */
> +        return env->epcr;
> +
> +    case TO_SPR(0, 48): /* EEAR */
> +        return env->eear;
> +
> +    case TO_SPR(0, 64): /* ESR */
> +        return env->esr;
> +
> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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 */
> +        idx = spr - TO_SPR(1, 640);
> +        return env->tlb->dtlb[0][idx].tr;
> +
> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
> +    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 */
> +        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 */
> +        idx = spr - TO_SPR(2, 640);
> +        return env->tlb->itlb[0][idx].tr;
> +
> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
> +        break;
> +
> +    case TO_SPR(9, 0):  /* PICMR */
> +        return env->picmr;
> +
> +    case TO_SPR(9, 2):  /* PICSR */
> +        return env->picsr;
> +
> +    case TO_SPR(10, 0): /* TTMR */
> +        return env->ttmr;
> +
> +    case TO_SPR(10, 1): /* TTCR */
> +        cpu_openrisc_count_update(cpu);
> +        return env->ttcr;
> +
> +    default:
> +        break;
> +    }
> +#endif
> +
> +/*If we later need to add tracepoints (or debug printfs) for the return
> +value, it may be useful to structure the code like this:
> +
> +target_ulong ret = 0;
> +
> +switch() {
> +case x:
> + ret = y;
> + break;
> +case z:
> + ret = 42;
> + break;
> +...
> +}
> +
> +later something like trace_spr_read(ret);
> +
> +return ret;*/
> +
> +    /* for rd is passed in, if rd unchanged, just keep it back.  */
> +    return rd;
> +}
> diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
> index ed25604..8069edb 100644
> --- a/target-openrisc/translate.c
> +++ b/target-openrisc/translate.c
> @@ -995,10 +995,20 @@ static void dec_misc(DisasContext *dc, uint32_t insn)
>
>      case 0x2d:    /* l.mfspr */
>          LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
> +        {
> +            TCGv_i32 ti = tcg_const_i32(I16);
> +            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
> +            tcg_temp_free_i32(ti);
> +        }
>          break;
>
>      case 0x30:    /* l.mtspr */
>          LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
> +        {
> +            TCGv_i32 im = tcg_const_i32(tmp);
> +            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
> +            tcg_temp_free_i32(im);
> +        }
>          break;

openrisc ISA says that l.mtspr/l.mfspr are only accessible in supervisor mode,
but I don't see where it is enforced.
Jia Liu July 14, 2012, 11:12 a.m. UTC | #2
Hi Max

On Fri, Jul 13, 2012 at 5:27 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
> On Fri, Jul 13, 2012 at 8:35 AM, Jia Liu <proljc@gmail.com> wrote:
>> Add OpenRISC system instructions.
>>
>> Signed-off-by: Jia Liu <proljc@gmail.com>
>> ---
>>  target-openrisc/Makefile.objs |    2 +-
>>  target-openrisc/cpu.h         |    3 +
>>  target-openrisc/helper.h      |    4 +
>>  target-openrisc/sys_helper.c  |  287 +++++++++++++++++++++++++++++++++++++++++
>>  target-openrisc/translate.c   |   10 ++
>>  5 files changed, 305 insertions(+), 1 deletion(-)
>>  create mode 100644 target-openrisc/sys_helper.c
>>
>> diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
>> index 926fc2f..44dc539 100644
>> --- a/target-openrisc/Makefile.objs
>> +++ b/target-openrisc/Makefile.objs
>> @@ -1,4 +1,4 @@
>>  obj-$(CONFIG_SOFTMMU) += machine.o
>>  obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
>>  obj-y += exception_helper.o fpu_helper.o int_helper.o \
>> -         interrupt_helper.o mmu_helper.o
>> +         interrupt_helper.o mmu_helper.o sys_helper.o
>> diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
>> index df07eaf..6506665 100644
>> --- a/target-openrisc/cpu.h
>> +++ b/target-openrisc/cpu.h
>> @@ -80,6 +80,9 @@ enum {
>>                                        (reg) |= ((v & 0x1f) << 2);\
>>                                    } while (0)
>>
>> +/* Version Register */
>> +#define SPR_VR 0xFFFF003F
>> +
>>  /* Internal flags, delay slot flag */
>>  #define D_FLAG    1
>>
>> diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h
>> index 6eb259a..836a70b 100644
>> --- a/target-openrisc/helper.h
>> +++ b/target-openrisc/helper.h
>> @@ -63,4 +63,8 @@ DEF_HELPER_FLAGS_3(mul32, 0, tl, env, tl, tl)
>>  /* interrupt */
>>  DEF_HELPER_FLAGS_1(rfe, 0, void, env)
>>
>> +/* sys */
>> +DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
>> +DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
>> +
>>  #include "def-helper.h"
>> diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
>> new file mode 100644
>> index 0000000..7ff8e15
>> --- /dev/null
>> +++ b/target-openrisc/sys_helper.c
>> @@ -0,0 +1,287 @@
>> +/*
>> + * OpenRISC system instructions helper routines
>> + *
>> + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
>> + *                         Zhizhou Zhang <etouzh@gmail.com>
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include "cpu.h"
>> +#include "helper.h"
>> +
>> +#define TO_SPR(group, number) (((group) << 11) + (number))
>> +
>> +void HELPER(mtspr)(CPUOpenRISCState *env,
>> +                   target_ulong ra, target_ulong rb, target_ulong offset)
>> +{
>> +#ifndef CONFIG_USER_ONLY
>> +    int spr = (ra | offset);
>> +    int idx;
>> +
>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>> +
>> +    switch (spr) {
>> +    case TO_SPR(0, 0): /* VR */
>> +        env->vr = rb;
>> +        break;
>> +
>> +    case TO_SPR(0, 16): /* NPC */
>> +        env->npc = rb;
>> +        break;
>> +
>> +    case TO_SPR(0, 17): /* SR */
>> +        if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
>> +            (rb & (SR_IME | SR_DME | SR_SM))) {
>> +            tlb_flush(env, 1);
>> +        }
>> +        env->sr = rb;
>> +        env->sr |= SR_FO;      /* FO is const equal to 1 */
>> +        if (env->sr & SR_DME) {
>> +            env->tlb->cpu_openrisc_map_address_data =
>> +                &cpu_openrisc_get_phys_data;
>> +        } else {
>> +            env->tlb->cpu_openrisc_map_address_data =
>> +                &cpu_openrisc_get_phys_nommu;
>> +        }
>> +
>> +        if (env->sr & SR_IME) {
>> +            env->tlb->cpu_openrisc_map_address_code =
>> +                &cpu_openrisc_get_phys_code;
>> +        } else {
>> +            env->tlb->cpu_openrisc_map_address_code =
>> +                &cpu_openrisc_get_phys_nommu;
>> +        }
>> +        break;
>> +
>> +    case TO_SPR(0, 18): /* PPC */
>> +        env->ppc = rb;
>> +        break;
>> +
>> +    case TO_SPR(0, 32): /* EPCR */
>> +        env->epcr = rb;
>> +        break;
>> +
>> +    case TO_SPR(0, 48): /* EEAR */
>> +        env->eear = rb;
>> +        break;
>> +
>> +    case TO_SPR(0, 64): /* ESR */
>> +        env->esr = rb;
>> +        break;
>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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);
>> +        }
>> +        env->tlb->dtlb[0][idx].mr = rb;
>> +        break;
>> +
>> +    case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */
>> +        idx = spr - TO_SPR(1, 640);
>> +        env->tlb->dtlb[0][idx].tr = rb;
>> +        break;
>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>> +    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 */
>> +        idx = spr - TO_SPR(2, 512);
>> +        if (!(rb & 1)) {
>> +            tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
>> +        }
>> +        env->tlb->itlb[0][idx].mr = rb;
>> +        break;
>> +
>> +    case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */
>> +        idx = spr - TO_SPR(2, 640);
>> +        env->tlb->itlb[0][idx].tr = rb;
>> +        break;
>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>> +        break;
>> +    case TO_SPR(9, 0):  /* PICMR */
>> +        env->picmr |= rb;
>> +        break;
>> +    case TO_SPR(9, 2):  /* PICSR */
>> +        env->picsr &= ~rb;
>> +        break;
>> +    case TO_SPR(10, 0): /* TTMR */
>> +        {
>> +            int ip = env->ttmr & TTMR_IP;
>> +
>> +            if (rb & TTMR_IP) {    /* Keep IP bit.  */
>> +                env->ttmr = (rb & ~TTMR_IP) + ip;
>> +            } else {    /* Clear IP bit.  */
>> +                env->ttmr = rb & ~TTMR_IP;
>> +                env->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;
>> +            }
>> +        }
>> +        break;
>> +
>> +    case TO_SPR(10, 1): /* TTCR */
>> +        env->ttcr = rb;
>> +        if (env->ttmr & TIMER_NONE) {
>> +            return;
>> +        }
>> +        cpu_openrisc_count_start(cpu);
>> +        break;
>> +    default:
>> +
>> +        break;
>> +    }
>> +#endif
>> +}
>> +
>> +target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
>> +                           target_ulong rd, target_ulong ra, uint32_t offset)
>> +{
>> +#ifndef CONFIG_USER_ONLY
>> +    int spr = (ra | offset);
>> +    int idx;
>> +
>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>> +
>> +    switch (spr) {
>> +    case TO_SPR(0, 0): /* VR */
>> +        return env->vr & SPR_VR;
>> +
>> +    case TO_SPR(0, 1): /* UPR */
>> +        return env->upr;    /* TT, DM, IM, UP present */
>> +
>> +    case TO_SPR(0, 2): /* CPUCFGR */
>> +        return env->cpucfgr;
>> +
>> +    case TO_SPR(0, 3): /* DMMUCFGR */
>> +        return env->dmmucfgr;    /* 1Way, 64 entries */
>> +
>> +    case TO_SPR(0, 4): /* IMMUCFGR */
>> +        return env->immucfgr;
>> +
>> +    case TO_SPR(0, 16): /* NPC */
>> +        return env->npc;
>> +
>> +    case TO_SPR(0, 17): /* SR */
>> +        return env->sr;
>> +
>> +    case TO_SPR(0, 18): /* PPC */
>> +        return env->ppc;
>> +
>> +    case TO_SPR(0, 32): /* EPCR */
>> +        return env->epcr;
>> +
>> +    case TO_SPR(0, 48): /* EEAR */
>> +        return env->eear;
>> +
>> +    case TO_SPR(0, 64): /* ESR */
>> +        return env->esr;
>> +
>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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 */
>> +        idx = spr - TO_SPR(1, 640);
>> +        return env->tlb->dtlb[0][idx].tr;
>> +
>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>> +    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 */
>> +        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 */
>> +        idx = spr - TO_SPR(2, 640);
>> +        return env->tlb->itlb[0][idx].tr;
>> +
>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>> +        break;
>> +
>> +    case TO_SPR(9, 0):  /* PICMR */
>> +        return env->picmr;
>> +
>> +    case TO_SPR(9, 2):  /* PICSR */
>> +        return env->picsr;
>> +
>> +    case TO_SPR(10, 0): /* TTMR */
>> +        return env->ttmr;
>> +
>> +    case TO_SPR(10, 1): /* TTCR */
>> +        cpu_openrisc_count_update(cpu);
>> +        return env->ttcr;
>> +
>> +    default:
>> +        break;
>> +    }
>> +#endif
>> +
>> +/*If we later need to add tracepoints (or debug printfs) for the return
>> +value, it may be useful to structure the code like this:
>> +
>> +target_ulong ret = 0;
>> +
>> +switch() {
>> +case x:
>> + ret = y;
>> + break;
>> +case z:
>> + ret = 42;
>> + break;
>> +...
>> +}
>> +
>> +later something like trace_spr_read(ret);
>> +
>> +return ret;*/
>> +
>> +    /* for rd is passed in, if rd unchanged, just keep it back.  */
>> +    return rd;
>> +}
>> diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
>> index ed25604..8069edb 100644
>> --- a/target-openrisc/translate.c
>> +++ b/target-openrisc/translate.c
>> @@ -995,10 +995,20 @@ static void dec_misc(DisasContext *dc, uint32_t insn)
>>
>>      case 0x2d:    /* l.mfspr */
>>          LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>> +        {
>> +            TCGv_i32 ti = tcg_const_i32(I16);
>> +            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>> +            tcg_temp_free_i32(ti);
>> +        }
>>          break;
>>
>>      case 0x30:    /* l.mtspr */
>>          LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>> +        {
>> +            TCGv_i32 im = tcg_const_i32(tmp);
>> +            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>> +            tcg_temp_free_i32(im);
>> +        }
>>          break;
>
> openrisc ISA says that l.mtspr/l.mfspr are only accessible in supervisor mode,
> but I don't see where it is enforced.
>

Thank you for mind me, it is the new code. Is it OK?

#ifndef CONFIG_USER_ONLY
    case 0x2d:    /* l.mfspr */
        LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
        {
            TCGv_i32 ti = tcg_const_i32(I16);
            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
            tcg_temp_free_i32(ti);
        }
        break;

    case 0x30:    /* l.mtspr */
        LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
        {
            TCGv_i32 im = tcg_const_i32(tmp);
            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
            tcg_temp_free_i32(im);
        }
        break;
#endif


> --
> Thanks.
> -- Max

Regards,
Jia
Blue Swirl July 14, 2012, 1:19 p.m. UTC | #3
On Sat, Jul 14, 2012 at 11:12 AM, Jia Liu <proljc@gmail.com> wrote:
> Hi Max
>
> On Fri, Jul 13, 2012 at 5:27 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>> On Fri, Jul 13, 2012 at 8:35 AM, Jia Liu <proljc@gmail.com> wrote:
>>> Add OpenRISC system instructions.
>>>
>>> Signed-off-by: Jia Liu <proljc@gmail.com>
>>> ---
>>>  target-openrisc/Makefile.objs |    2 +-
>>>  target-openrisc/cpu.h         |    3 +
>>>  target-openrisc/helper.h      |    4 +
>>>  target-openrisc/sys_helper.c  |  287 +++++++++++++++++++++++++++++++++++++++++
>>>  target-openrisc/translate.c   |   10 ++
>>>  5 files changed, 305 insertions(+), 1 deletion(-)
>>>  create mode 100644 target-openrisc/sys_helper.c
>>>
>>> diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
>>> index 926fc2f..44dc539 100644
>>> --- a/target-openrisc/Makefile.objs
>>> +++ b/target-openrisc/Makefile.objs
>>> @@ -1,4 +1,4 @@
>>>  obj-$(CONFIG_SOFTMMU) += machine.o
>>>  obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
>>>  obj-y += exception_helper.o fpu_helper.o int_helper.o \
>>> -         interrupt_helper.o mmu_helper.o
>>> +         interrupt_helper.o mmu_helper.o sys_helper.o
>>> diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
>>> index df07eaf..6506665 100644
>>> --- a/target-openrisc/cpu.h
>>> +++ b/target-openrisc/cpu.h
>>> @@ -80,6 +80,9 @@ enum {
>>>                                        (reg) |= ((v & 0x1f) << 2);\
>>>                                    } while (0)
>>>
>>> +/* Version Register */
>>> +#define SPR_VR 0xFFFF003F
>>> +
>>>  /* Internal flags, delay slot flag */
>>>  #define D_FLAG    1
>>>
>>> diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h
>>> index 6eb259a..836a70b 100644
>>> --- a/target-openrisc/helper.h
>>> +++ b/target-openrisc/helper.h
>>> @@ -63,4 +63,8 @@ DEF_HELPER_FLAGS_3(mul32, 0, tl, env, tl, tl)
>>>  /* interrupt */
>>>  DEF_HELPER_FLAGS_1(rfe, 0, void, env)
>>>
>>> +/* sys */
>>> +DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
>>> +DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
>>> +
>>>  #include "def-helper.h"
>>> diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
>>> new file mode 100644
>>> index 0000000..7ff8e15
>>> --- /dev/null
>>> +++ b/target-openrisc/sys_helper.c
>>> @@ -0,0 +1,287 @@
>>> +/*
>>> + * OpenRISC system instructions helper routines
>>> + *
>>> + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
>>> + *                         Zhizhou Zhang <etouzh@gmail.com>
>>> + *
>>> + * This library is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2 of the License, or (at your option) any later version.
>>> + *
>>> + * This library is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +#include "cpu.h"
>>> +#include "helper.h"
>>> +
>>> +#define TO_SPR(group, number) (((group) << 11) + (number))
>>> +
>>> +void HELPER(mtspr)(CPUOpenRISCState *env,
>>> +                   target_ulong ra, target_ulong rb, target_ulong offset)
>>> +{
>>> +#ifndef CONFIG_USER_ONLY
>>> +    int spr = (ra | offset);
>>> +    int idx;
>>> +
>>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>>> +
>>> +    switch (spr) {
>>> +    case TO_SPR(0, 0): /* VR */
>>> +        env->vr = rb;
>>> +        break;
>>> +
>>> +    case TO_SPR(0, 16): /* NPC */
>>> +        env->npc = rb;
>>> +        break;
>>> +
>>> +    case TO_SPR(0, 17): /* SR */
>>> +        if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
>>> +            (rb & (SR_IME | SR_DME | SR_SM))) {
>>> +            tlb_flush(env, 1);
>>> +        }
>>> +        env->sr = rb;
>>> +        env->sr |= SR_FO;      /* FO is const equal to 1 */
>>> +        if (env->sr & SR_DME) {
>>> +            env->tlb->cpu_openrisc_map_address_data =
>>> +                &cpu_openrisc_get_phys_data;
>>> +        } else {
>>> +            env->tlb->cpu_openrisc_map_address_data =
>>> +                &cpu_openrisc_get_phys_nommu;
>>> +        }
>>> +
>>> +        if (env->sr & SR_IME) {
>>> +            env->tlb->cpu_openrisc_map_address_code =
>>> +                &cpu_openrisc_get_phys_code;
>>> +        } else {
>>> +            env->tlb->cpu_openrisc_map_address_code =
>>> +                &cpu_openrisc_get_phys_nommu;
>>> +        }
>>> +        break;
>>> +
>>> +    case TO_SPR(0, 18): /* PPC */
>>> +        env->ppc = rb;
>>> +        break;
>>> +
>>> +    case TO_SPR(0, 32): /* EPCR */
>>> +        env->epcr = rb;
>>> +        break;
>>> +
>>> +    case TO_SPR(0, 48): /* EEAR */
>>> +        env->eear = rb;
>>> +        break;
>>> +
>>> +    case TO_SPR(0, 64): /* ESR */
>>> +        env->esr = rb;
>>> +        break;
>>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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);
>>> +        }
>>> +        env->tlb->dtlb[0][idx].mr = rb;
>>> +        break;
>>> +
>>> +    case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */
>>> +        idx = spr - TO_SPR(1, 640);
>>> +        env->tlb->dtlb[0][idx].tr = rb;
>>> +        break;
>>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>>> +    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 */
>>> +        idx = spr - TO_SPR(2, 512);
>>> +        if (!(rb & 1)) {
>>> +            tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
>>> +        }
>>> +        env->tlb->itlb[0][idx].mr = rb;
>>> +        break;
>>> +
>>> +    case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */
>>> +        idx = spr - TO_SPR(2, 640);
>>> +        env->tlb->itlb[0][idx].tr = rb;
>>> +        break;
>>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>>> +        break;
>>> +    case TO_SPR(9, 0):  /* PICMR */
>>> +        env->picmr |= rb;
>>> +        break;
>>> +    case TO_SPR(9, 2):  /* PICSR */
>>> +        env->picsr &= ~rb;
>>> +        break;
>>> +    case TO_SPR(10, 0): /* TTMR */
>>> +        {
>>> +            int ip = env->ttmr & TTMR_IP;
>>> +
>>> +            if (rb & TTMR_IP) {    /* Keep IP bit.  */
>>> +                env->ttmr = (rb & ~TTMR_IP) + ip;
>>> +            } else {    /* Clear IP bit.  */
>>> +                env->ttmr = rb & ~TTMR_IP;
>>> +                env->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;
>>> +            }
>>> +        }
>>> +        break;
>>> +
>>> +    case TO_SPR(10, 1): /* TTCR */
>>> +        env->ttcr = rb;
>>> +        if (env->ttmr & TIMER_NONE) {
>>> +            return;
>>> +        }
>>> +        cpu_openrisc_count_start(cpu);
>>> +        break;
>>> +    default:
>>> +
>>> +        break;
>>> +    }
>>> +#endif
>>> +}
>>> +
>>> +target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
>>> +                           target_ulong rd, target_ulong ra, uint32_t offset)
>>> +{
>>> +#ifndef CONFIG_USER_ONLY
>>> +    int spr = (ra | offset);
>>> +    int idx;
>>> +
>>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>>> +
>>> +    switch (spr) {
>>> +    case TO_SPR(0, 0): /* VR */
>>> +        return env->vr & SPR_VR;
>>> +
>>> +    case TO_SPR(0, 1): /* UPR */
>>> +        return env->upr;    /* TT, DM, IM, UP present */
>>> +
>>> +    case TO_SPR(0, 2): /* CPUCFGR */
>>> +        return env->cpucfgr;
>>> +
>>> +    case TO_SPR(0, 3): /* DMMUCFGR */
>>> +        return env->dmmucfgr;    /* 1Way, 64 entries */
>>> +
>>> +    case TO_SPR(0, 4): /* IMMUCFGR */
>>> +        return env->immucfgr;
>>> +
>>> +    case TO_SPR(0, 16): /* NPC */
>>> +        return env->npc;
>>> +
>>> +    case TO_SPR(0, 17): /* SR */
>>> +        return env->sr;
>>> +
>>> +    case TO_SPR(0, 18): /* PPC */
>>> +        return env->ppc;
>>> +
>>> +    case TO_SPR(0, 32): /* EPCR */
>>> +        return env->epcr;
>>> +
>>> +    case TO_SPR(0, 48): /* EEAR */
>>> +        return env->eear;
>>> +
>>> +    case TO_SPR(0, 64): /* ESR */
>>> +        return env->esr;
>>> +
>>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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 */
>>> +        idx = spr - TO_SPR(1, 640);
>>> +        return env->tlb->dtlb[0][idx].tr;
>>> +
>>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>>> +    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 */
>>> +        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 */
>>> +        idx = spr - TO_SPR(2, 640);
>>> +        return env->tlb->itlb[0][idx].tr;
>>> +
>>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>>> +        break;
>>> +
>>> +    case TO_SPR(9, 0):  /* PICMR */
>>> +        return env->picmr;
>>> +
>>> +    case TO_SPR(9, 2):  /* PICSR */
>>> +        return env->picsr;
>>> +
>>> +    case TO_SPR(10, 0): /* TTMR */
>>> +        return env->ttmr;
>>> +
>>> +    case TO_SPR(10, 1): /* TTCR */
>>> +        cpu_openrisc_count_update(cpu);
>>> +        return env->ttcr;
>>> +
>>> +    default:
>>> +        break;
>>> +    }
>>> +#endif
>>> +
>>> +/*If we later need to add tracepoints (or debug printfs) for the return
>>> +value, it may be useful to structure the code like this:
>>> +
>>> +target_ulong ret = 0;
>>> +
>>> +switch() {
>>> +case x:
>>> + ret = y;
>>> + break;
>>> +case z:
>>> + ret = 42;
>>> + break;
>>> +...
>>> +}
>>> +
>>> +later something like trace_spr_read(ret);
>>> +
>>> +return ret;*/
>>> +
>>> +    /* for rd is passed in, if rd unchanged, just keep it back.  */
>>> +    return rd;
>>> +}
>>> diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
>>> index ed25604..8069edb 100644
>>> --- a/target-openrisc/translate.c
>>> +++ b/target-openrisc/translate.c
>>> @@ -995,10 +995,20 @@ static void dec_misc(DisasContext *dc, uint32_t insn)
>>>
>>>      case 0x2d:    /* l.mfspr */
>>>          LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>> +        {
>>> +            TCGv_i32 ti = tcg_const_i32(I16);
>>> +            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>> +            tcg_temp_free_i32(ti);
>>> +        }
>>>          break;
>>>
>>>      case 0x30:    /* l.mtspr */
>>>          LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>> +        {
>>> +            TCGv_i32 im = tcg_const_i32(tmp);
>>> +            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>> +            tcg_temp_free_i32(im);
>>> +        }
>>>          break;
>>
>> openrisc ISA says that l.mtspr/l.mfspr are only accessible in supervisor mode,
>> but I don't see where it is enforced.
>>
>
> Thank you for mind me, it is the new code. Is it OK?

I don't think so, please check for example target-ppc/translate.c:4192
on how supervisor only mfsr is handled there.

>
> #ifndef CONFIG_USER_ONLY
>     case 0x2d:    /* l.mfspr */
>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>         {
>             TCGv_i32 ti = tcg_const_i32(I16);
>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>             tcg_temp_free_i32(ti);
>         }
>         break;
>
>     case 0x30:    /* l.mtspr */
>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>         {
>             TCGv_i32 im = tcg_const_i32(tmp);
>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>             tcg_temp_free_i32(im);
>         }
>         break;
> #endif
>
>
>> --
>> Thanks.
>> -- Max
>
> Regards,
> Jia
>
Jia Liu July 14, 2012, 1:39 p.m. UTC | #4
Hi Blue,

On Sat, Jul 14, 2012 at 9:19 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Sat, Jul 14, 2012 at 11:12 AM, Jia Liu <proljc@gmail.com> wrote:
>> Hi Max
>>
>> On Fri, Jul 13, 2012 at 5:27 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>> On Fri, Jul 13, 2012 at 8:35 AM, Jia Liu <proljc@gmail.com> wrote:
>>>> Add OpenRISC system instructions.
>>>>
>>>> Signed-off-by: Jia Liu <proljc@gmail.com>
>>>> ---
>>>>  target-openrisc/Makefile.objs |    2 +-
>>>>  target-openrisc/cpu.h         |    3 +
>>>>  target-openrisc/helper.h      |    4 +
>>>>  target-openrisc/sys_helper.c  |  287 +++++++++++++++++++++++++++++++++++++++++
>>>>  target-openrisc/translate.c   |   10 ++
>>>>  5 files changed, 305 insertions(+), 1 deletion(-)
>>>>  create mode 100644 target-openrisc/sys_helper.c
>>>>
>>>> diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
>>>> index 926fc2f..44dc539 100644
>>>> --- a/target-openrisc/Makefile.objs
>>>> +++ b/target-openrisc/Makefile.objs
>>>> @@ -1,4 +1,4 @@
>>>>  obj-$(CONFIG_SOFTMMU) += machine.o
>>>>  obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
>>>>  obj-y += exception_helper.o fpu_helper.o int_helper.o \
>>>> -         interrupt_helper.o mmu_helper.o
>>>> +         interrupt_helper.o mmu_helper.o sys_helper.o
>>>> diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
>>>> index df07eaf..6506665 100644
>>>> --- a/target-openrisc/cpu.h
>>>> +++ b/target-openrisc/cpu.h
>>>> @@ -80,6 +80,9 @@ enum {
>>>>                                        (reg) |= ((v & 0x1f) << 2);\
>>>>                                    } while (0)
>>>>
>>>> +/* Version Register */
>>>> +#define SPR_VR 0xFFFF003F
>>>> +
>>>>  /* Internal flags, delay slot flag */
>>>>  #define D_FLAG    1
>>>>
>>>> diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h
>>>> index 6eb259a..836a70b 100644
>>>> --- a/target-openrisc/helper.h
>>>> +++ b/target-openrisc/helper.h
>>>> @@ -63,4 +63,8 @@ DEF_HELPER_FLAGS_3(mul32, 0, tl, env, tl, tl)
>>>>  /* interrupt */
>>>>  DEF_HELPER_FLAGS_1(rfe, 0, void, env)
>>>>
>>>> +/* sys */
>>>> +DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
>>>> +DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
>>>> +
>>>>  #include "def-helper.h"
>>>> diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
>>>> new file mode 100644
>>>> index 0000000..7ff8e15
>>>> --- /dev/null
>>>> +++ b/target-openrisc/sys_helper.c
>>>> @@ -0,0 +1,287 @@
>>>> +/*
>>>> + * OpenRISC system instructions helper routines
>>>> + *
>>>> + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
>>>> + *                         Zhizhou Zhang <etouzh@gmail.com>
>>>> + *
>>>> + * This library is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU Lesser General Public
>>>> + * License as published by the Free Software Foundation; either
>>>> + * version 2 of the License, or (at your option) any later version.
>>>> + *
>>>> + * This library is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> + * Lesser General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU Lesser General Public
>>>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include "cpu.h"
>>>> +#include "helper.h"
>>>> +
>>>> +#define TO_SPR(group, number) (((group) << 11) + (number))
>>>> +
>>>> +void HELPER(mtspr)(CPUOpenRISCState *env,
>>>> +                   target_ulong ra, target_ulong rb, target_ulong offset)
>>>> +{
>>>> +#ifndef CONFIG_USER_ONLY
>>>> +    int spr = (ra | offset);
>>>> +    int idx;
>>>> +
>>>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>>>> +
>>>> +    switch (spr) {
>>>> +    case TO_SPR(0, 0): /* VR */
>>>> +        env->vr = rb;
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(0, 16): /* NPC */
>>>> +        env->npc = rb;
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(0, 17): /* SR */
>>>> +        if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
>>>> +            (rb & (SR_IME | SR_DME | SR_SM))) {
>>>> +            tlb_flush(env, 1);
>>>> +        }
>>>> +        env->sr = rb;
>>>> +        env->sr |= SR_FO;      /* FO is const equal to 1 */
>>>> +        if (env->sr & SR_DME) {
>>>> +            env->tlb->cpu_openrisc_map_address_data =
>>>> +                &cpu_openrisc_get_phys_data;
>>>> +        } else {
>>>> +            env->tlb->cpu_openrisc_map_address_data =
>>>> +                &cpu_openrisc_get_phys_nommu;
>>>> +        }
>>>> +
>>>> +        if (env->sr & SR_IME) {
>>>> +            env->tlb->cpu_openrisc_map_address_code =
>>>> +                &cpu_openrisc_get_phys_code;
>>>> +        } else {
>>>> +            env->tlb->cpu_openrisc_map_address_code =
>>>> +                &cpu_openrisc_get_phys_nommu;
>>>> +        }
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(0, 18): /* PPC */
>>>> +        env->ppc = rb;
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(0, 32): /* EPCR */
>>>> +        env->epcr = rb;
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(0, 48): /* EEAR */
>>>> +        env->eear = rb;
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(0, 64): /* ESR */
>>>> +        env->esr = rb;
>>>> +        break;
>>>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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);
>>>> +        }
>>>> +        env->tlb->dtlb[0][idx].mr = rb;
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */
>>>> +        idx = spr - TO_SPR(1, 640);
>>>> +        env->tlb->dtlb[0][idx].tr = rb;
>>>> +        break;
>>>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>>>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>>>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>>>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>>>> +    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 */
>>>> +        idx = spr - TO_SPR(2, 512);
>>>> +        if (!(rb & 1)) {
>>>> +            tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
>>>> +        }
>>>> +        env->tlb->itlb[0][idx].mr = rb;
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */
>>>> +        idx = spr - TO_SPR(2, 640);
>>>> +        env->tlb->itlb[0][idx].tr = rb;
>>>> +        break;
>>>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>>>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>>>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>>>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>>>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>>>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>>>> +        break;
>>>> +    case TO_SPR(9, 0):  /* PICMR */
>>>> +        env->picmr |= rb;
>>>> +        break;
>>>> +    case TO_SPR(9, 2):  /* PICSR */
>>>> +        env->picsr &= ~rb;
>>>> +        break;
>>>> +    case TO_SPR(10, 0): /* TTMR */
>>>> +        {
>>>> +            int ip = env->ttmr & TTMR_IP;
>>>> +
>>>> +            if (rb & TTMR_IP) {    /* Keep IP bit.  */
>>>> +                env->ttmr = (rb & ~TTMR_IP) + ip;
>>>> +            } else {    /* Clear IP bit.  */
>>>> +                env->ttmr = rb & ~TTMR_IP;
>>>> +                env->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;
>>>> +            }
>>>> +        }
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(10, 1): /* TTCR */
>>>> +        env->ttcr = rb;
>>>> +        if (env->ttmr & TIMER_NONE) {
>>>> +            return;
>>>> +        }
>>>> +        cpu_openrisc_count_start(cpu);
>>>> +        break;
>>>> +    default:
>>>> +
>>>> +        break;
>>>> +    }
>>>> +#endif
>>>> +}
>>>> +
>>>> +target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
>>>> +                           target_ulong rd, target_ulong ra, uint32_t offset)
>>>> +{
>>>> +#ifndef CONFIG_USER_ONLY
>>>> +    int spr = (ra | offset);
>>>> +    int idx;
>>>> +
>>>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>>>> +
>>>> +    switch (spr) {
>>>> +    case TO_SPR(0, 0): /* VR */
>>>> +        return env->vr & SPR_VR;
>>>> +
>>>> +    case TO_SPR(0, 1): /* UPR */
>>>> +        return env->upr;    /* TT, DM, IM, UP present */
>>>> +
>>>> +    case TO_SPR(0, 2): /* CPUCFGR */
>>>> +        return env->cpucfgr;
>>>> +
>>>> +    case TO_SPR(0, 3): /* DMMUCFGR */
>>>> +        return env->dmmucfgr;    /* 1Way, 64 entries */
>>>> +
>>>> +    case TO_SPR(0, 4): /* IMMUCFGR */
>>>> +        return env->immucfgr;
>>>> +
>>>> +    case TO_SPR(0, 16): /* NPC */
>>>> +        return env->npc;
>>>> +
>>>> +    case TO_SPR(0, 17): /* SR */
>>>> +        return env->sr;
>>>> +
>>>> +    case TO_SPR(0, 18): /* PPC */
>>>> +        return env->ppc;
>>>> +
>>>> +    case TO_SPR(0, 32): /* EPCR */
>>>> +        return env->epcr;
>>>> +
>>>> +    case TO_SPR(0, 48): /* EEAR */
>>>> +        return env->eear;
>>>> +
>>>> +    case TO_SPR(0, 64): /* ESR */
>>>> +        return env->esr;
>>>> +
>>>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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 */
>>>> +        idx = spr - TO_SPR(1, 640);
>>>> +        return env->tlb->dtlb[0][idx].tr;
>>>> +
>>>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>>>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>>>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>>>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>>>> +    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 */
>>>> +        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 */
>>>> +        idx = spr - TO_SPR(2, 640);
>>>> +        return env->tlb->itlb[0][idx].tr;
>>>> +
>>>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>>>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>>>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>>>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>>>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>>>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>>>> +        break;
>>>> +
>>>> +    case TO_SPR(9, 0):  /* PICMR */
>>>> +        return env->picmr;
>>>> +
>>>> +    case TO_SPR(9, 2):  /* PICSR */
>>>> +        return env->picsr;
>>>> +
>>>> +    case TO_SPR(10, 0): /* TTMR */
>>>> +        return env->ttmr;
>>>> +
>>>> +    case TO_SPR(10, 1): /* TTCR */
>>>> +        cpu_openrisc_count_update(cpu);
>>>> +        return env->ttcr;
>>>> +
>>>> +    default:
>>>> +        break;
>>>> +    }
>>>> +#endif
>>>> +
>>>> +/*If we later need to add tracepoints (or debug printfs) for the return
>>>> +value, it may be useful to structure the code like this:
>>>> +
>>>> +target_ulong ret = 0;
>>>> +
>>>> +switch() {
>>>> +case x:
>>>> + ret = y;
>>>> + break;
>>>> +case z:
>>>> + ret = 42;
>>>> + break;
>>>> +...
>>>> +}
>>>> +
>>>> +later something like trace_spr_read(ret);
>>>> +
>>>> +return ret;*/
>>>> +
>>>> +    /* for rd is passed in, if rd unchanged, just keep it back.  */
>>>> +    return rd;
>>>> +}
>>>> diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
>>>> index ed25604..8069edb 100644
>>>> --- a/target-openrisc/translate.c
>>>> +++ b/target-openrisc/translate.c
>>>> @@ -995,10 +995,20 @@ static void dec_misc(DisasContext *dc, uint32_t insn)
>>>>
>>>>      case 0x2d:    /* l.mfspr */
>>>>          LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>>> +        {
>>>> +            TCGv_i32 ti = tcg_const_i32(I16);
>>>> +            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>>> +            tcg_temp_free_i32(ti);
>>>> +        }
>>>>          break;
>>>>
>>>>      case 0x30:    /* l.mtspr */
>>>>          LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>>> +        {
>>>> +            TCGv_i32 im = tcg_const_i32(tmp);
>>>> +            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>>> +            tcg_temp_free_i32(im);
>>>> +        }
>>>>          break;
>>>
>>> openrisc ISA says that l.mtspr/l.mfspr are only accessible in supervisor mode,
>>> but I don't see where it is enforced.
>>>
>>
>> Thank you for mind me, it is the new code. Is it OK?
>
> I don't think so, please check for example target-ppc/translate.c:4192
> on how supervisor only mfsr is handled there.
>

Thank you for comment, Blue.

is this code OK?

    case 0x2d:    /* l.mfspr */
        LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
        {
#if defined(CONFIG_USER_ONLY)
            gen_illegal_exception(dc);
#else
            TCGv_i32 ti = tcg_const_i32(I16);
            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
            tcg_temp_free_i32(ti);
#endif
        }
        break;

    case 0x30:    /* l.mtspr */
        LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
        {
#if defined(CONFIG_USER_ONLY)
            gen_illegal_exception(dc);
#else
            TCGv_i32 im = tcg_const_i32(tmp);
            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
            tcg_temp_free_i32(im);
#endif
        }
        break;

>>
>> #ifndef CONFIG_USER_ONLY
>>     case 0x2d:    /* l.mfspr */
>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>         {
>>             TCGv_i32 ti = tcg_const_i32(I16);
>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>             tcg_temp_free_i32(ti);
>>         }
>>         break;
>>
>>     case 0x30:    /* l.mtspr */
>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>         {
>>             TCGv_i32 im = tcg_const_i32(tmp);
>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>             tcg_temp_free_i32(im);
>>         }
>>         break;
>> #endif
>>
>>
>>> --
>>> Thanks.
>>> -- Max
>>
>> Regards,
>> Jia
>>

Regards,
Jia
Max Filippov July 14, 2012, 1:49 p.m. UTC | #5
On Sat, Jul 14, 2012 at 5:39 PM, Jia Liu <proljc@gmail.com> wrote:
> Hi Blue,
>
> On Sat, Jul 14, 2012 at 9:19 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
>> On Sat, Jul 14, 2012 at 11:12 AM, Jia Liu <proljc@gmail.com> wrote:
>>> Hi Max
>>>
>>> On Fri, Jul 13, 2012 at 5:27 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>>> On Fri, Jul 13, 2012 at 8:35 AM, Jia Liu <proljc@gmail.com> wrote:
>>>>> Add OpenRISC system instructions.
>>>>>
>>>>> Signed-off-by: Jia Liu <proljc@gmail.com>
>>>>> ---
>>>>>  target-openrisc/Makefile.objs |    2 +-
>>>>>  target-openrisc/cpu.h         |    3 +
>>>>>  target-openrisc/helper.h      |    4 +
>>>>>  target-openrisc/sys_helper.c  |  287 +++++++++++++++++++++++++++++++++++++++++
>>>>>  target-openrisc/translate.c   |   10 ++
>>>>>  5 files changed, 305 insertions(+), 1 deletion(-)
>>>>>  create mode 100644 target-openrisc/sys_helper.c
>>>>>
>>>>> diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
>>>>> index 926fc2f..44dc539 100644
>>>>> --- a/target-openrisc/Makefile.objs
>>>>> +++ b/target-openrisc/Makefile.objs
>>>>> @@ -1,4 +1,4 @@
>>>>>  obj-$(CONFIG_SOFTMMU) += machine.o
>>>>>  obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
>>>>>  obj-y += exception_helper.o fpu_helper.o int_helper.o \
>>>>> -         interrupt_helper.o mmu_helper.o
>>>>> +         interrupt_helper.o mmu_helper.o sys_helper.o
>>>>> diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
>>>>> index df07eaf..6506665 100644
>>>>> --- a/target-openrisc/cpu.h
>>>>> +++ b/target-openrisc/cpu.h
>>>>> @@ -80,6 +80,9 @@ enum {
>>>>>                                        (reg) |= ((v & 0x1f) << 2);\
>>>>>                                    } while (0)
>>>>>
>>>>> +/* Version Register */
>>>>> +#define SPR_VR 0xFFFF003F
>>>>> +
>>>>>  /* Internal flags, delay slot flag */
>>>>>  #define D_FLAG    1
>>>>>
>>>>> diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h
>>>>> index 6eb259a..836a70b 100644
>>>>> --- a/target-openrisc/helper.h
>>>>> +++ b/target-openrisc/helper.h
>>>>> @@ -63,4 +63,8 @@ DEF_HELPER_FLAGS_3(mul32, 0, tl, env, tl, tl)
>>>>>  /* interrupt */
>>>>>  DEF_HELPER_FLAGS_1(rfe, 0, void, env)
>>>>>
>>>>> +/* sys */
>>>>> +DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
>>>>> +DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
>>>>> +
>>>>>  #include "def-helper.h"
>>>>> diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
>>>>> new file mode 100644
>>>>> index 0000000..7ff8e15
>>>>> --- /dev/null
>>>>> +++ b/target-openrisc/sys_helper.c
>>>>> @@ -0,0 +1,287 @@
>>>>> +/*
>>>>> + * OpenRISC system instructions helper routines
>>>>> + *
>>>>> + * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
>>>>> + *                         Zhizhou Zhang <etouzh@gmail.com>
>>>>> + *
>>>>> + * This library is free software; you can redistribute it and/or
>>>>> + * modify it under the terms of the GNU Lesser General Public
>>>>> + * License as published by the Free Software Foundation; either
>>>>> + * version 2 of the License, or (at your option) any later version.
>>>>> + *
>>>>> + * This library is distributed in the hope that it will be useful,
>>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>>> + * Lesser General Public License for more details.
>>>>> + *
>>>>> + * You should have received a copy of the GNU Lesser General Public
>>>>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>>>>> + */
>>>>> +
>>>>> +#include "cpu.h"
>>>>> +#include "helper.h"
>>>>> +
>>>>> +#define TO_SPR(group, number) (((group) << 11) + (number))
>>>>> +
>>>>> +void HELPER(mtspr)(CPUOpenRISCState *env,
>>>>> +                   target_ulong ra, target_ulong rb, target_ulong offset)
>>>>> +{
>>>>> +#ifndef CONFIG_USER_ONLY
>>>>> +    int spr = (ra | offset);
>>>>> +    int idx;
>>>>> +
>>>>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>>>>> +
>>>>> +    switch (spr) {
>>>>> +    case TO_SPR(0, 0): /* VR */
>>>>> +        env->vr = rb;
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(0, 16): /* NPC */
>>>>> +        env->npc = rb;
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(0, 17): /* SR */
>>>>> +        if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
>>>>> +            (rb & (SR_IME | SR_DME | SR_SM))) {
>>>>> +            tlb_flush(env, 1);
>>>>> +        }
>>>>> +        env->sr = rb;
>>>>> +        env->sr |= SR_FO;      /* FO is const equal to 1 */
>>>>> +        if (env->sr & SR_DME) {
>>>>> +            env->tlb->cpu_openrisc_map_address_data =
>>>>> +                &cpu_openrisc_get_phys_data;
>>>>> +        } else {
>>>>> +            env->tlb->cpu_openrisc_map_address_data =
>>>>> +                &cpu_openrisc_get_phys_nommu;
>>>>> +        }
>>>>> +
>>>>> +        if (env->sr & SR_IME) {
>>>>> +            env->tlb->cpu_openrisc_map_address_code =
>>>>> +                &cpu_openrisc_get_phys_code;
>>>>> +        } else {
>>>>> +            env->tlb->cpu_openrisc_map_address_code =
>>>>> +                &cpu_openrisc_get_phys_nommu;
>>>>> +        }
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(0, 18): /* PPC */
>>>>> +        env->ppc = rb;
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(0, 32): /* EPCR */
>>>>> +        env->epcr = rb;
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(0, 48): /* EEAR */
>>>>> +        env->eear = rb;
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(0, 64): /* ESR */
>>>>> +        env->esr = rb;
>>>>> +        break;
>>>>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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);
>>>>> +        }
>>>>> +        env->tlb->dtlb[0][idx].mr = rb;
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */
>>>>> +        idx = spr - TO_SPR(1, 640);
>>>>> +        env->tlb->dtlb[0][idx].tr = rb;
>>>>> +        break;
>>>>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>>>>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>>>>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>>>>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>>>>> +    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 */
>>>>> +        idx = spr - TO_SPR(2, 512);
>>>>> +        if (!(rb & 1)) {
>>>>> +            tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
>>>>> +        }
>>>>> +        env->tlb->itlb[0][idx].mr = rb;
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */
>>>>> +        idx = spr - TO_SPR(2, 640);
>>>>> +        env->tlb->itlb[0][idx].tr = rb;
>>>>> +        break;
>>>>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>>>>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>>>>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>>>>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>>>>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>>>>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>>>>> +        break;
>>>>> +    case TO_SPR(9, 0):  /* PICMR */
>>>>> +        env->picmr |= rb;
>>>>> +        break;
>>>>> +    case TO_SPR(9, 2):  /* PICSR */
>>>>> +        env->picsr &= ~rb;
>>>>> +        break;
>>>>> +    case TO_SPR(10, 0): /* TTMR */
>>>>> +        {
>>>>> +            int ip = env->ttmr & TTMR_IP;
>>>>> +
>>>>> +            if (rb & TTMR_IP) {    /* Keep IP bit.  */
>>>>> +                env->ttmr = (rb & ~TTMR_IP) + ip;
>>>>> +            } else {    /* Clear IP bit.  */
>>>>> +                env->ttmr = rb & ~TTMR_IP;
>>>>> +                env->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;
>>>>> +            }
>>>>> +        }
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(10, 1): /* TTCR */
>>>>> +        env->ttcr = rb;
>>>>> +        if (env->ttmr & TIMER_NONE) {
>>>>> +            return;
>>>>> +        }
>>>>> +        cpu_openrisc_count_start(cpu);
>>>>> +        break;
>>>>> +    default:
>>>>> +
>>>>> +        break;
>>>>> +    }
>>>>> +#endif
>>>>> +}
>>>>> +
>>>>> +target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
>>>>> +                           target_ulong rd, target_ulong ra, uint32_t offset)
>>>>> +{
>>>>> +#ifndef CONFIG_USER_ONLY
>>>>> +    int spr = (ra | offset);
>>>>> +    int idx;
>>>>> +
>>>>> +    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
>>>>> +
>>>>> +    switch (spr) {
>>>>> +    case TO_SPR(0, 0): /* VR */
>>>>> +        return env->vr & SPR_VR;
>>>>> +
>>>>> +    case TO_SPR(0, 1): /* UPR */
>>>>> +        return env->upr;    /* TT, DM, IM, UP present */
>>>>> +
>>>>> +    case TO_SPR(0, 2): /* CPUCFGR */
>>>>> +        return env->cpucfgr;
>>>>> +
>>>>> +    case TO_SPR(0, 3): /* DMMUCFGR */
>>>>> +        return env->dmmucfgr;    /* 1Way, 64 entries */
>>>>> +
>>>>> +    case TO_SPR(0, 4): /* IMMUCFGR */
>>>>> +        return env->immucfgr;
>>>>> +
>>>>> +    case TO_SPR(0, 16): /* NPC */
>>>>> +        return env->npc;
>>>>> +
>>>>> +    case TO_SPR(0, 17): /* SR */
>>>>> +        return env->sr;
>>>>> +
>>>>> +    case TO_SPR(0, 18): /* PPC */
>>>>> +        return env->ppc;
>>>>> +
>>>>> +    case TO_SPR(0, 32): /* EPCR */
>>>>> +        return env->epcr;
>>>>> +
>>>>> +    case TO_SPR(0, 48): /* EEAR */
>>>>> +        return env->eear;
>>>>> +
>>>>> +    case TO_SPR(0, 64): /* ESR */
>>>>> +        return env->esr;
>>>>> +
>>>>> +    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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 */
>>>>> +        idx = spr - TO_SPR(1, 640);
>>>>> +        return env->tlb->dtlb[0][idx].tr;
>>>>> +
>>>>> +    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
>>>>> +    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
>>>>> +    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
>>>>> +    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
>>>>> +    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 */
>>>>> +        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 */
>>>>> +        idx = spr - TO_SPR(2, 640);
>>>>> +        return env->tlb->itlb[0][idx].tr;
>>>>> +
>>>>> +    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
>>>>> +    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
>>>>> +    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
>>>>> +    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
>>>>> +    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
>>>>> +    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
>>>>> +        break;
>>>>> +
>>>>> +    case TO_SPR(9, 0):  /* PICMR */
>>>>> +        return env->picmr;
>>>>> +
>>>>> +    case TO_SPR(9, 2):  /* PICSR */
>>>>> +        return env->picsr;
>>>>> +
>>>>> +    case TO_SPR(10, 0): /* TTMR */
>>>>> +        return env->ttmr;
>>>>> +
>>>>> +    case TO_SPR(10, 1): /* TTCR */
>>>>> +        cpu_openrisc_count_update(cpu);
>>>>> +        return env->ttcr;
>>>>> +
>>>>> +    default:
>>>>> +        break;
>>>>> +    }
>>>>> +#endif
>>>>> +
>>>>> +/*If we later need to add tracepoints (or debug printfs) for the return
>>>>> +value, it may be useful to structure the code like this:
>>>>> +
>>>>> +target_ulong ret = 0;
>>>>> +
>>>>> +switch() {
>>>>> +case x:
>>>>> + ret = y;
>>>>> + break;
>>>>> +case z:
>>>>> + ret = 42;
>>>>> + break;
>>>>> +...
>>>>> +}
>>>>> +
>>>>> +later something like trace_spr_read(ret);
>>>>> +
>>>>> +return ret;*/
>>>>> +
>>>>> +    /* for rd is passed in, if rd unchanged, just keep it back.  */
>>>>> +    return rd;
>>>>> +}
>>>>> diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
>>>>> index ed25604..8069edb 100644
>>>>> --- a/target-openrisc/translate.c
>>>>> +++ b/target-openrisc/translate.c
>>>>> @@ -995,10 +995,20 @@ static void dec_misc(DisasContext *dc, uint32_t insn)
>>>>>
>>>>>      case 0x2d:    /* l.mfspr */
>>>>>          LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>>>> +        {
>>>>> +            TCGv_i32 ti = tcg_const_i32(I16);
>>>>> +            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>>>> +            tcg_temp_free_i32(ti);
>>>>> +        }
>>>>>          break;
>>>>>
>>>>>      case 0x30:    /* l.mtspr */
>>>>>          LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>>>> +        {
>>>>> +            TCGv_i32 im = tcg_const_i32(tmp);
>>>>> +            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>>>> +            tcg_temp_free_i32(im);
>>>>> +        }
>>>>>          break;
>>>>
>>>> openrisc ISA says that l.mtspr/l.mfspr are only accessible in supervisor mode,
>>>> but I don't see where it is enforced.
>>>>
>>>
>>> Thank you for mind me, it is the new code. Is it OK?
>>
>> I don't think so, please check for example target-ppc/translate.c:4192
>> on how supervisor only mfsr is handled there.
>>
>
> Thank you for comment, Blue.
>
> is this code OK?

Shouldn't there also be an exception in softmmu mode
if the CPU is not in supervisor mode?

>
>     case 0x2d:    /* l.mfspr */
>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>         {
> #if defined(CONFIG_USER_ONLY)
>             gen_illegal_exception(dc);
> #else
>             TCGv_i32 ti = tcg_const_i32(I16);
>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>             tcg_temp_free_i32(ti);
> #endif
>         }
>         break;
>
>     case 0x30:    /* l.mtspr */
>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>         {
> #if defined(CONFIG_USER_ONLY)
>             gen_illegal_exception(dc);
> #else
>             TCGv_i32 im = tcg_const_i32(tmp);
>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>             tcg_temp_free_i32(im);
> #endif
>         }
>         break;
>
>>>
>>> #ifndef CONFIG_USER_ONLY
>>>     case 0x2d:    /* l.mfspr */
>>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>>         {
>>>             TCGv_i32 ti = tcg_const_i32(I16);
>>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>>             tcg_temp_free_i32(ti);
>>>         }
>>>         break;
>>>
>>>     case 0x30:    /* l.mtspr */
>>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>>         {
>>>             TCGv_i32 im = tcg_const_i32(tmp);
>>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>>             tcg_temp_free_i32(im);
>>>         }
>>>         break;
>>> #endif
>>>
>>>
>>>> --
>>>> Thanks.
>>>> -- Max
>>>
>>> Regards,
>>> Jia
>>>
>
> Regards,
> Jia
Jia Liu July 14, 2012, 2:08 p.m. UTC | #6
Hi Max

On Sat, Jul 14, 2012 at 9:49 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>> I don't think so, please check for example target-ppc/translate.c:4192
>>> on how supervisor only mfsr is handled there.
>>>
>>
>> Thank you for comment, Blue.
>>
>> is this code OK?
>
> Shouldn't there also be an exception in softmmu mode
> if the CPU is not in supervisor mode?
>

Sorry, I...
May you give me more comment? I'm not sure about this.

>>
>>     case 0x2d:    /* l.mfspr */
>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>         {
>> #if defined(CONFIG_USER_ONLY)
>>             gen_illegal_exception(dc);
>> #else
>>             TCGv_i32 ti = tcg_const_i32(I16);
>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>             tcg_temp_free_i32(ti);
>> #endif
>>         }
>>         break;
>>
>>     case 0x30:    /* l.mtspr */
>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>         {
>> #if defined(CONFIG_USER_ONLY)
>>             gen_illegal_exception(dc);
>> #else
>>             TCGv_i32 im = tcg_const_i32(tmp);
>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>             tcg_temp_free_i32(im);
>> #endif
>>         }
>>         break;
>>
>
> --
> Thanks.
> -- Max

Regards,
Jia.
Blue Swirl July 14, 2012, 2:42 p.m. UTC | #7
On Sat, Jul 14, 2012 at 2:08 PM, Jia Liu <proljc@gmail.com> wrote:
> Hi Max
>
> On Sat, Jul 14, 2012 at 9:49 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>>> I don't think so, please check for example target-ppc/translate.c:4192
>>>> on how supervisor only mfsr is handled there.
>>>>
>>>
>>> Thank you for comment, Blue.
>>>
>>> is this code OK?
>>
>> Shouldn't there also be an exception in softmmu mode
>> if the CPU is not in supervisor mode?
>>
>
> Sorry, I...
> May you give me more comment? I'm not sure about this.

If a user tries to execute a supervisor instruction (only allowed for
kernel level code, not applications), the instruction won't be
executed but an exception will be raised.

This is the PPC mfsr instruction part of target-ppc/translate.c:
/* mfsr */
static void gen_mfsr(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
#else
    TCGv t0;
    if (unlikely(!ctx->mem_idx)) {

Here the MMU mode is checked for user mode. I'd use more explicit
check ctx->mmu_idx == MMU_USER_IDX.

        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
        return;
    }
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
    tcg_temp_free(t0);
#endif
}

>
>>>
>>>     case 0x2d:    /* l.mfspr */
>>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>>         {
>>> #if defined(CONFIG_USER_ONLY)
>>>             gen_illegal_exception(dc);
>>> #else
>>>             TCGv_i32 ti = tcg_const_i32(I16);
>>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>>             tcg_temp_free_i32(ti);
>>> #endif
>>>         }
>>>         break;
>>>
>>>     case 0x30:    /* l.mtspr */
>>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>>         {
>>> #if defined(CONFIG_USER_ONLY)
>>>             gen_illegal_exception(dc);
>>> #else
>>>             TCGv_i32 im = tcg_const_i32(tmp);
>>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>>             tcg_temp_free_i32(im);
>>> #endif
>>>         }
>>>         break;
>>>
>>
>> --
>> Thanks.
>> -- Max
>
> Regards,
> Jia.
Jia Liu July 15, 2012, 12:39 a.m. UTC | #8
Hi Blue

On Sat, Jul 14, 2012 at 10:42 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Sat, Jul 14, 2012 at 2:08 PM, Jia Liu <proljc@gmail.com> wrote:
>> Hi Max
>>
>> On Sat, Jul 14, 2012 at 9:49 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>>>> I don't think so, please check for example target-ppc/translate.c:4192
>>>>> on how supervisor only mfsr is handled there.
>>>>>
>>>>
>>>> Thank you for comment, Blue.
>>>>
>>>> is this code OK?
>>>
>>> Shouldn't there also be an exception in softmmu mode
>>> if the CPU is not in supervisor mode?
>>>
>>
>> Sorry, I...
>> May you give me more comment? I'm not sure about this.
>
> If a user tries to execute a supervisor instruction (only allowed for
> kernel level code, not applications), the instruction won't be
> executed but an exception will be raised.
>
> This is the PPC mfsr instruction part of target-ppc/translate.c:
> /* mfsr */
> static void gen_mfsr(DisasContext *ctx)
> {
> #if defined(CONFIG_USER_ONLY)
>     gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
> #else
>     TCGv t0;
>     if (unlikely(!ctx->mem_idx)) {
>
> Here the MMU mode is checked for user mode. I'd use more explicit
> check ctx->mmu_idx == MMU_USER_IDX.
>
>         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
>         return;
>     }
>     t0 = tcg_const_tl(SR(ctx->opcode));
>     gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
>     tcg_temp_free(t0);
> #endif
> }
>

Thank you very much for this nice example.
Is this code OK?
    case 0x2d:    /* l.mfspr */
        LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
        {
#if defined(CONFIG_USER_ONLY)
            gen_illegal_exception(dc);
#else
            TCGv_i32 ti = tcg_const_i32(I16);
            if (dc->mem_idx == MMU_USER_IDX) {
                gen_illegal_exception(dc);
                return;
            }
            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
            tcg_temp_free_i32(ti);
#endif
        }
        break;

    case 0x30:    /* l.mtspr */
        LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
        {
#if defined(CONFIG_USER_ONLY)
            gen_illegal_exception(dc);
#else
            TCGv_i32 im = tcg_const_i32(tmp);
            if (dc->mem_idx == MMU_USER_IDX) {
                gen_illegal_exception(dc);
                return;
            }
            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
            tcg_temp_free_i32(im);
#endif
        }
        break;


>>
>>>>
>>>>     case 0x2d:    /* l.mfspr */
>>>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>>>         {
>>>> #if defined(CONFIG_USER_ONLY)
>>>>             gen_illegal_exception(dc);
>>>> #else
>>>>             TCGv_i32 ti = tcg_const_i32(I16);
>>>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>>>             tcg_temp_free_i32(ti);
>>>> #endif
>>>>         }
>>>>         break;
>>>>
>>>>     case 0x30:    /* l.mtspr */
>>>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>>>         {
>>>> #if defined(CONFIG_USER_ONLY)
>>>>             gen_illegal_exception(dc);
>>>> #else
>>>>             TCGv_i32 im = tcg_const_i32(tmp);
>>>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>>>             tcg_temp_free_i32(im);
>>>> #endif
>>>>         }
>>>>         break;
>>>>
>>>
>>> --
>>> Thanks.
>>> -- Max
>>
>> Regards,
>> Jia.

Regards,
Jia
Blue Swirl July 15, 2012, 7:54 a.m. UTC | #9
On Sun, Jul 15, 2012 at 12:39 AM, Jia Liu <proljc@gmail.com> wrote:
> Hi Blue
>
> On Sat, Jul 14, 2012 at 10:42 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
>> On Sat, Jul 14, 2012 at 2:08 PM, Jia Liu <proljc@gmail.com> wrote:
>>> Hi Max
>>>
>>> On Sat, Jul 14, 2012 at 9:49 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>>>>> I don't think so, please check for example target-ppc/translate.c:4192
>>>>>> on how supervisor only mfsr is handled there.
>>>>>>
>>>>>
>>>>> Thank you for comment, Blue.
>>>>>
>>>>> is this code OK?
>>>>
>>>> Shouldn't there also be an exception in softmmu mode
>>>> if the CPU is not in supervisor mode?
>>>>
>>>
>>> Sorry, I...
>>> May you give me more comment? I'm not sure about this.
>>
>> If a user tries to execute a supervisor instruction (only allowed for
>> kernel level code, not applications), the instruction won't be
>> executed but an exception will be raised.
>>
>> This is the PPC mfsr instruction part of target-ppc/translate.c:
>> /* mfsr */
>> static void gen_mfsr(DisasContext *ctx)
>> {
>> #if defined(CONFIG_USER_ONLY)
>>     gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
>> #else
>>     TCGv t0;
>>     if (unlikely(!ctx->mem_idx)) {
>>
>> Here the MMU mode is checked for user mode. I'd use more explicit
>> check ctx->mmu_idx == MMU_USER_IDX.
>>
>>         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
>>         return;
>>     }
>>     t0 = tcg_const_tl(SR(ctx->opcode));
>>     gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
>>     tcg_temp_free(t0);
>> #endif
>> }
>>
>
> Thank you very much for this nice example.
> Is this code OK?
>     case 0x2d:    /* l.mfspr */
>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>         {
> #if defined(CONFIG_USER_ONLY)
>             gen_illegal_exception(dc);
> #else
>             TCGv_i32 ti = tcg_const_i32(I16);
>             if (dc->mem_idx == MMU_USER_IDX) {
>                 gen_illegal_exception(dc);
>                 return;
>             }
>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>             tcg_temp_free_i32(ti);
> #endif
>         }
>         break;
>
>     case 0x30:    /* l.mtspr */
>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>         {
> #if defined(CONFIG_USER_ONLY)
>             gen_illegal_exception(dc);

Maybe return?

> #else
>             TCGv_i32 im = tcg_const_i32(tmp);
>             if (dc->mem_idx == MMU_USER_IDX) {
>                 gen_illegal_exception(dc);
>                 return;
>             }
>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>             tcg_temp_free_i32(im);
> #endif
>         }
>         break;


Otherwise looks OK. Perhaps there are other supervisor mode only
instructions which need this kind of checks?

>
>
>>>
>>>>>
>>>>>     case 0x2d:    /* l.mfspr */
>>>>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>>>>         {
>>>>> #if defined(CONFIG_USER_ONLY)
>>>>>             gen_illegal_exception(dc);
>>>>> #else
>>>>>             TCGv_i32 ti = tcg_const_i32(I16);
>>>>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>>>>             tcg_temp_free_i32(ti);
>>>>> #endif
>>>>>         }
>>>>>         break;
>>>>>
>>>>>     case 0x30:    /* l.mtspr */
>>>>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>>>>         {
>>>>> #if defined(CONFIG_USER_ONLY)
>>>>>             gen_illegal_exception(dc);
>>>>> #else
>>>>>             TCGv_i32 im = tcg_const_i32(tmp);
>>>>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>>>>             tcg_temp_free_i32(im);
>>>>> #endif
>>>>>         }
>>>>>         break;
>>>>>
>>>>
>>>> --
>>>> Thanks.
>>>> -- Max
>>>
>>> Regards,
>>> Jia.
>
> Regards,
> Jia
Jia Liu July 15, 2012, 1:31 p.m. UTC | #10
Hi Blue,

On Sun, Jul 15, 2012 at 3:54 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Sun, Jul 15, 2012 at 12:39 AM, Jia Liu <proljc@gmail.com> wrote:
>> Hi Blue
>>
>> On Sat, Jul 14, 2012 at 10:42 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
>>> On Sat, Jul 14, 2012 at 2:08 PM, Jia Liu <proljc@gmail.com> wrote:
>>>> Hi Max
>>>>
>>>> On Sat, Jul 14, 2012 at 9:49 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>>>>>> I don't think so, please check for example target-ppc/translate.c:4192
>>>>>>> on how supervisor only mfsr is handled there.
>>>>>>>
>>>>>>
>>>>>> Thank you for comment, Blue.
>>>>>>
>>>>>> is this code OK?
>>>>>
>>>>> Shouldn't there also be an exception in softmmu mode
>>>>> if the CPU is not in supervisor mode?
>>>>>
>>>>
>>>> Sorry, I...
>>>> May you give me more comment? I'm not sure about this.
>>>
>>> If a user tries to execute a supervisor instruction (only allowed for
>>> kernel level code, not applications), the instruction won't be
>>> executed but an exception will be raised.
>>>
>>> This is the PPC mfsr instruction part of target-ppc/translate.c:
>>> /* mfsr */
>>> static void gen_mfsr(DisasContext *ctx)
>>> {
>>> #if defined(CONFIG_USER_ONLY)
>>>     gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
>>> #else
>>>     TCGv t0;
>>>     if (unlikely(!ctx->mem_idx)) {
>>>
>>> Here the MMU mode is checked for user mode. I'd use more explicit
>>> check ctx->mmu_idx == MMU_USER_IDX.
>>>
>>>         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
>>>         return;
>>>     }
>>>     t0 = tcg_const_tl(SR(ctx->opcode));
>>>     gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
>>>     tcg_temp_free(t0);
>>> #endif
>>> }
>>>
>>
>> Thank you very much for this nice example.
>> Is this code OK?
>>     case 0x2d:    /* l.mfspr */
>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>         {
>> #if defined(CONFIG_USER_ONLY)
>>             gen_illegal_exception(dc);
>> #else
>>             TCGv_i32 ti = tcg_const_i32(I16);
>>             if (dc->mem_idx == MMU_USER_IDX) {
>>                 gen_illegal_exception(dc);
>>                 return;
>>             }
>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>             tcg_temp_free_i32(ti);
>> #endif
>>         }
>>         break;
>>
>>     case 0x30:    /* l.mtspr */
>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>         {
>> #if defined(CONFIG_USER_ONLY)
>>             gen_illegal_exception(dc);
>
> Maybe return?

Thank you! I think return is a better way.

>
>> #else
>>             TCGv_i32 im = tcg_const_i32(tmp);
>>             if (dc->mem_idx == MMU_USER_IDX) {
>>                 gen_illegal_exception(dc);
>>                 return;
>>             }
>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>             tcg_temp_free_i32(im);
>> #endif
>>         }
>>         break;
>
>
> Otherwise looks OK. Perhaps there are other supervisor mode only
> instructions which need this kind of checks?
>

I'll make a check, thank you.

>>
>>
>>>>
>>>>>>
>>>>>>     case 0x2d:    /* l.mfspr */
>>>>>>         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
>>>>>>         {
>>>>>> #if defined(CONFIG_USER_ONLY)
>>>>>>             gen_illegal_exception(dc);
>>>>>> #else
>>>>>>             TCGv_i32 ti = tcg_const_i32(I16);
>>>>>>             gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
>>>>>>             tcg_temp_free_i32(ti);
>>>>>> #endif
>>>>>>         }
>>>>>>         break;
>>>>>>
>>>>>>     case 0x30:    /* l.mtspr */
>>>>>>         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>>>>>>         {
>>>>>> #if defined(CONFIG_USER_ONLY)
>>>>>>             gen_illegal_exception(dc);
>>>>>> #else
>>>>>>             TCGv_i32 im = tcg_const_i32(tmp);
>>>>>>             gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
>>>>>>             tcg_temp_free_i32(im);
>>>>>> #endif
>>>>>>         }
>>>>>>         break;
>>>>>>
>>>>>
>>>>> --
>>>>> Thanks.
>>>>> -- Max
>>>>
>>>> Regards,
>>>> Jia.
>>
>> Regards,
>> Jia

Regards,
Jia
diff mbox

Patch

diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
index 926fc2f..44dc539 100644
--- a/target-openrisc/Makefile.objs
+++ b/target-openrisc/Makefile.objs
@@ -1,4 +1,4 @@ 
 obj-$(CONFIG_SOFTMMU) += machine.o
 obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
 obj-y += exception_helper.o fpu_helper.o int_helper.o \
-         interrupt_helper.o mmu_helper.o
+         interrupt_helper.o mmu_helper.o sys_helper.o
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index df07eaf..6506665 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -80,6 +80,9 @@  enum {
                                       (reg) |= ((v & 0x1f) << 2);\
                                   } while (0)
 
+/* Version Register */
+#define SPR_VR 0xFFFF003F
+
 /* Internal flags, delay slot flag */
 #define D_FLAG    1
 
diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h
index 6eb259a..836a70b 100644
--- a/target-openrisc/helper.h
+++ b/target-openrisc/helper.h
@@ -63,4 +63,8 @@  DEF_HELPER_FLAGS_3(mul32, 0, tl, env, tl, tl)
 /* interrupt */
 DEF_HELPER_FLAGS_1(rfe, 0, void, env)
 
+/* sys */
+DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
+DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
+
 #include "def-helper.h"
diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
new file mode 100644
index 0000000..7ff8e15
--- /dev/null
+++ b/target-openrisc/sys_helper.c
@@ -0,0 +1,287 @@ 
+/*
+ * OpenRISC system instructions helper routines
+ *
+ * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
+ *                         Zhizhou Zhang <etouzh@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define TO_SPR(group, number) (((group) << 11) + (number))
+
+void HELPER(mtspr)(CPUOpenRISCState *env,
+                   target_ulong ra, target_ulong rb, target_ulong offset)
+{
+#ifndef CONFIG_USER_ONLY
+    int spr = (ra | offset);
+    int idx;
+
+    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
+
+    switch (spr) {
+    case TO_SPR(0, 0): /* VR */
+        env->vr = rb;
+        break;
+
+    case TO_SPR(0, 16): /* NPC */
+        env->npc = rb;
+        break;
+
+    case TO_SPR(0, 17): /* SR */
+        if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
+            (rb & (SR_IME | SR_DME | SR_SM))) {
+            tlb_flush(env, 1);
+        }
+        env->sr = rb;
+        env->sr |= SR_FO;      /* FO is const equal to 1 */
+        if (env->sr & SR_DME) {
+            env->tlb->cpu_openrisc_map_address_data =
+                &cpu_openrisc_get_phys_data;
+        } else {
+            env->tlb->cpu_openrisc_map_address_data =
+                &cpu_openrisc_get_phys_nommu;
+        }
+
+        if (env->sr & SR_IME) {
+            env->tlb->cpu_openrisc_map_address_code =
+                &cpu_openrisc_get_phys_code;
+        } else {
+            env->tlb->cpu_openrisc_map_address_code =
+                &cpu_openrisc_get_phys_nommu;
+        }
+        break;
+
+    case TO_SPR(0, 18): /* PPC */
+        env->ppc = rb;
+        break;
+
+    case TO_SPR(0, 32): /* EPCR */
+        env->epcr = rb;
+        break;
+
+    case TO_SPR(0, 48): /* EEAR */
+        env->eear = rb;
+        break;
+
+    case TO_SPR(0, 64): /* ESR */
+        env->esr = rb;
+        break;
+    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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);
+        }
+        env->tlb->dtlb[0][idx].mr = rb;
+        break;
+
+    case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */
+        idx = spr - TO_SPR(1, 640);
+        env->tlb->dtlb[0][idx].tr = rb;
+        break;
+    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
+    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
+    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
+    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
+    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 */
+        idx = spr - TO_SPR(2, 512);
+        if (!(rb & 1)) {
+            tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
+        }
+        env->tlb->itlb[0][idx].mr = rb;
+        break;
+
+    case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */
+        idx = spr - TO_SPR(2, 640);
+        env->tlb->itlb[0][idx].tr = rb;
+        break;
+    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
+    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
+    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
+    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
+    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
+    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
+        break;
+    case TO_SPR(9, 0):  /* PICMR */
+        env->picmr |= rb;
+        break;
+    case TO_SPR(9, 2):  /* PICSR */
+        env->picsr &= ~rb;
+        break;
+    case TO_SPR(10, 0): /* TTMR */
+        {
+            int ip = env->ttmr & TTMR_IP;
+
+            if (rb & TTMR_IP) {    /* Keep IP bit.  */
+                env->ttmr = (rb & ~TTMR_IP) + ip;
+            } else {    /* Clear IP bit.  */
+                env->ttmr = rb & ~TTMR_IP;
+                env->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;
+            }
+        }
+        break;
+
+    case TO_SPR(10, 1): /* TTCR */
+        env->ttcr = rb;
+        if (env->ttmr & TIMER_NONE) {
+            return;
+        }
+        cpu_openrisc_count_start(cpu);
+        break;
+    default:
+
+        break;
+    }
+#endif
+}
+
+target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
+                           target_ulong rd, target_ulong ra, uint32_t offset)
+{
+#ifndef CONFIG_USER_ONLY
+    int spr = (ra | offset);
+    int idx;
+
+    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
+
+    switch (spr) {
+    case TO_SPR(0, 0): /* VR */
+        return env->vr & SPR_VR;
+
+    case TO_SPR(0, 1): /* UPR */
+        return env->upr;    /* TT, DM, IM, UP present */
+
+    case TO_SPR(0, 2): /* CPUCFGR */
+        return env->cpucfgr;
+
+    case TO_SPR(0, 3): /* DMMUCFGR */
+        return env->dmmucfgr;    /* 1Way, 64 entries */
+
+    case TO_SPR(0, 4): /* IMMUCFGR */
+        return env->immucfgr;
+
+    case TO_SPR(0, 16): /* NPC */
+        return env->npc;
+
+    case TO_SPR(0, 17): /* SR */
+        return env->sr;
+
+    case TO_SPR(0, 18): /* PPC */
+        return env->ppc;
+
+    case TO_SPR(0, 32): /* EPCR */
+        return env->epcr;
+
+    case TO_SPR(0, 48): /* EEAR */
+        return env->eear;
+
+    case TO_SPR(0, 64): /* ESR */
+        return env->esr;
+
+    case TO_SPR(1, 512) ... TO_SPR(1, 639): /* 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 */
+        idx = spr - TO_SPR(1, 640);
+        return env->tlb->dtlb[0][idx].tr;
+
+    case TO_SPR(1, 768) ... TO_SPR(1, 895):   /* DTLBW1MR 0-127 */
+    case TO_SPR(1, 896) ... TO_SPR(1, 1023):  /* DTLBW1TR 0-127 */
+    case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */
+    case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */
+    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 */
+        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 */
+        idx = spr - TO_SPR(2, 640);
+        return env->tlb->itlb[0][idx].tr;
+
+    case TO_SPR(2, 768) ... TO_SPR(2, 895):   /* ITLBW1MR 0-127 */
+    case TO_SPR(2, 896) ... TO_SPR(2, 1023):  /* ITLBW1TR 0-127 */
+    case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */
+    case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */
+    case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
+    case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
+        break;
+
+    case TO_SPR(9, 0):  /* PICMR */
+        return env->picmr;
+
+    case TO_SPR(9, 2):  /* PICSR */
+        return env->picsr;
+
+    case TO_SPR(10, 0): /* TTMR */
+        return env->ttmr;
+
+    case TO_SPR(10, 1): /* TTCR */
+        cpu_openrisc_count_update(cpu);
+        return env->ttcr;
+
+    default:
+        break;
+    }
+#endif
+
+/*If we later need to add tracepoints (or debug printfs) for the return
+value, it may be useful to structure the code like this:
+
+target_ulong ret = 0;
+
+switch() {
+case x:
+ ret = y;
+ break;
+case z:
+ ret = 42;
+ break;
+...
+}
+
+later something like trace_spr_read(ret);
+
+return ret;*/
+
+    /* for rd is passed in, if rd unchanged, just keep it back.  */
+    return rd;
+}
diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index ed25604..8069edb 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -995,10 +995,20 @@  static void dec_misc(DisasContext *dc, uint32_t insn)
 
     case 0x2d:    /* l.mfspr */
         LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
+        {
+            TCGv_i32 ti = tcg_const_i32(I16);
+            gen_helper_mfspr(cpu_R[rd], cpu_env, cpu_R[rd], cpu_R[ra], ti);
+            tcg_temp_free_i32(ti);
+        }
         break;
 
     case 0x30:    /* l.mtspr */
         LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+        {
+            TCGv_i32 im = tcg_const_i32(tmp);
+            gen_helper_mtspr(cpu_env, cpu_R[ra], cpu_R[rb], im);
+            tcg_temp_free_i32(im);
+        }
         break;
 
 /* not used yet, open it when we need or64.  */