xref: /qemu/target/rx/helper.c (revision 075d047e2bd69d01d8718f5b2750020151f96d2f)
1*075d047eSYoshinori Sato /*
2*075d047eSYoshinori Sato  *  RX emulation
3*075d047eSYoshinori Sato  *
4*075d047eSYoshinori Sato  *  Copyright (c) 2019 Yoshinori Sato
5*075d047eSYoshinori Sato  *
6*075d047eSYoshinori Sato  * This program is free software; you can redistribute it and/or modify it
7*075d047eSYoshinori Sato  * under the terms and conditions of the GNU General Public License,
8*075d047eSYoshinori Sato  * version 2 or later, as published by the Free Software Foundation.
9*075d047eSYoshinori Sato  *
10*075d047eSYoshinori Sato  * This program is distributed in the hope it will be useful, but WITHOUT
11*075d047eSYoshinori Sato  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*075d047eSYoshinori Sato  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13*075d047eSYoshinori Sato  * more details.
14*075d047eSYoshinori Sato  *
15*075d047eSYoshinori Sato  * You should have received a copy of the GNU General Public License along with
16*075d047eSYoshinori Sato  * this program.  If not, see <http://www.gnu.org/licenses/>.
17*075d047eSYoshinori Sato  */
18*075d047eSYoshinori Sato 
19*075d047eSYoshinori Sato #include "qemu/osdep.h"
20*075d047eSYoshinori Sato #include "qemu/bitops.h"
21*075d047eSYoshinori Sato #include "cpu.h"
22*075d047eSYoshinori Sato #include "exec/log.h"
23*075d047eSYoshinori Sato #include "exec/cpu_ldst.h"
24*075d047eSYoshinori Sato #include "sysemu/sysemu.h"
25*075d047eSYoshinori Sato #include "hw/irq.h"
26*075d047eSYoshinori Sato 
27*075d047eSYoshinori Sato void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte)
28*075d047eSYoshinori Sato {
29*075d047eSYoshinori Sato     if (env->psw_pm == 0) {
30*075d047eSYoshinori Sato         env->psw_ipl = FIELD_EX32(psw, PSW, IPL);
31*075d047eSYoshinori Sato         if (rte) {
32*075d047eSYoshinori Sato             /* PSW.PM can write RTE and RTFI */
33*075d047eSYoshinori Sato             env->psw_pm = FIELD_EX32(psw, PSW, PM);
34*075d047eSYoshinori Sato         }
35*075d047eSYoshinori Sato         env->psw_u = FIELD_EX32(psw, PSW, U);
36*075d047eSYoshinori Sato         env->psw_i = FIELD_EX32(psw, PSW, I);
37*075d047eSYoshinori Sato     }
38*075d047eSYoshinori Sato     env->psw_o = FIELD_EX32(psw, PSW, O) << 31;
39*075d047eSYoshinori Sato     env->psw_s = FIELD_EX32(psw, PSW, S) << 31;
40*075d047eSYoshinori Sato     env->psw_z = 1 - FIELD_EX32(psw, PSW, Z);
41*075d047eSYoshinori Sato     env->psw_c = FIELD_EX32(psw, PSW, C);
42*075d047eSYoshinori Sato }
43*075d047eSYoshinori Sato 
44*075d047eSYoshinori Sato #define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR)
45*075d047eSYoshinori Sato void rx_cpu_do_interrupt(CPUState *cs)
46*075d047eSYoshinori Sato {
47*075d047eSYoshinori Sato     RXCPU *cpu = RXCPU(cs);
48*075d047eSYoshinori Sato     CPURXState *env = &cpu->env;
49*075d047eSYoshinori Sato     int do_irq = cs->interrupt_request & INT_FLAGS;
50*075d047eSYoshinori Sato     uint32_t save_psw;
51*075d047eSYoshinori Sato 
52*075d047eSYoshinori Sato     env->in_sleep = 0;
53*075d047eSYoshinori Sato 
54*075d047eSYoshinori Sato     if (env->psw_u) {
55*075d047eSYoshinori Sato         env->usp = env->regs[0];
56*075d047eSYoshinori Sato     } else {
57*075d047eSYoshinori Sato         env->isp = env->regs[0];
58*075d047eSYoshinori Sato     }
59*075d047eSYoshinori Sato     save_psw = rx_cpu_pack_psw(env);
60*075d047eSYoshinori Sato     env->psw_pm = env->psw_i = env->psw_u = 0;
61*075d047eSYoshinori Sato 
62*075d047eSYoshinori Sato     if (do_irq) {
63*075d047eSYoshinori Sato         if (do_irq & CPU_INTERRUPT_FIR) {
64*075d047eSYoshinori Sato             env->bpc = env->pc;
65*075d047eSYoshinori Sato             env->bpsw = save_psw;
66*075d047eSYoshinori Sato             env->pc = env->fintv;
67*075d047eSYoshinori Sato             env->psw_ipl = 15;
68*075d047eSYoshinori Sato             cs->interrupt_request &= ~CPU_INTERRUPT_FIR;
69*075d047eSYoshinori Sato             qemu_set_irq(env->ack, env->ack_irq);
70*075d047eSYoshinori Sato             qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
71*075d047eSYoshinori Sato         } else if (do_irq & CPU_INTERRUPT_HARD) {
72*075d047eSYoshinori Sato             env->isp -= 4;
73*075d047eSYoshinori Sato             cpu_stl_data(env, env->isp, save_psw);
74*075d047eSYoshinori Sato             env->isp -= 4;
75*075d047eSYoshinori Sato             cpu_stl_data(env, env->isp, env->pc);
76*075d047eSYoshinori Sato             env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4);
77*075d047eSYoshinori Sato             env->psw_ipl = env->ack_ipl;
78*075d047eSYoshinori Sato             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
79*075d047eSYoshinori Sato             qemu_set_irq(env->ack, env->ack_irq);
80*075d047eSYoshinori Sato             qemu_log_mask(CPU_LOG_INT,
81*075d047eSYoshinori Sato                           "interrupt 0x%02x raised\n", env->ack_irq);
82*075d047eSYoshinori Sato         }
83*075d047eSYoshinori Sato     } else {
84*075d047eSYoshinori Sato         uint32_t vec = cs->exception_index;
85*075d047eSYoshinori Sato         const char *expname = "unknown exception";
86*075d047eSYoshinori Sato 
87*075d047eSYoshinori Sato         env->isp -= 4;
88*075d047eSYoshinori Sato         cpu_stl_data(env, env->isp, save_psw);
89*075d047eSYoshinori Sato         env->isp -= 4;
90*075d047eSYoshinori Sato         cpu_stl_data(env, env->isp, env->pc);
91*075d047eSYoshinori Sato 
92*075d047eSYoshinori Sato         if (vec < 0x100) {
93*075d047eSYoshinori Sato             env->pc = cpu_ldl_data(env, 0xffffffc0 + vec * 4);
94*075d047eSYoshinori Sato         } else {
95*075d047eSYoshinori Sato             env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4);
96*075d047eSYoshinori Sato         }
97*075d047eSYoshinori Sato         switch (vec) {
98*075d047eSYoshinori Sato         case 20:
99*075d047eSYoshinori Sato             expname = "privilege violation";
100*075d047eSYoshinori Sato             break;
101*075d047eSYoshinori Sato         case 21:
102*075d047eSYoshinori Sato             expname = "access exception";
103*075d047eSYoshinori Sato             break;
104*075d047eSYoshinori Sato         case 23:
105*075d047eSYoshinori Sato             expname = "illegal instruction";
106*075d047eSYoshinori Sato             break;
107*075d047eSYoshinori Sato         case 25:
108*075d047eSYoshinori Sato             expname = "fpu exception";
109*075d047eSYoshinori Sato             break;
110*075d047eSYoshinori Sato         case 30:
111*075d047eSYoshinori Sato             expname = "non-maskable interrupt";
112*075d047eSYoshinori Sato             break;
113*075d047eSYoshinori Sato         case 0x100 ... 0x1ff:
114*075d047eSYoshinori Sato             expname = "unconditional trap";
115*075d047eSYoshinori Sato         }
116*075d047eSYoshinori Sato         qemu_log_mask(CPU_LOG_INT, "exception 0x%02x [%s] raised\n",
117*075d047eSYoshinori Sato                       (vec & 0xff), expname);
118*075d047eSYoshinori Sato     }
119*075d047eSYoshinori Sato     env->regs[0] = env->isp;
120*075d047eSYoshinori Sato }
121*075d047eSYoshinori Sato 
122*075d047eSYoshinori Sato bool rx_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
123*075d047eSYoshinori Sato {
124*075d047eSYoshinori Sato     RXCPU *cpu = RXCPU(cs);
125*075d047eSYoshinori Sato     CPURXState *env = &cpu->env;
126*075d047eSYoshinori Sato     int accept = 0;
127*075d047eSYoshinori Sato     /* hardware interrupt (Normal) */
128*075d047eSYoshinori Sato     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
129*075d047eSYoshinori Sato         env->psw_i && (env->psw_ipl < env->req_ipl)) {
130*075d047eSYoshinori Sato         env->ack_irq = env->req_irq;
131*075d047eSYoshinori Sato         env->ack_ipl = env->req_ipl;
132*075d047eSYoshinori Sato         accept = 1;
133*075d047eSYoshinori Sato     }
134*075d047eSYoshinori Sato     /* hardware interrupt (FIR) */
135*075d047eSYoshinori Sato     if ((interrupt_request & CPU_INTERRUPT_FIR) &&
136*075d047eSYoshinori Sato         env->psw_i && (env->psw_ipl < 15)) {
137*075d047eSYoshinori Sato         accept = 1;
138*075d047eSYoshinori Sato     }
139*075d047eSYoshinori Sato     if (accept) {
140*075d047eSYoshinori Sato         rx_cpu_do_interrupt(cs);
141*075d047eSYoshinori Sato         return true;
142*075d047eSYoshinori Sato     }
143*075d047eSYoshinori Sato     return false;
144*075d047eSYoshinori Sato }
145*075d047eSYoshinori Sato 
146*075d047eSYoshinori Sato hwaddr rx_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
147*075d047eSYoshinori Sato {
148*075d047eSYoshinori Sato     return addr;
149*075d047eSYoshinori Sato }
150