blob: 4c85badd5d3411605758793da18f40b7338ca876 [file] [log] [blame]
pbrooke6e59062006-10-22 00:18:54 +00001/*
2 * m68k op helpers
ths5fafdf22007-09-16 21:08:06 +00003 *
pbrook06338792007-05-23 19:58:11 +00004 * Copyright (c) 2006-2007 CodeSourcery
pbrooke6e59062006-10-22 00:18:54 +00005 * Written by Paul Brook
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
Thomas Huthd749fb82019-01-29 14:43:58 +010010 * version 2.1 of the License, or (at your option) any later version.
pbrooke6e59062006-10-22 00:18:54 +000011 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Thomas Huthd749fb82019-01-29 14:43:58 +010015 * Lesser General Public License for more details.
pbrooke6e59062006-10-22 00:18:54 +000016 *
17 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000018 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
pbrooke6e59062006-10-22 00:18:54 +000019 */
20
Peter Maydelld8416662016-01-26 18:17:23 +000021#include "qemu/osdep.h"
pbrooke6e59062006-10-22 00:18:54 +000022#include "cpu.h"
Paolo Bonzini63c91552016-03-15 13:18:37 +010023#include "exec/exec-all.h"
Philippe Mathieu-Daudé74781c02023-12-06 20:27:32 +010024#include "exec/page-protection.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010025#include "exec/gdbstub.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070026#include "exec/helper-proto.h"
Alex Bennée4ea5fe92023-03-02 18:57:56 -080027#include "gdbstub/helpers.h"
Alex Bennée24f91e82018-01-19 18:24:22 +000028#include "fpu/softfloat.h"
Markus Armbruster04424282019-04-17 21:17:57 +020029#include "qemu/qemu-print.h"
pbrooke1f38082008-05-24 22:29:16 +000030
31#define SIGNBIT (1u << 31)
32
Akihiko Odaki66260152024-02-27 14:43:16 +000033static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
pbrook56aebc82008-10-11 17:55:29 +000034{
Akihiko Odaki66260152024-02-27 14:43:16 +000035 M68kCPU *cpu = M68K_CPU(cs);
36 CPUM68KState *env = &cpu->env;
37
pbrook56aebc82008-10-11 17:55:29 +000038 if (n < 8) {
Laurent Vivierf83311e2017-06-20 22:51:18 +020039 float_status s;
Peter Maydell7ed51402021-02-11 12:27:46 +000040 return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
pbrook56aebc82008-10-11 17:55:29 +000041 }
Laurent Vivierba624942017-06-20 22:51:20 +020042 switch (n) {
43 case 8: /* fpcontrol */
Alex Bennée462474d2020-03-16 17:21:39 +000044 return gdb_get_reg32(mem_buf, env->fpcr);
Laurent Vivierba624942017-06-20 22:51:20 +020045 case 9: /* fpstatus */
Alex Bennée462474d2020-03-16 17:21:39 +000046 return gdb_get_reg32(mem_buf, env->fpsr);
Laurent Vivierba624942017-06-20 22:51:20 +020047 case 10: /* fpiar, not implemented */
Alex Bennée462474d2020-03-16 17:21:39 +000048 return gdb_get_reg32(mem_buf, 0);
pbrook56aebc82008-10-11 17:55:29 +000049 }
50 return 0;
51}
52
Akihiko Odaki66260152024-02-27 14:43:16 +000053static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
pbrook56aebc82008-10-11 17:55:29 +000054{
Akihiko Odaki66260152024-02-27 14:43:16 +000055 M68kCPU *cpu = M68K_CPU(cs);
56 CPUM68KState *env = &cpu->env;
57
pbrook56aebc82008-10-11 17:55:29 +000058 if (n < 8) {
Laurent Vivierf83311e2017-06-20 22:51:18 +020059 float_status s;
Peter Maydell7ed51402021-02-11 12:27:46 +000060 env->fregs[n].d = float64_to_floatx80(ldq_p(mem_buf), &s);
pbrook56aebc82008-10-11 17:55:29 +000061 return 8;
62 }
Laurent Vivierba624942017-06-20 22:51:20 +020063 switch (n) {
64 case 8: /* fpcontrol */
65 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
66 return 4;
67 case 9: /* fpstatus */
68 env->fpsr = ldl_p(mem_buf);
69 return 4;
70 case 10: /* fpiar, not implemented */
pbrook56aebc82008-10-11 17:55:29 +000071 return 4;
72 }
73 return 0;
74}
75
Akihiko Odaki66260152024-02-27 14:43:16 +000076static int m68k_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
Laurent Vivier5a4526b2017-06-20 22:51:19 +020077{
Akihiko Odaki66260152024-02-27 14:43:16 +000078 M68kCPU *cpu = M68K_CPU(cs);
79 CPUM68KState *env = &cpu->env;
80
Laurent Vivier5a4526b2017-06-20 22:51:19 +020081 if (n < 8) {
Alex Bennée462474d2020-03-16 17:21:39 +000082 int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
Philippe Mathieu-Daudé4b27f9b2020-04-14 21:06:24 +010083 len += gdb_get_reg16(mem_buf, 0);
84 len += gdb_get_reg64(mem_buf, env->fregs[n].l.lower);
Alex Bennée462474d2020-03-16 17:21:39 +000085 return len;
Laurent Vivier5a4526b2017-06-20 22:51:19 +020086 }
87 switch (n) {
88 case 8: /* fpcontrol */
Alex Bennée462474d2020-03-16 17:21:39 +000089 return gdb_get_reg32(mem_buf, env->fpcr);
Laurent Vivier5a4526b2017-06-20 22:51:19 +020090 case 9: /* fpstatus */
Keith Packard58883572023-08-02 20:52:31 -070091 return gdb_get_reg32(mem_buf, cpu_m68k_get_fpsr(env));
Laurent Vivier5a4526b2017-06-20 22:51:19 +020092 case 10: /* fpiar, not implemented */
Alex Bennée462474d2020-03-16 17:21:39 +000093 return gdb_get_reg32(mem_buf, 0);
Laurent Vivier5a4526b2017-06-20 22:51:19 +020094 }
95 return 0;
96}
97
Akihiko Odaki66260152024-02-27 14:43:16 +000098static int m68k_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
Laurent Vivier5a4526b2017-06-20 22:51:19 +020099{
Akihiko Odaki66260152024-02-27 14:43:16 +0000100 M68kCPU *cpu = M68K_CPU(cs);
101 CPUM68KState *env = &cpu->env;
102
Laurent Vivier5a4526b2017-06-20 22:51:19 +0200103 if (n < 8) {
104 env->fregs[n].l.upper = lduw_be_p(mem_buf);
105 env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
106 return 12;
107 }
108 switch (n) {
109 case 8: /* fpcontrol */
Laurent Vivierba624942017-06-20 22:51:20 +0200110 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
Laurent Vivier5a4526b2017-06-20 22:51:19 +0200111 return 4;
112 case 9: /* fpstatus */
Keith Packard58883572023-08-02 20:52:31 -0700113 cpu_m68k_set_fpsr(env, ldl_p(mem_buf));
Laurent Vivier5a4526b2017-06-20 22:51:19 +0200114 return 4;
115 case 10: /* fpiar, not implemented */
116 return 4;
117 }
118 return 0;
119}
120
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100121void m68k_cpu_init_gdb(M68kCPU *cpu)
122{
Andreas Färber22169d42013-06-28 21:27:39 +0200123 CPUState *cs = CPU(cpu);
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100124 CPUM68KState *env = &cpu->env;
125
Andreas Färber11150912012-04-15 03:30:10 +0200126 if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
Laurent Vivierf83311e2017-06-20 22:51:18 +0200127 gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
Akihiko Odakiac1e8672024-02-27 14:43:14 +0000128 gdb_find_static_feature("cf-fp.xml"), 18);
Laurent Vivier5a4526b2017-06-20 22:51:19 +0200129 } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
Akihiko Odakiac1e8672024-02-27 14:43:14 +0000130 gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, m68k_fpu_gdb_set_reg,
131 gdb_find_static_feature("m68k-fp.xml"), 18);
bellardaaed9092007-11-10 15:15:54 +0000132 }
Andreas Färber11150912012-04-15 03:30:10 +0200133 /* TODO: Add [E]MAC registers. */
bellardaaed9092007-11-10 15:15:54 +0000134}
135
Laurent Vivier6e22b282018-01-04 02:29:12 +0100136void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
pbrook06338792007-05-23 19:58:11 +0000137{
138 switch (reg) {
Laurent Vivier6e22b282018-01-04 02:29:12 +0100139 case M68K_CR_CACR:
pbrook20dcee92007-06-03 11:13:39 +0000140 env->cacr = val;
141 m68k_switch_sp(env);
142 break;
Laurent Vivier6e22b282018-01-04 02:29:12 +0100143 case M68K_CR_ACR0:
144 case M68K_CR_ACR1:
145 case M68K_CR_ACR2:
146 case M68K_CR_ACR3:
pbrook20dcee92007-06-03 11:13:39 +0000147 /* TODO: Implement Access Control Registers. */
pbrook06338792007-05-23 19:58:11 +0000148 break;
Laurent Vivier6e22b282018-01-04 02:29:12 +0100149 case M68K_CR_VBR:
pbrook06338792007-05-23 19:58:11 +0000150 env->vbr = val;
151 break;
152 /* TODO: Implement control registers. */
153 default:
Richard Hendersona8d92fd2019-03-22 18:23:25 -0700154 cpu_abort(env_cpu(env),
Laurent Vivier6e22b282018-01-04 02:29:12 +0100155 "Unimplemented control register write 0x%x = 0x%x\n",
pbrook06338792007-05-23 19:58:11 +0000156 reg, val);
157 }
158}
159
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100160static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
161{
162 CPUState *cs = env_cpu(env);
163
164 cs->exception_index = tt;
165 cpu_loop_exit_restore(cs, raddr);
166}
167
Laurent Vivier6e22b282018-01-04 02:29:12 +0100168void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
169{
Laurent Vivier6e22b282018-01-04 02:29:12 +0100170 switch (reg) {
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100171 /* MC680[12346]0 */
Laurent Vivier5fa9f1f2018-01-18 20:38:44 +0100172 case M68K_CR_SFC:
173 env->sfc = val & 7;
174 return;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100175 /* MC680[12346]0 */
Laurent Vivier5fa9f1f2018-01-18 20:38:44 +0100176 case M68K_CR_DFC:
177 env->dfc = val & 7;
178 return;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100179 /* MC680[12346]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100180 case M68K_CR_VBR:
181 env->vbr = val;
182 return;
Laurent Vivier18b61022019-12-20 18:24:15 +0100183 /* MC680[2346]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100184 case M68K_CR_CACR:
Laurent Vivier18b61022019-12-20 18:24:15 +0100185 if (m68k_feature(env, M68K_FEATURE_M68020)) {
186 env->cacr = val & 0x0000000f;
187 } else if (m68k_feature(env, M68K_FEATURE_M68030)) {
188 env->cacr = val & 0x00003f1f;
189 } else if (m68k_feature(env, M68K_FEATURE_M68040)) {
190 env->cacr = val & 0x80008000;
191 } else if (m68k_feature(env, M68K_FEATURE_M68060)) {
192 env->cacr = val & 0xf8e0e000;
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100193 } else {
194 break;
Laurent Vivier18b61022019-12-20 18:24:15 +0100195 }
Laurent Vivier6e22b282018-01-04 02:29:12 +0100196 m68k_switch_sp(env);
197 return;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100198 /* MC680[46]0 */
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100199 case M68K_CR_TC:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100200 if (m68k_feature(env, M68K_FEATURE_M68040)
201 || m68k_feature(env, M68K_FEATURE_M68060)) {
202 env->mmu.tcr = val;
203 return;
204 }
205 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100206 /* MC68040 */
Laurent Viviere55886c2018-01-18 20:38:45 +0100207 case M68K_CR_MMUSR:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100208 if (m68k_feature(env, M68K_FEATURE_M68040)) {
209 env->mmu.mmusr = val;
210 return;
211 }
212 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100213 /* MC680[46]0 */
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100214 case M68K_CR_SRP:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100215 if (m68k_feature(env, M68K_FEATURE_M68040)
216 || m68k_feature(env, M68K_FEATURE_M68060)) {
217 env->mmu.srp = val;
218 return;
219 }
220 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100221 /* MC680[46]0 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100222 case M68K_CR_URP:
223 if (m68k_feature(env, M68K_FEATURE_M68040)
224 || m68k_feature(env, M68K_FEATURE_M68060)) {
225 env->mmu.urp = val;
226 return;
227 }
228 break;
229 /* MC680[12346]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100230 case M68K_CR_USP:
231 env->sp[M68K_USP] = val;
232 return;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100233 /* MC680[234]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100234 case M68K_CR_MSP:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100235 if (m68k_feature(env, M68K_FEATURE_M68020)
236 || m68k_feature(env, M68K_FEATURE_M68030)
237 || m68k_feature(env, M68K_FEATURE_M68040)) {
238 env->sp[M68K_SSP] = val;
239 return;
240 }
241 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100242 /* MC680[234]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100243 case M68K_CR_ISP:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100244 if (m68k_feature(env, M68K_FEATURE_M68020)
245 || m68k_feature(env, M68K_FEATURE_M68030)
246 || m68k_feature(env, M68K_FEATURE_M68040)) {
247 env->sp[M68K_ISP] = val;
248 return;
249 }
250 break;
Laurent Vivierc05c73b2018-01-18 20:38:42 +0100251 /* MC68040/MC68LC040 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100252 case M68K_CR_ITT0: /* MC68EC040 only: M68K_CR_IACR0 */
253 if (m68k_feature(env, M68K_FEATURE_M68040)) {
254 env->mmu.ttr[M68K_ITTR0] = val;
255 return;
256 }
257 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100258 /* MC68040/MC68LC040 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100259 case M68K_CR_ITT1: /* MC68EC040 only: M68K_CR_IACR1 */
260 if (m68k_feature(env, M68K_FEATURE_M68040)) {
261 env->mmu.ttr[M68K_ITTR1] = val;
262 return;
263 }
264 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100265 /* MC68040/MC68LC040 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100266 case M68K_CR_DTT0: /* MC68EC040 only: M68K_CR_DACR0 */
267 if (m68k_feature(env, M68K_FEATURE_M68040)) {
268 env->mmu.ttr[M68K_DTTR0] = val;
269 return;
270 }
271 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100272 /* MC68040/MC68LC040 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100273 case M68K_CR_DTT1: /* MC68EC040 only: M68K_CR_DACR1 */
274 if (m68k_feature(env, M68K_FEATURE_M68040)) {
275 env->mmu.ttr[M68K_DTTR1] = val;
276 return;
277 }
278 break;
Lucien Murray-Pitts57365262021-02-01 01:01:52 +0100279 /* Unimplemented Registers */
280 case M68K_CR_CAAR:
281 case M68K_CR_PCR:
282 case M68K_CR_BUSCR:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100283 cpu_abort(env_cpu(env),
284 "Unimplemented control register write 0x%x = 0x%x\n",
285 reg, val);
Laurent Vivier6e22b282018-01-04 02:29:12 +0100286 }
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100287
288 /* Invalid control registers will generate an exception. */
289 raise_exception_ra(env, EXCP_ILLEGAL, 0);
290 return;
Laurent Vivier6e22b282018-01-04 02:29:12 +0100291}
292
293uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
294{
Laurent Vivier6e22b282018-01-04 02:29:12 +0100295 switch (reg) {
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100296 /* MC680[12346]0 */
Laurent Vivier5fa9f1f2018-01-18 20:38:44 +0100297 case M68K_CR_SFC:
298 return env->sfc;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100299 /* MC680[12346]0 */
Laurent Vivier5fa9f1f2018-01-18 20:38:44 +0100300 case M68K_CR_DFC:
301 return env->dfc;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100302 /* MC680[12346]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100303 case M68K_CR_VBR:
304 return env->vbr;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100305 /* MC680[2346]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100306 case M68K_CR_CACR:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100307 if (m68k_feature(env, M68K_FEATURE_M68020)
308 || m68k_feature(env, M68K_FEATURE_M68030)
309 || m68k_feature(env, M68K_FEATURE_M68040)
310 || m68k_feature(env, M68K_FEATURE_M68060)) {
311 return env->cacr;
312 }
313 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100314 /* MC680[46]0 */
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100315 case M68K_CR_TC:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100316 if (m68k_feature(env, M68K_FEATURE_M68040)
317 || m68k_feature(env, M68K_FEATURE_M68060)) {
318 return env->mmu.tcr;
319 }
320 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100321 /* MC68040 */
Laurent Viviere55886c2018-01-18 20:38:45 +0100322 case M68K_CR_MMUSR:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100323 if (m68k_feature(env, M68K_FEATURE_M68040)) {
324 return env->mmu.mmusr;
325 }
326 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100327 /* MC680[46]0 */
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100328 case M68K_CR_SRP:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100329 if (m68k_feature(env, M68K_FEATURE_M68040)
330 || m68k_feature(env, M68K_FEATURE_M68060)) {
331 return env->mmu.srp;
332 }
333 break;
334 /* MC68040/MC68LC040 */
335 case M68K_CR_URP:
336 if (m68k_feature(env, M68K_FEATURE_M68040)
337 || m68k_feature(env, M68K_FEATURE_M68060)) {
338 return env->mmu.urp;
339 }
340 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100341 /* MC680[46]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100342 case M68K_CR_USP:
343 return env->sp[M68K_USP];
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100344 /* MC680[234]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100345 case M68K_CR_MSP:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100346 if (m68k_feature(env, M68K_FEATURE_M68020)
347 || m68k_feature(env, M68K_FEATURE_M68030)
348 || m68k_feature(env, M68K_FEATURE_M68040)) {
349 return env->sp[M68K_SSP];
350 }
351 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100352 /* MC680[234]0 */
Laurent Vivier6e22b282018-01-04 02:29:12 +0100353 case M68K_CR_ISP:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100354 if (m68k_feature(env, M68K_FEATURE_M68020)
355 || m68k_feature(env, M68K_FEATURE_M68030)
356 || m68k_feature(env, M68K_FEATURE_M68040)) {
357 return env->sp[M68K_ISP];
358 }
359 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100360 /* MC68040/MC68LC040 */
361 case M68K_CR_ITT0: /* MC68EC040 only: M68K_CR_IACR0 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100362 if (m68k_feature(env, M68K_FEATURE_M68040)) {
363 return env->mmu.ttr[M68K_ITTR0];
364 }
365 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100366 /* MC68040/MC68LC040 */
367 case M68K_CR_ITT1: /* MC68EC040 only: M68K_CR_IACR1 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100368 if (m68k_feature(env, M68K_FEATURE_M68040)) {
369 return env->mmu.ttr[M68K_ITTR1];
370 }
371 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100372 /* MC68040/MC68LC040 */
373 case M68K_CR_DTT0: /* MC68EC040 only: M68K_CR_DACR0 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100374 if (m68k_feature(env, M68K_FEATURE_M68040)) {
375 return env->mmu.ttr[M68K_DTTR0];
376 }
377 break;
Lucien Murray-Pitts60d8e962021-02-01 01:01:52 +0100378 /* MC68040/MC68LC040 */
379 case M68K_CR_DTT1: /* MC68EC040 only: M68K_CR_DACR1 */
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100380 if (m68k_feature(env, M68K_FEATURE_M68040)) {
381 return env->mmu.ttr[M68K_DTTR1];
382 }
383 break;
Lucien Murray-Pitts57365262021-02-01 01:01:52 +0100384 /* Unimplemented Registers */
385 case M68K_CR_CAAR:
386 case M68K_CR_PCR:
387 case M68K_CR_BUSCR:
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100388 cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n",
389 reg);
Laurent Vivier6e22b282018-01-04 02:29:12 +0100390 }
Lucien Murray-Pitts8df0e6a2021-02-01 01:01:52 +0100391
392 /* Invalid control registers will generate an exception. */
393 raise_exception_ra(env, EXCP_ILLEGAL, 0);
394
395 return 0;
Laurent Vivier6e22b282018-01-04 02:29:12 +0100396}
397
pbrooke1f38082008-05-24 22:29:16 +0000398void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
pbrookacf930a2007-05-29 14:57:59 +0000399{
400 uint32_t acc;
401 int8_t exthigh;
402 uint8_t extlow;
403 uint64_t regval;
404 int i;
405 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
406 for (i = 0; i < 4; i++) {
407 regval = env->macc[i];
408 exthigh = regval >> 40;
409 if (env->macsr & MACSR_FI) {
410 acc = regval >> 8;
411 extlow = regval;
412 } else {
413 acc = regval;
414 extlow = regval >> 32;
415 }
416 if (env->macsr & MACSR_FI) {
417 regval = (((uint64_t)acc) << 8) | extlow;
418 regval |= ((int64_t)exthigh) << 40;
419 } else if (env->macsr & MACSR_SU) {
420 regval = acc | (((int64_t)extlow) << 32);
421 regval |= ((int64_t)exthigh) << 40;
422 } else {
423 regval = acc | (((uint64_t)extlow) << 32);
424 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
425 }
426 env->macc[i] = regval;
427 }
428 }
429 env->macsr = val;
430}
431
pbrook20dcee92007-06-03 11:13:39 +0000432void m68k_switch_sp(CPUM68KState *env)
433{
434 int new_sp;
435
436 env->sp[env->current_sp] = env->aregs[7];
Mark Cave-Aylandaece90d2022-09-17 12:25:12 +0100437 if (m68k_feature(env, M68K_FEATURE_M68K)) {
Laurent Vivier6e22b282018-01-04 02:29:12 +0100438 if (env->sr & SR_S) {
Lucien Murray-Pitts7525a9b2021-02-01 01:01:52 +0100439 /* SR:Master-Mode bit unimplemented then ISP is not available */
440 if (!m68k_feature(env, M68K_FEATURE_MSP) || env->sr & SR_M) {
Laurent Vivier6e22b282018-01-04 02:29:12 +0100441 new_sp = M68K_SSP;
442 } else {
443 new_sp = M68K_ISP;
444 }
445 } else {
446 new_sp = M68K_USP;
447 }
448 } else {
449 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
450 ? M68K_SSP : M68K_USP;
451 }
pbrook20dcee92007-06-03 11:13:39 +0000452 env->aregs[7] = env->sp[new_sp];
453 env->current_sp = new_sp;
454}
455
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700456#if !defined(CONFIG_USER_ONLY)
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100457/* MMU: 68040 only */
Paul Brook4fcc5622010-03-01 03:46:18 +0000458
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200459static void print_address_zone(uint32_t logical, uint32_t physical,
Laurent Vivier2097dca2018-01-18 20:38:46 +0100460 uint32_t size, int attr)
461{
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200462 qemu_printf("%08x - %08x -> %08x - %08x %c ",
Laurent Vivier2097dca2018-01-18 20:38:46 +0100463 logical, logical + size - 1,
464 physical, physical + size - 1,
465 attr & 4 ? 'W' : '-');
466 size >>= 10;
467 if (size < 1024) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200468 qemu_printf("(%d KiB)\n", size);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100469 } else {
470 size >>= 10;
471 if (size < 1024) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200472 qemu_printf("(%d MiB)\n", size);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100473 } else {
474 size >>= 10;
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200475 qemu_printf("(%d GiB)\n", size);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100476 }
477 }
478}
479
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200480static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
Laurent Vivier2097dca2018-01-18 20:38:46 +0100481{
Laurent Vivier2097dca2018-01-18 20:38:46 +0100482 int tic_size, tic_shift;
483 uint32_t tib_mask;
484 uint32_t tia, tib, tic;
485 uint32_t logical = 0xffffffff, physical = 0xffffffff;
486 uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
487 uint32_t last_logical, last_physical;
488 int32_t size;
489 int last_attr = -1, attr = -1;
Richard Hendersona8d92fd2019-03-22 18:23:25 -0700490 CPUState *cs = env_cpu(env);
Peter Maydellf80b5512018-12-10 16:56:34 +0000491 MemTxResult txres;
Laurent Vivier2097dca2018-01-18 20:38:46 +0100492
493 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
494 /* 8k page */
495 tic_size = 32;
496 tic_shift = 13;
497 tib_mask = M68K_8K_PAGE_MASK;
498 } else {
499 /* 4k page */
500 tic_size = 64;
501 tic_shift = 12;
502 tib_mask = M68K_4K_PAGE_MASK;
503 }
Peter Maydell7d016232024-07-23 16:42:07 +0100504 for (unsigned i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
Peter Maydellf80b5512018-12-10 16:56:34 +0000505 tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
506 MEMTXATTRS_UNSPECIFIED, &txres);
507 if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
Laurent Vivier2097dca2018-01-18 20:38:46 +0100508 continue;
509 }
Peter Maydell7d016232024-07-23 16:42:07 +0100510 for (unsigned j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
Peter Maydellf80b5512018-12-10 16:56:34 +0000511 tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
512 MEMTXATTRS_UNSPECIFIED, &txres);
513 if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
Laurent Vivier2097dca2018-01-18 20:38:46 +0100514 continue;
515 }
Peter Maydell7d016232024-07-23 16:42:07 +0100516 for (unsigned k = 0; k < tic_size; k++) {
Peter Maydellf80b5512018-12-10 16:56:34 +0000517 tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
518 MEMTXATTRS_UNSPECIFIED, &txres);
519 if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
Laurent Vivier2097dca2018-01-18 20:38:46 +0100520 continue;
521 }
522 if (M68K_PDT_INDIRECT(tic)) {
Peter Maydellf80b5512018-12-10 16:56:34 +0000523 tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic),
524 MEMTXATTRS_UNSPECIFIED, &txres);
525 if (txres != MEMTX_OK) {
526 continue;
527 }
Laurent Vivier2097dca2018-01-18 20:38:46 +0100528 }
529
530 last_logical = logical;
531 logical = (i << M68K_TTS_ROOT_SHIFT) |
532 (j << M68K_TTS_POINTER_SHIFT) |
533 (k << tic_shift);
534
535 last_physical = physical;
536 physical = tic & ~((1 << tic_shift) - 1);
537
538 last_attr = attr;
539 attr = tic & ((1 << tic_shift) - 1);
540
541 if ((logical != (last_logical + (1 << tic_shift))) ||
542 (physical != (last_physical + (1 << tic_shift))) ||
543 (attr & 4) != (last_attr & 4)) {
544
545 if (first_logical != 0xffffffff) {
546 size = last_logical + (1 << tic_shift) -
547 first_logical;
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200548 print_address_zone(first_logical,
Laurent Vivier2097dca2018-01-18 20:38:46 +0100549 first_physical, size, last_attr);
550 }
551 first_logical = logical;
552 first_physical = physical;
553 }
554 }
555 }
556 }
557 if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
558 size = logical + (1 << tic_shift) - first_logical;
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200559 print_address_zone(first_logical, first_physical, size, last_attr);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100560 }
561}
562
563#define DUMP_CACHEFLAGS(a) \
564 switch (a & M68K_DESC_CACHEMODE) { \
Michael Tokarev8b819682023-07-14 14:23:51 +0300565 case M68K_DESC_CM_WRTHRU: /* cacheable, write-through */ \
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200566 qemu_printf("T"); \
Laurent Vivier2097dca2018-01-18 20:38:46 +0100567 break; \
Michael Tokarev8b819682023-07-14 14:23:51 +0300568 case M68K_DESC_CM_COPYBK: /* cacheable, copyback */ \
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200569 qemu_printf("C"); \
Laurent Vivier2097dca2018-01-18 20:38:46 +0100570 break; \
571 case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200572 qemu_printf("S"); \
Laurent Vivier2097dca2018-01-18 20:38:46 +0100573 break; \
574 case M68K_DESC_CM_NCACHE: /* noncachable */ \
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200575 qemu_printf("N"); \
Laurent Vivier2097dca2018-01-18 20:38:46 +0100576 break; \
577 }
578
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200579static void dump_ttr(uint32_t ttr)
Laurent Vivier2097dca2018-01-18 20:38:46 +0100580{
581 if ((ttr & M68K_TTR_ENABLED) == 0) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200582 qemu_printf("disabled\n");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100583 return;
584 }
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200585 qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ",
Laurent Vivier2097dca2018-01-18 20:38:46 +0100586 ttr & M68K_TTR_ADDR_BASE,
587 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
588 switch (ttr & M68K_TTR_SFIELD) {
589 case M68K_TTR_SFIELD_USER:
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200590 qemu_printf("U");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100591 break;
592 case M68K_TTR_SFIELD_SUPER:
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200593 qemu_printf("S");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100594 break;
595 default:
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200596 qemu_printf("*");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100597 break;
598 }
599 DUMP_CACHEFLAGS(ttr);
600 if (ttr & M68K_DESC_WRITEPROT) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200601 qemu_printf("R");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100602 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200603 qemu_printf("W");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100604 }
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200605 qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >>
Laurent Vivier2097dca2018-01-18 20:38:46 +0100606 M68K_DESC_USERATTR_SHIFT);
607}
608
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200609void dump_mmu(CPUM68KState *env)
Laurent Vivier2097dca2018-01-18 20:38:46 +0100610{
611 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200612 qemu_printf("Translation disabled\n");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100613 return;
614 }
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200615 qemu_printf("Page Size: ");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100616 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200617 qemu_printf("8kB\n");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100618 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200619 qemu_printf("4kB\n");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100620 }
621
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200622 qemu_printf("MMUSR: ");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100623 if (env->mmu.mmusr & M68K_MMU_B_040) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200624 qemu_printf("BUS ERROR\n");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100625 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200626 qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100627 /* flags found on the page descriptor */
628 if (env->mmu.mmusr & M68K_MMU_G_040) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200629 qemu_printf("G"); /* Global */
Laurent Vivier2097dca2018-01-18 20:38:46 +0100630 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200631 qemu_printf(".");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100632 }
633 if (env->mmu.mmusr & M68K_MMU_S_040) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200634 qemu_printf("S"); /* Supervisor */
Laurent Vivier2097dca2018-01-18 20:38:46 +0100635 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200636 qemu_printf(".");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100637 }
638 if (env->mmu.mmusr & M68K_MMU_M_040) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200639 qemu_printf("M"); /* Modified */
Laurent Vivier2097dca2018-01-18 20:38:46 +0100640 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200641 qemu_printf(".");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100642 }
643 if (env->mmu.mmusr & M68K_MMU_WP_040) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200644 qemu_printf("W"); /* Write protect */
Laurent Vivier2097dca2018-01-18 20:38:46 +0100645 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200646 qemu_printf(".");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100647 }
648 if (env->mmu.mmusr & M68K_MMU_T_040) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200649 qemu_printf("T"); /* Transparent */
Laurent Vivier2097dca2018-01-18 20:38:46 +0100650 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200651 qemu_printf(".");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100652 }
653 if (env->mmu.mmusr & M68K_MMU_R_040) {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200654 qemu_printf("R"); /* Resident */
Laurent Vivier2097dca2018-01-18 20:38:46 +0100655 } else {
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200656 qemu_printf(".");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100657 }
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200658 qemu_printf(" Cache: ");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100659 DUMP_CACHEFLAGS(env->mmu.mmusr);
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200660 qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3);
661 qemu_printf("\n");
Laurent Vivier2097dca2018-01-18 20:38:46 +0100662 }
663
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200664 qemu_printf("ITTR0: ");
665 dump_ttr(env->mmu.ttr[M68K_ITTR0]);
666 qemu_printf("ITTR1: ");
667 dump_ttr(env->mmu.ttr[M68K_ITTR1]);
668 qemu_printf("DTTR0: ");
669 dump_ttr(env->mmu.ttr[M68K_DTTR0]);
670 qemu_printf("DTTR1: ");
671 dump_ttr(env->mmu.ttr[M68K_DTTR1]);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100672
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200673 qemu_printf("SRP: 0x%08x\n", env->mmu.srp);
674 dump_address_map(env, env->mmu.srp);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100675
Markus Armbrusterfad866d2019-04-17 21:17:58 +0200676 qemu_printf("URP: 0x%08x\n", env->mmu.urp);
677 dump_address_map(env, env->mmu.urp);
Laurent Vivier2097dca2018-01-18 20:38:46 +0100678}
679
Laurent Vivierc05c73b2018-01-18 20:38:42 +0100680static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
681 int access_type)
682{
683 uint32_t base, mask;
684
685 /* check if transparent translation is enabled */
686 if ((ttr & M68K_TTR_ENABLED) == 0) {
687 return 0;
688 }
689
690 /* check mode access */
691 switch (ttr & M68K_TTR_SFIELD) {
692 case M68K_TTR_SFIELD_USER:
693 /* match only if user */
694 if ((access_type & ACCESS_SUPER) != 0) {
695 return 0;
696 }
697 break;
698 case M68K_TTR_SFIELD_SUPER:
699 /* match only if supervisor */
700 if ((access_type & ACCESS_SUPER) == 0) {
701 return 0;
702 }
703 break;
704 default:
705 /* all other values disable mode matching (FC2) */
706 break;
707 }
708
709 /* check address matching */
710
711 base = ttr & M68K_TTR_ADDR_BASE;
712 mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
713 mask <<= M68K_TTR_ADDR_MASK_SHIFT;
714
715 if ((addr & mask) != (base & mask)) {
716 return 0;
717 }
718
719 *prot = PAGE_READ | PAGE_EXEC;
720 if ((ttr & M68K_DESC_WRITEPROT) == 0) {
721 *prot |= PAGE_WRITE;
722 }
723
724 return 1;
725}
726
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100727static int get_physical_address(CPUM68KState *env, hwaddr *physical,
728 int *prot, target_ulong address,
729 int access_type, target_ulong *page_size)
730{
Richard Hendersona8d92fd2019-03-22 18:23:25 -0700731 CPUState *cs = env_cpu(env);
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100732 uint32_t entry;
733 uint32_t next;
734 target_ulong page_mask;
735 bool debug = access_type & ACCESS_DEBUG;
736 int page_bits;
Laurent Vivierc05c73b2018-01-18 20:38:42 +0100737 int i;
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000738 MemTxResult txres;
Laurent Vivierc05c73b2018-01-18 20:38:42 +0100739
740 /* Transparent Translation (physical = logical) */
741 for (i = 0; i < M68K_MAX_TTR; i++) {
742 if (check_TTR(env->mmu.TTR(access_type, i),
743 prot, address, access_type)) {
Laurent Viviere55886c2018-01-18 20:38:45 +0100744 if (access_type & ACCESS_PTEST) {
745 /* Transparent Translation Register bit */
746 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
747 }
Mark Cave-Ayland852002b2020-07-01 21:15:31 +0100748 *physical = address;
Laurent Vivierc05c73b2018-01-18 20:38:42 +0100749 *page_size = TARGET_PAGE_SIZE;
750 return 0;
751 }
752 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100753
754 /* Page Table Root Pointer */
755 *prot = PAGE_READ | PAGE_WRITE;
756 if (access_type & ACCESS_CODE) {
757 *prot |= PAGE_EXEC;
758 }
759 if (access_type & ACCESS_SUPER) {
760 next = env->mmu.srp;
761 } else {
762 next = env->mmu.urp;
763 }
764
765 /* Root Index */
766 entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
767
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000768 next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
769 if (txres != MEMTX_OK) {
770 goto txfail;
771 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100772 if (!M68K_UDT_VALID(next)) {
773 return -1;
774 }
775 if (!(next & M68K_DESC_USED) && !debug) {
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000776 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
777 MEMTXATTRS_UNSPECIFIED, &txres);
778 if (txres != MEMTX_OK) {
779 goto txfail;
780 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100781 }
782 if (next & M68K_DESC_WRITEPROT) {
Laurent Viviere55886c2018-01-18 20:38:45 +0100783 if (access_type & ACCESS_PTEST) {
784 env->mmu.mmusr |= M68K_MMU_WP_040;
785 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100786 *prot &= ~PAGE_WRITE;
787 if (access_type & ACCESS_STORE) {
788 return -1;
789 }
790 }
791
792 /* Pointer Index */
793 entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
794
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000795 next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
796 if (txres != MEMTX_OK) {
797 goto txfail;
798 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100799 if (!M68K_UDT_VALID(next)) {
800 return -1;
801 }
802 if (!(next & M68K_DESC_USED) && !debug) {
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000803 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
804 MEMTXATTRS_UNSPECIFIED, &txres);
805 if (txres != MEMTX_OK) {
806 goto txfail;
807 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100808 }
809 if (next & M68K_DESC_WRITEPROT) {
Laurent Viviere55886c2018-01-18 20:38:45 +0100810 if (access_type & ACCESS_PTEST) {
811 env->mmu.mmusr |= M68K_MMU_WP_040;
812 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100813 *prot &= ~PAGE_WRITE;
814 if (access_type & ACCESS_STORE) {
815 return -1;
816 }
817 }
818
819 /* Page Index */
820 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
821 entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
822 } else {
823 entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
824 }
825
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000826 next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
827 if (txres != MEMTX_OK) {
828 goto txfail;
829 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100830
831 if (!M68K_PDT_VALID(next)) {
832 return -1;
833 }
834 if (M68K_PDT_INDIRECT(next)) {
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000835 next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next),
836 MEMTXATTRS_UNSPECIFIED, &txres);
837 if (txres != MEMTX_OK) {
838 goto txfail;
839 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100840 }
841 if (access_type & ACCESS_STORE) {
842 if (next & M68K_DESC_WRITEPROT) {
843 if (!(next & M68K_DESC_USED) && !debug) {
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000844 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
845 MEMTXATTRS_UNSPECIFIED, &txres);
846 if (txres != MEMTX_OK) {
847 goto txfail;
848 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100849 }
850 } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
851 (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000852 address_space_stl(cs->as, entry,
853 next | (M68K_DESC_MODIFIED | M68K_DESC_USED),
854 MEMTXATTRS_UNSPECIFIED, &txres);
855 if (txres != MEMTX_OK) {
856 goto txfail;
857 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100858 }
859 } else {
860 if (!(next & M68K_DESC_USED) && !debug) {
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000861 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
862 MEMTXATTRS_UNSPECIFIED, &txres);
863 if (txres != MEMTX_OK) {
864 goto txfail;
865 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100866 }
867 }
868
869 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
870 page_bits = 13;
871 } else {
872 page_bits = 12;
873 }
874 *page_size = 1 << page_bits;
875 page_mask = ~(*page_size - 1);
Mark Cave-Ayland852002b2020-07-01 21:15:31 +0100876 *physical = (next & page_mask) + (address & (*page_size - 1));
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100877
Laurent Viviere55886c2018-01-18 20:38:45 +0100878 if (access_type & ACCESS_PTEST) {
879 env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
880 env->mmu.mmusr |= *physical & 0xfffff000;
881 env->mmu.mmusr |= M68K_MMU_R_040;
882 }
883
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100884 if (next & M68K_DESC_WRITEPROT) {
885 *prot &= ~PAGE_WRITE;
886 if (access_type & ACCESS_STORE) {
887 return -1;
888 }
889 }
890 if (next & M68K_DESC_SUPERONLY) {
891 if ((access_type & ACCESS_SUPER) == 0) {
892 return -1;
893 }
894 }
895
896 return 0;
Peter Maydelladcf0bf2018-12-10 16:56:35 +0000897
898txfail:
899 /*
900 * A page table load/store failed. TODO: we should really raise a
901 * suitable guest fault here if this is not a debug access.
902 * For now just return that the translation failed.
903 */
904 return -1;
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100905}
906
Andreas Färber00b941e2013-06-29 18:55:54 +0200907hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
Paul Brook4fcc5622010-03-01 03:46:18 +0000908{
Philippe Mathieu-Daudée22a4562024-01-29 17:44:58 +0100909 CPUM68KState *env = cpu_env(cs);
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100910 hwaddr phys_addr;
911 int prot;
912 int access_type;
913 target_ulong page_size;
914
915 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
916 /* MMU disabled */
917 return addr;
918 }
919
920 access_type = ACCESS_DATA | ACCESS_DEBUG;
921 if (env->sr & SR_S) {
922 access_type |= ACCESS_SUPER;
923 }
Mark Cave-Ayland78318112020-07-01 21:15:30 +0100924
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100925 if (get_physical_address(env, &phys_addr, &prot,
926 addr, access_type, &page_size) != 0) {
927 return -1;
928 }
Mark Cave-Ayland78318112020-07-01 21:15:30 +0100929
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100930 return phys_addr;
Paul Brook4fcc5622010-03-01 03:46:18 +0000931}
932
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700933/*
934 * Notify CPU of a pending interrupt. Prioritization and vectoring should
935 * be handled by the interrupt controller. Real hardware only requests
936 * the vector when the interrupt is acknowledged by the CPU. For
937 * simplicity we calculate it when the interrupt is signalled.
938 */
939void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
940{
941 CPUState *cs = CPU(cpu);
942 CPUM68KState *env = &cpu->env;
943
944 env->pending_level = level;
945 env->pending_vector = vector;
946 if (level) {
947 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
948 } else {
949 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
950 }
951}
952
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700953bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
954 MMUAccessType qemu_access_type, int mmu_idx,
955 bool probe, uintptr_t retaddr)
pbrook06338792007-05-23 19:58:11 +0000956{
Philippe Mathieu-Daudée22a4562024-01-29 17:44:58 +0100957 CPUM68KState *env = cpu_env(cs);
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100958 hwaddr physical;
pbrook06338792007-05-23 19:58:11 +0000959 int prot;
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100960 int access_type;
961 int ret;
962 target_ulong page_size;
pbrook06338792007-05-23 19:58:11 +0000963
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100964 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
965 /* MMU disabled */
966 tlb_set_page(cs, address & TARGET_PAGE_MASK,
967 address & TARGET_PAGE_MASK,
968 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
969 mmu_idx, TARGET_PAGE_SIZE);
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700970 return true;
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100971 }
972
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700973 if (qemu_access_type == MMU_INST_FETCH) {
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100974 access_type = ACCESS_CODE;
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100975 } else {
976 access_type = ACCESS_DATA;
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700977 if (qemu_access_type == MMU_DATA_STORE) {
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100978 access_type |= ACCESS_STORE;
979 }
980 }
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100981 if (mmu_idx != MMU_USER_IDX) {
982 access_type |= ACCESS_SUPER;
983 }
984
Philippe Mathieu-Daudéee1004b2024-01-29 17:44:43 +0100985 ret = get_physical_address(env, &physical, &prot,
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100986 address, access_type, &page_size);
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700987 if (likely(ret == 0)) {
Mark Cave-Ayland852002b2020-07-01 21:15:31 +0100988 tlb_set_page(cs, address & TARGET_PAGE_MASK,
989 physical & TARGET_PAGE_MASK, prot, mmu_idx, page_size);
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700990 return true;
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100991 }
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700992
993 if (probe) {
994 return false;
995 }
996
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100997 /* page fault */
998 env->mmu.ssw = M68K_ATC_040;
999 switch (size) {
1000 case 1:
1001 env->mmu.ssw |= M68K_BA_SIZE_BYTE;
1002 break;
1003 case 2:
1004 env->mmu.ssw |= M68K_BA_SIZE_WORD;
1005 break;
1006 case 4:
1007 env->mmu.ssw |= M68K_BA_SIZE_LONG;
1008 break;
1009 }
1010 if (access_type & ACCESS_SUPER) {
1011 env->mmu.ssw |= M68K_TM_040_SUPER;
1012 }
1013 if (access_type & ACCESS_CODE) {
1014 env->mmu.ssw |= M68K_TM_040_CODE;
1015 } else {
1016 env->mmu.ssw |= M68K_TM_040_DATA;
1017 }
1018 if (!(access_type & ACCESS_STORE)) {
1019 env->mmu.ssw |= M68K_RW_040;
1020 }
Richard Hendersonfe5f7b12019-04-02 15:55:10 +07001021
Laurent Vivier88b2fef2018-01-18 20:38:41 +01001022 cs->exception_index = EXCP_ACCESS;
Richard Hendersonfe5f7b12019-04-02 15:55:10 +07001023 env->mmu.ar = address;
1024 cpu_loop_exit_restore(cs, retaddr);
pbrook06338792007-05-23 19:58:11 +00001025}
Richard Henderson028772c2021-09-14 16:56:32 -07001026#endif /* !CONFIG_USER_ONLY */
pbrook06338792007-05-23 19:58:11 +00001027
pbrooke1f38082008-05-24 22:29:16 +00001028uint32_t HELPER(bitrev)(uint32_t x)
1029{
1030 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
1031 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
1032 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
1033 return bswap32(x);
1034}
1035
1036uint32_t HELPER(ff1)(uint32_t x)
1037{
1038 int n;
1039 for (n = 32; x; n--)
1040 x >>= 1;
1041 return n;
1042}
1043
Richard Henderson620c6cf2015-08-14 07:59:20 -07001044uint32_t HELPER(sats)(uint32_t val, uint32_t v)
pbrooke1f38082008-05-24 22:29:16 +00001045{
1046 /* The result has the opposite sign to the original value. */
Richard Henderson620c6cf2015-08-14 07:59:20 -07001047 if ((int32_t)v < 0) {
pbrooke1f38082008-05-24 22:29:16 +00001048 val = (((int32_t)val) >> 31) ^ SIGNBIT;
Richard Henderson620c6cf2015-08-14 07:59:20 -07001049 }
pbrooke1f38082008-05-24 22:29:16 +00001050 return val;
1051}
1052
Laurent Vivierd2f8fb82018-01-04 02:29:02 +01001053void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
pbrooke1f38082008-05-24 22:29:16 +00001054{
Laurent Vivierd2f8fb82018-01-04 02:29:02 +01001055 env->sr = sr & 0xffe0;
1056 cpu_m68k_set_ccr(env, sr);
pbrooke1f38082008-05-24 22:29:16 +00001057 m68k_switch_sp(env);
1058}
1059
Laurent Vivierd2f8fb82018-01-04 02:29:02 +01001060void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
1061{
1062 cpu_m68k_set_sr(env, val);
1063}
pbrooke1f38082008-05-24 22:29:16 +00001064
1065/* MAC unit. */
Lucien Murray-Pitts808d77b2019-06-07 08:41:25 +09001066/*
1067 * FIXME: The MAC unit implementation is a bit of a mess. Some helpers
1068 * take values, others take register numbers and manipulate the contents
1069 * in-place.
1070 */
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001071void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
pbrooke1f38082008-05-24 22:29:16 +00001072{
1073 uint32_t mask;
1074 env->macc[dest] = env->macc[src];
1075 mask = MACSR_PAV0 << dest;
1076 if (env->macsr & (MACSR_PAV0 << src))
1077 env->macsr |= mask;
1078 else
1079 env->macsr &= ~mask;
1080}
1081
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001082uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +00001083{
1084 int64_t product;
1085 int64_t res;
1086
1087 product = (uint64_t)op1 * op2;
1088 res = (product << 24) >> 24;
1089 if (res != product) {
1090 env->macsr |= MACSR_V;
1091 if (env->macsr & MACSR_OMC) {
1092 /* Make sure the accumulate operation overflows. */
1093 if (product < 0)
1094 res = ~(1ll << 50);
1095 else
1096 res = 1ll << 50;
1097 }
1098 }
1099 return res;
1100}
1101
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001102uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +00001103{
1104 uint64_t product;
1105
1106 product = (uint64_t)op1 * op2;
1107 if (product & (0xffffffull << 40)) {
1108 env->macsr |= MACSR_V;
1109 if (env->macsr & MACSR_OMC) {
1110 /* Make sure the accumulate operation overflows. */
1111 product = 1ll << 50;
1112 } else {
1113 product &= ((1ull << 40) - 1);
1114 }
1115 }
1116 return product;
1117}
1118
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001119uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +00001120{
1121 uint64_t product;
1122 uint32_t remainder;
1123
1124 product = (uint64_t)op1 * op2;
1125 if (env->macsr & MACSR_RT) {
1126 remainder = product & 0xffffff;
1127 product >>= 24;
1128 if (remainder > 0x800000)
1129 product++;
1130 else if (remainder == 0x800000)
1131 product += (product & 1);
1132 } else {
1133 product >>= 24;
1134 }
1135 return product;
1136}
1137
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001138void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001139{
1140 int64_t tmp;
1141 int64_t result;
1142 tmp = env->macc[acc];
1143 result = ((tmp << 16) >> 16);
1144 if (result != tmp) {
1145 env->macsr |= MACSR_V;
1146 }
1147 if (env->macsr & MACSR_V) {
1148 env->macsr |= MACSR_PAV0 << acc;
1149 if (env->macsr & MACSR_OMC) {
Lucien Murray-Pitts808d77b2019-06-07 08:41:25 +09001150 /*
1151 * The result is saturated to 32 bits, despite overflow occurring
1152 * at 48 bits. Seems weird, but that's what the hardware docs
1153 * say.
1154 */
pbrooke1f38082008-05-24 22:29:16 +00001155 result = (result >> 63) ^ 0x7fffffff;
1156 }
1157 }
1158 env->macc[acc] = result;
1159}
1160
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001161void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001162{
1163 uint64_t val;
1164
1165 val = env->macc[acc];
1166 if (val & (0xffffull << 48)) {
1167 env->macsr |= MACSR_V;
1168 }
1169 if (env->macsr & MACSR_V) {
1170 env->macsr |= MACSR_PAV0 << acc;
1171 if (env->macsr & MACSR_OMC) {
1172 if (val > (1ull << 53))
1173 val = 0;
1174 else
1175 val = (1ull << 48) - 1;
1176 } else {
1177 val &= ((1ull << 48) - 1);
1178 }
1179 }
1180 env->macc[acc] = val;
1181}
1182
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001183void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001184{
1185 int64_t sum;
1186 int64_t result;
1187
1188 sum = env->macc[acc];
1189 result = (sum << 16) >> 16;
1190 if (result != sum) {
1191 env->macsr |= MACSR_V;
1192 }
1193 if (env->macsr & MACSR_V) {
1194 env->macsr |= MACSR_PAV0 << acc;
1195 if (env->macsr & MACSR_OMC) {
1196 result = (result >> 63) ^ 0x7fffffffffffll;
1197 }
1198 }
1199 env->macc[acc] = result;
1200}
1201
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001202void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001203{
1204 uint64_t val;
1205 val = env->macc[acc];
Blue Swirlc4162572010-04-23 19:22:22 +00001206 if (val == 0) {
pbrooke1f38082008-05-24 22:29:16 +00001207 env->macsr |= MACSR_Z;
Blue Swirlc4162572010-04-23 19:22:22 +00001208 } else if (val & (1ull << 47)) {
pbrooke1f38082008-05-24 22:29:16 +00001209 env->macsr |= MACSR_N;
Blue Swirlc4162572010-04-23 19:22:22 +00001210 }
pbrooke1f38082008-05-24 22:29:16 +00001211 if (env->macsr & (MACSR_PAV0 << acc)) {
1212 env->macsr |= MACSR_V;
1213 }
1214 if (env->macsr & MACSR_FI) {
1215 val = ((int64_t)val) >> 40;
1216 if (val != 0 && val != -1)
1217 env->macsr |= MACSR_EV;
1218 } else if (env->macsr & MACSR_SU) {
1219 val = ((int64_t)val) >> 32;
1220 if (val != 0 && val != -1)
1221 env->macsr |= MACSR_EV;
1222 } else {
1223 if ((val >> 32) != 0)
1224 env->macsr |= MACSR_EV;
1225 }
1226}
1227
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001228#define EXTSIGN(val, index) ( \
1229 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1230)
Richard Henderson620c6cf2015-08-14 07:59:20 -07001231
1232#define COMPUTE_CCR(op, x, n, z, v, c) { \
1233 switch (op) { \
1234 case CC_OP_FLAGS: \
1235 /* Everything in place. */ \
1236 break; \
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001237 case CC_OP_ADDB: \
1238 case CC_OP_ADDW: \
1239 case CC_OP_ADDL: \
Richard Henderson620c6cf2015-08-14 07:59:20 -07001240 res = n; \
1241 src2 = v; \
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001242 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
Richard Henderson620c6cf2015-08-14 07:59:20 -07001243 c = x; \
1244 z = n; \
1245 v = (res ^ src1) & ~(src1 ^ src2); \
1246 break; \
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001247 case CC_OP_SUBB: \
1248 case CC_OP_SUBW: \
1249 case CC_OP_SUBL: \
Richard Henderson620c6cf2015-08-14 07:59:20 -07001250 res = n; \
1251 src2 = v; \
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001252 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
Richard Henderson620c6cf2015-08-14 07:59:20 -07001253 c = x; \
1254 z = n; \
1255 v = (res ^ src1) & (src1 ^ src2); \
1256 break; \
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001257 case CC_OP_CMPB: \
1258 case CC_OP_CMPW: \
1259 case CC_OP_CMPL: \
Richard Henderson620c6cf2015-08-14 07:59:20 -07001260 src1 = n; \
1261 src2 = v; \
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001262 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
Richard Henderson620c6cf2015-08-14 07:59:20 -07001263 n = res; \
1264 z = res; \
1265 c = src1 < src2; \
1266 v = (res ^ src1) & (src1 ^ src2); \
1267 break; \
1268 case CC_OP_LOGIC: \
1269 c = v = 0; \
1270 z = n; \
1271 break; \
1272 default: \
Richard Hendersona8d92fd2019-03-22 18:23:25 -07001273 cpu_abort(env_cpu(env), "Bad CC_OP %d", op); \
Richard Henderson620c6cf2015-08-14 07:59:20 -07001274 } \
1275} while (0)
1276
1277uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
pbrooke1f38082008-05-24 22:29:16 +00001278{
Richard Henderson620c6cf2015-08-14 07:59:20 -07001279 uint32_t x, c, n, z, v;
1280 uint32_t res, src1, src2;
1281
1282 x = env->cc_x;
Richard Henderson620c6cf2015-08-14 07:59:20 -07001283 n = env->cc_n;
1284 z = env->cc_z;
1285 v = env->cc_v;
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001286 c = env->cc_c;
Richard Henderson620c6cf2015-08-14 07:59:20 -07001287
1288 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1289
1290 n = n >> 31;
Richard Henderson620c6cf2015-08-14 07:59:20 -07001291 z = (z == 0);
Laurent Vivierdb3d7942016-01-16 17:23:50 +01001292 v = v >> 31;
Richard Henderson620c6cf2015-08-14 07:59:20 -07001293
1294 return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1295}
1296
1297uint32_t HELPER(get_ccr)(CPUM68KState *env)
1298{
1299 return cpu_m68k_get_ccr(env);
1300}
1301
1302void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1303{
1304 env->cc_x = (ccr & CCF_X ? 1 : 0);
1305 env->cc_n = (ccr & CCF_N ? -1 : 0);
1306 env->cc_z = (ccr & CCF_Z ? 0 : 1);
1307 env->cc_v = (ccr & CCF_V ? -1 : 0);
1308 env->cc_c = (ccr & CCF_C ? 1 : 0);
1309 env->cc_op = CC_OP_FLAGS;
1310}
1311
1312void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1313{
1314 cpu_m68k_set_ccr(env, ccr);
1315}
1316
1317void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1318{
1319 uint32_t res, src1, src2;
1320
1321 COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1322 env->cc_op = CC_OP_FLAGS;
pbrooke1f38082008-05-24 22:29:16 +00001323}
1324
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001325uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
pbrooke1f38082008-05-24 22:29:16 +00001326{
1327 int rem;
1328 uint32_t result;
1329
1330 if (env->macsr & MACSR_SU) {
1331 /* 16-bit rounding. */
1332 rem = val & 0xffffff;
1333 val = (val >> 24) & 0xffffu;
1334 if (rem > 0x800000)
1335 val++;
1336 else if (rem == 0x800000)
1337 val += (val & 1);
1338 } else if (env->macsr & MACSR_RT) {
1339 /* 32-bit rounding. */
1340 rem = val & 0xff;
1341 val >>= 8;
1342 if (rem > 0x80)
1343 val++;
1344 else if (rem == 0x80)
1345 val += (val & 1);
1346 } else {
1347 /* No rounding. */
1348 val >>= 8;
1349 }
1350 if (env->macsr & MACSR_OMC) {
1351 /* Saturate. */
1352 if (env->macsr & MACSR_SU) {
1353 if (val != (uint16_t) val) {
1354 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1355 } else {
1356 result = val & 0xffff;
1357 }
1358 } else {
1359 if (val != (uint32_t)val) {
1360 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1361 } else {
1362 result = (uint32_t)val;
1363 }
1364 }
1365 } else {
1366 /* No saturation. */
1367 if (env->macsr & MACSR_SU) {
1368 result = val & 0xffff;
1369 } else {
1370 result = (uint32_t)val;
1371 }
1372 }
1373 return result;
1374}
1375
1376uint32_t HELPER(get_macs)(uint64_t val)
1377{
1378 if (val == (int32_t)val) {
1379 return (int32_t)val;
1380 } else {
1381 return (val >> 61) ^ ~SIGNBIT;
1382 }
1383}
1384
1385uint32_t HELPER(get_macu)(uint64_t val)
1386{
1387 if ((val >> 32) == 0) {
1388 return (uint32_t)val;
1389 } else {
1390 return 0xffffffffu;
1391 }
1392}
1393
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001394uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001395{
1396 uint32_t val;
1397 val = env->macc[acc] & 0x00ff;
Paolo Bonzini5ce747c2016-07-15 17:29:22 +02001398 val |= (env->macc[acc] >> 32) & 0xff00;
pbrooke1f38082008-05-24 22:29:16 +00001399 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1400 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1401 return val;
1402}
1403
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001404uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001405{
1406 uint32_t val;
1407 val = (env->macc[acc] >> 32) & 0xffff;
1408 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1409 return val;
1410}
1411
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001412void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001413{
1414 int64_t res;
1415 int32_t tmp;
1416 res = env->macc[acc] & 0xffffffff00ull;
1417 tmp = (int16_t)(val & 0xff00);
1418 res |= ((int64_t)tmp) << 32;
1419 res |= val & 0xff;
1420 env->macc[acc] = res;
1421 res = env->macc[acc + 1] & 0xffffffff00ull;
1422 tmp = (val & 0xff000000);
1423 res |= ((int64_t)tmp) << 16;
1424 res |= (val >> 16) & 0xff;
1425 env->macc[acc + 1] = res;
1426}
1427
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001428void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001429{
1430 int64_t res;
1431 int32_t tmp;
1432 res = (uint32_t)env->macc[acc];
1433 tmp = (int16_t)val;
1434 res |= ((int64_t)tmp) << 32;
1435 env->macc[acc] = res;
1436 res = (uint32_t)env->macc[acc + 1];
1437 tmp = val & 0xffff0000;
1438 res |= (int64_t)tmp << 16;
1439 env->macc[acc + 1] = res;
1440}
1441
Andreas Färber2b3e3cf2012-03-14 01:38:22 +01001442void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +00001443{
1444 uint64_t res;
1445 res = (uint32_t)env->macc[acc];
1446 res |= ((uint64_t)(val & 0xffff)) << 32;
1447 env->macc[acc] = res;
1448 res = (uint32_t)env->macc[acc + 1];
1449 res |= (uint64_t)(val & 0xffff0000) << 16;
1450 env->macc[acc + 1] = res;
1451}
Laurent Vivier0bdb2b32018-01-04 02:29:07 +01001452
Philippe Mathieu-Daudé6a140582023-06-13 15:33:41 +02001453#if !defined(CONFIG_USER_ONLY)
Laurent Viviere55886c2018-01-18 20:38:45 +01001454void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1455{
Laurent Viviere55886c2018-01-18 20:38:45 +01001456 hwaddr physical;
1457 int access_type;
1458 int prot;
1459 int ret;
1460 target_ulong page_size;
1461
1462 access_type = ACCESS_PTEST;
1463 if (env->dfc & 4) {
1464 access_type |= ACCESS_SUPER;
1465 }
1466 if ((env->dfc & 3) == 2) {
1467 access_type |= ACCESS_CODE;
1468 }
1469 if (!is_read) {
1470 access_type |= ACCESS_STORE;
1471 }
1472
1473 env->mmu.mmusr = 0;
1474 env->mmu.ssw = 0;
1475 ret = get_physical_address(env, &physical, &prot, addr,
1476 access_type, &page_size);
1477 if (ret == 0) {
Mark Cave-Ayland852002b2020-07-01 21:15:31 +01001478 tlb_set_page(env_cpu(env), addr & TARGET_PAGE_MASK,
1479 physical & TARGET_PAGE_MASK,
Laurent Viviere55886c2018-01-18 20:38:45 +01001480 prot, access_type & ACCESS_SUPER ?
1481 MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1482 }
1483}
1484
1485void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1486{
Richard Hendersona8d92fd2019-03-22 18:23:25 -07001487 CPUState *cs = env_cpu(env);
Laurent Viviere55886c2018-01-18 20:38:45 +01001488
1489 switch (opmode) {
1490 case 0: /* Flush page entry if not global */
1491 case 1: /* Flush page entry */
Richard Hendersona8d92fd2019-03-22 18:23:25 -07001492 tlb_flush_page(cs, addr);
Laurent Viviere55886c2018-01-18 20:38:45 +01001493 break;
1494 case 2: /* Flush all except global entries */
Richard Hendersona8d92fd2019-03-22 18:23:25 -07001495 tlb_flush(cs);
Laurent Viviere55886c2018-01-18 20:38:45 +01001496 break;
1497 case 3: /* Flush all entries */
Richard Hendersona8d92fd2019-03-22 18:23:25 -07001498 tlb_flush(cs);
Laurent Viviere55886c2018-01-18 20:38:45 +01001499 break;
1500 }
1501}
1502
Laurent Vivier0bdb2b32018-01-04 02:29:07 +01001503void HELPER(reset)(CPUM68KState *env)
1504{
1505 /* FIXME: reset all except CPU */
1506}
Philippe Mathieu-Daudé6a140582023-06-13 15:33:41 +02001507#endif /* !CONFIG_USER_ONLY */