Revision | 6db1bc8e2ccef9bb8f9831cbd36674e404e845f7 (tree) |
---|---|
Time | 2019-01-01 23:53:15 |
Author | Yoshinori Sato <ysato@user...> |
Commiter | Yoshinori Sato |
Add ms7619se support.
@@ -7020,7 +7020,7 @@ target_name=$(echo $target | cut -d '-' -f 1) | ||
7020 | 7020 | target_bigendian="no" |
7021 | 7021 | |
7022 | 7022 | case "$target_name" in |
7023 | - armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) | |
7023 | + armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppc64|ppc64abi32|s390x|sh2|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) | |
7024 | 7024 | target_bigendian=yes |
7025 | 7025 | ;; |
7026 | 7026 | esac |
@@ -7185,6 +7185,11 @@ case "$target_name" in | ||
7185 | 7185 | mttcg=yes |
7186 | 7186 | target_compiler=$cross_cc_riscv64 |
7187 | 7187 | ;; |
7188 | + sh2) | |
7189 | + TARGET_ARCH=sh4 | |
7190 | + bflt="yes" | |
7191 | + target_compiler=$cross_cc_sh4 | |
7192 | + ;; | |
7188 | 7193 | sh4|sh4eb) |
7189 | 7194 | TARGET_ARCH=sh4 |
7190 | 7195 | bflt="yes" |
@@ -7408,7 +7413,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do | ||
7408 | 7413 | s390*) |
7409 | 7414 | disas_config "S390" |
7410 | 7415 | ;; |
7411 | - sh4) | |
7416 | + sh*) | |
7412 | 7417 | disas_config "SH4" |
7413 | 7418 | ;; |
7414 | 7419 | sparc*) |
@@ -0,0 +1,22 @@ | ||
1 | +# Default configuration for sh2-softmmu | |
2 | + | |
3 | +include pci.mak | |
4 | +include usb.mak | |
5 | +CONFIG_SERIAL=y | |
6 | +CONFIG_SERIAL_ISA=y | |
7 | +CONFIG_PTIMER=y | |
8 | +CONFIG_PFLASH_CFI02=y | |
9 | +CONFIG_SH4=y | |
10 | +CONFIG_IDE_MMIO=y | |
11 | +CONFIG_SM501=y | |
12 | +CONFIG_I2C=y | |
13 | +CONFIG_DDC=y | |
14 | +CONFIG_ISA_TESTDEV=y | |
15 | +CONFIG_I82378=y | |
16 | +CONFIG_I8259=y | |
17 | +CONFIG_I8254=y | |
18 | +CONFIG_PCSPK=y | |
19 | +CONFIG_I82374=y | |
20 | +CONFIG_I8257=y | |
21 | +CONFIG_MC146818RTC=y | |
22 | +CONFIG_RENESAS_CMT=y |
@@ -401,16 +401,21 @@ void sh_serial_init(MemoryRegion *sysmem, | ||
401 | 401 | |
402 | 402 | sh_serial_clear_fifo(s); |
403 | 403 | |
404 | - memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s, | |
405 | - "serial", 0x100000000ULL); | |
406 | - | |
407 | - memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem, | |
408 | - 0, 0x28); | |
409 | - memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); | |
410 | - | |
411 | - memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem, | |
412 | - 0, 0x28); | |
413 | - memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); | |
404 | + if (base < 0xf0000000) { | |
405 | + memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s, | |
406 | + "serial", 0x100000000ULL); | |
407 | + | |
408 | + memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem, | |
409 | + 0, 0x28); | |
410 | + memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); | |
411 | + memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem, | |
412 | + 0, 0x28); | |
413 | + memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); | |
414 | + } else { | |
415 | + memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s, | |
416 | + "serial", 0x10000); | |
417 | + memory_region_add_subregion(sysmem, base, &s->iomem); | |
418 | + } | |
414 | 419 | |
415 | 420 | if (chr) { |
416 | 421 | qemu_chr_fe_init(&s->chr, chr, &error_abort); |
@@ -33,7 +33,7 @@ obj-$(CONFIG_IOAPIC) += ioapic.o | ||
33 | 33 | obj-$(CONFIG_OMAP) += omap_intc.o |
34 | 34 | obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o |
35 | 35 | obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o |
36 | -obj-$(CONFIG_SH4) += sh_intc.o | |
36 | +obj-$(CONFIG_SH4) += sh_intc.o sh7619_intc.o | |
37 | 37 | obj-$(CONFIG_XICS) += xics.o |
38 | 38 | obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o |
39 | 39 | obj-$(CONFIG_XICS_KVM) += xics_kvm.o |
@@ -0,0 +1,351 @@ | ||
1 | +/* | |
2 | + * SH7619 Interrupt controller | |
3 | + * | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | + * | |
6 | + * This code is licensed under the GPL. | |
7 | + */ | |
8 | + | |
9 | +#include "qemu/osdep.h" | |
10 | +#include "qemu-common.h" | |
11 | +#include "cpu.h" | |
12 | +#include "hw/hw.h" | |
13 | +#include "hw/sysbus.h" | |
14 | +#include "hw/sh4/sh_intc.h" | |
15 | +#include "hw/intc/sh7619intc.h" | |
16 | +#include "qemu/error-report.h" | |
17 | + | |
18 | +static void sh7619intc_set_irq(void *opaque, int n_IRQ, int level) | |
19 | +{ | |
20 | + SH7619INTCState *intc = opaque; | |
21 | + struct IRQSource *src; | |
22 | + int issue = 0; | |
23 | + | |
24 | + n_IRQ += 64; | |
25 | + if (n_IRQ < 64 || n_IRQ >= 128) { | |
26 | + error_report("%s: IRQ %d out of range", __func__, n_IRQ); | |
27 | + return; | |
28 | + } | |
29 | + | |
30 | + src = &intc->src[n_IRQ - 64]; | |
31 | + | |
32 | + level = (level != 0); | |
33 | + if (n_IRQ >= 64 && n_IRQ <= 71) { | |
34 | + if (level) | |
35 | + intc->irqsr |= (0x100 << (n_IRQ - 64)); | |
36 | + else | |
37 | + intc->irqsr &= ~(0x100 << (n_IRQ - 64)); | |
38 | + } | |
39 | + switch (src->sense) { | |
40 | + case TRG_LEVEL: | |
41 | + /* level-sensitive irq */ | |
42 | + issue = (level == 0); | |
43 | + break; | |
44 | + case TRG_NEDGE: | |
45 | + issue = (level == 0 && src->level == 1); | |
46 | + break; | |
47 | + case TRG_PEDGE: | |
48 | + issue = (level == 1 && src->level == 0); | |
49 | + break; | |
50 | + case TRG_BEDGE: | |
51 | + issue = ((level ^ src->level) & 1); | |
52 | + break; | |
53 | + } | |
54 | + src->level = level; | |
55 | + if (issue == 0 && src->sense == TRG_LEVEL) { | |
56 | + if (n_IRQ >= 64 && n_IRQ <= 71) | |
57 | + intc->irqsr &= ~(1 << (n_IRQ - 64)); | |
58 | + if (intc->req_irq == n_IRQ) { | |
59 | + qemu_set_irq(intc->irq, 0); | |
60 | + src->req = 0; | |
61 | + intc->req_irq = -1; | |
62 | + } | |
63 | + return; | |
64 | + } | |
65 | + if (issue) { | |
66 | + if (n_IRQ >= 64 && n_IRQ <= 71) | |
67 | + intc->irqsr |= (1 << (n_IRQ - 64)); | |
68 | + src->req = 1; | |
69 | + if(intc->req_irq < 0) { | |
70 | + qemu_set_irq(intc->irq, 1); | |
71 | + intc->req_irq = n_IRQ; | |
72 | + } | |
73 | + } | |
74 | +} | |
75 | + | |
76 | +static int priority(SH7619INTCState *intc, int req) | |
77 | +{ | |
78 | + static const int map[] = { | |
79 | + 3, 2, 1, 0, -1, -1, -1, -1, | |
80 | + -1, -1, -1, -1, -1, -1, -1, -1, | |
81 | + 7, 6, 5, 4, 11, 10, 9, 8, | |
82 | + 15, 15, 15, 15, 14, 14, 14, 14, | |
83 | + 13, 13, 13, 13, 19, 18, -1, -1, | |
84 | + 23, 22, 21, 20, 27, -1, -1, -1, | |
85 | + -1, -1, -1, -1, -1, -1, -1, -1, | |
86 | + -1, -1, -1, -1, -1, -1, -1, -1, | |
87 | + }; | |
88 | + int offset; | |
89 | + int pos; | |
90 | + offset = map[req - 64] / 4; | |
91 | + pos = map[req - 64] % 4; | |
92 | + return (intc->ipr[offset] >> pos) & 0x000f; | |
93 | +} | |
94 | + | |
95 | +int sh2_intc_get_pending_vector(void *state, int imask, int *level) | |
96 | +{ | |
97 | + SH7619INTCState *intc = SH7619INTC(state); | |
98 | + int pri = priority(intc, intc->req_irq); | |
99 | + int ret = -1; | |
100 | + int i; | |
101 | + int pend; | |
102 | + | |
103 | + if (pri > imask) { | |
104 | + *level = pri; | |
105 | + ret = intc->req_irq; | |
106 | + intc->src[intc->req_irq - 64].req = 0; | |
107 | + intc->req_irq = -1; | |
108 | + } | |
109 | + pri = -1; | |
110 | + pend = -1; | |
111 | + for (i = 0; i < 64; i++) { | |
112 | + if (intc->src[i].req && pri < priority(intc, i + 64)) { | |
113 | + pri = priority(intc, i + 64); | |
114 | + pend = i + 64; | |
115 | + } | |
116 | + } | |
117 | + if (pend >= 0) { | |
118 | + qemu_set_irq(intc->irq, 1); | |
119 | + intc->req_irq = pend; | |
120 | + } | |
121 | + return ret; | |
122 | +} | |
123 | + | |
124 | +static void intc_write1(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
125 | +{ | |
126 | + int reg = (addr & 0x0f) >> 1; | |
127 | + SH7619INTCState *intc = SH7619INTC(opaque); | |
128 | + | |
129 | + if (reg < 5) | |
130 | + intc->ipr[reg + 2] = val; | |
131 | + else | |
132 | + error_report("sh7619intc: unsupported write request at %08lx", addr); | |
133 | +} | |
134 | + | |
135 | +static uint64_t intc_read1(void *opaque, hwaddr addr, unsigned size) | |
136 | +{ | |
137 | + int reg = (addr & 0x0f) >> 1; | |
138 | + SH7619INTCState *intc = SH7619INTC(opaque); | |
139 | + | |
140 | + if (reg < 5) | |
141 | + return intc->ipr[reg + 2]; | |
142 | + else { | |
143 | + error_report("sh7619intc: unsupported write request at %08lx", addr); | |
144 | + return 0; | |
145 | + } | |
146 | +} | |
147 | + | |
148 | +static void update_byte(unsigned int *word, uint64_t val, int pos) | |
149 | +{ | |
150 | + *word &= 0xff << (pos * 8); | |
151 | + *word |= (val & 0xff) << ((1 - pos) * 8); | |
152 | +} | |
153 | + | |
154 | +static void write_irqsr(SH7619INTCState *intc, uint64_t val) | |
155 | +{ | |
156 | + int mask = ~intc->read_sr; | |
157 | + intc->irqsr &= mask; | |
158 | + intc->irqsr |= val & 0xff; | |
159 | +} | |
160 | + | |
161 | +static void update_trigger(SH7619INTCState *intc) | |
162 | +{ | |
163 | + int i; | |
164 | + for (i = 0; i < 8; i++) { | |
165 | + intc->src[i].sense = (intc->irqcr >> (i * 2)) & 3; | |
166 | + } | |
167 | +} | |
168 | + | |
169 | +static void intc_write2(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
170 | +{ | |
171 | + SH7619INTCState *intc = SH7619INTC(opaque); | |
172 | + int error = 0; | |
173 | + | |
174 | + if (size == 2) { | |
175 | + switch (addr & 0x0f) { | |
176 | + case 0: /* ICR0 */ | |
177 | + intc->icr0 &= ~0x80; | |
178 | + intc->icr0 |= val & 0x80; | |
179 | + break; | |
180 | + case 2: /* IRQCR */ | |
181 | + intc->irqcr = val; | |
182 | + update_trigger(intc); | |
183 | + break; | |
184 | + case 4: | |
185 | + write_irqsr(intc, val); | |
186 | + break; | |
187 | + case 6: /* IPR */ | |
188 | + case 8: | |
189 | + intc->ipr[((addr & 0x0f) - 8) / 2] = val; | |
190 | + break; | |
191 | + default: | |
192 | + error=1; | |
193 | + break; | |
194 | + } | |
195 | + } else { | |
196 | + switch (addr & 0x0f) { | |
197 | + case 1: /* ICR0 */ | |
198 | + intc->icr0 &= ~0x80; | |
199 | + intc->icr0 |= val & 0x80; | |
200 | + break; | |
201 | + case 2 ... 3: /* IRQCR */ | |
202 | + update_byte(&intc->irqcr, val, addr & 1); | |
203 | + update_trigger(intc); | |
204 | + break; | |
205 | + case 5: /* IRQSR */ | |
206 | + write_irqsr(intc, val); | |
207 | + break; | |
208 | + case 6 ... 9: /* IPR */ | |
209 | + update_byte(&intc->ipr[((addr & 0x0f) - 8) / 2], val, addr & 1); | |
210 | + break; | |
211 | + default: | |
212 | + error = 1; | |
213 | + } | |
214 | + } | |
215 | + if (error) | |
216 | + error_report("sh7619intc: unsupported write request at %08lx", addr); | |
217 | +} | |
218 | + | |
219 | +static unsigned int read_byte(unsigned int val, int pos) | |
220 | +{ | |
221 | + return (val >> ((1 - pos) * 8)) & 0xff; | |
222 | +} | |
223 | + | |
224 | +static uint64_t intc_read2(void *opaque, hwaddr addr, unsigned size) | |
225 | +{ | |
226 | + SH7619INTCState *intc = SH7619INTC(opaque); | |
227 | + int error = 0; | |
228 | + | |
229 | + if (size == 2) { | |
230 | + switch (addr & 0x0f) { | |
231 | + case 0: /* ICR0 */ | |
232 | + return intc->icr0; | |
233 | + break; | |
234 | + case 2: /* IRQCR */ | |
235 | + return intc->irqcr; | |
236 | + break; | |
237 | + case 4: /* IRQSR */ | |
238 | + intc->read_sr = intc->irqsr & 0xff; | |
239 | + return intc->irqsr; | |
240 | + break; | |
241 | + case 6: /* IPR */ | |
242 | + case 8: | |
243 | + return intc->ipr[((addr & 0x0f) - 8) / 2]; | |
244 | + break; | |
245 | + default: | |
246 | + error=1; | |
247 | + break; | |
248 | + } | |
249 | + } else { | |
250 | + switch (addr & 0x0f) { | |
251 | + case 0 ... 1: /* ICR0 */ | |
252 | + return read_byte(intc->icr0, addr & 1); | |
253 | + break; | |
254 | + case 2 ... 3: /* IRQCR */ | |
255 | + return read_byte(intc->irqcr, addr & 1); | |
256 | + break; | |
257 | + case 4 ... 5: /* IRQCR */ | |
258 | + if (addr & 1) | |
259 | + intc->read_sr = intc->irqsr & 0xff; | |
260 | + return read_byte(intc->irqsr, addr & 1); | |
261 | + break; | |
262 | + case 6 ... 9: /* IPR */ | |
263 | + return read_byte(intc->ipr[((addr & 0x0f) - 8) / 2], addr & 1); | |
264 | + break; | |
265 | + default: | |
266 | + error = 1; | |
267 | + } | |
268 | + } | |
269 | + if (error) | |
270 | + error_report("sh7619intc: unsupported write request at %08lx", addr); | |
271 | + return -1; | |
272 | +} | |
273 | + | |
274 | +static const MemoryRegionOps intc_ops1 = { | |
275 | + .write = intc_write1, | |
276 | + .read = intc_read1, | |
277 | + .endianness = DEVICE_BIG_ENDIAN, | |
278 | + .impl = { | |
279 | + .min_access_size = 2, | |
280 | + .max_access_size = 2, | |
281 | + }, | |
282 | +}; | |
283 | + | |
284 | +static const MemoryRegionOps intc_ops2 = { | |
285 | + .write = intc_write2, | |
286 | + .read = intc_read2, | |
287 | + .endianness = DEVICE_BIG_ENDIAN, | |
288 | + .impl = { | |
289 | + .min_access_size = 1, | |
290 | + .max_access_size = 2, | |
291 | + }, | |
292 | +}; | |
293 | + | |
294 | +static void sh7619intc_realize(DeviceState *dev, Error **errp) | |
295 | +{ | |
296 | + SH7619INTCState *intc = SH7619INTC(dev); | |
297 | + int i; | |
298 | + | |
299 | + for (i = 0; i < 64; i++) { | |
300 | + intc->src[i].sense = TRG_PEDGE; | |
301 | + } | |
302 | + intc->req_irq = -1; | |
303 | +} | |
304 | + | |
305 | +static void sh7619intc_init(Object *obj) | |
306 | +{ | |
307 | + SysBusDevice *d = SYS_BUS_DEVICE(obj); | |
308 | + SH7619INTCState *intc = SH7619INTC(obj); | |
309 | + | |
310 | + memory_region_init_io(&intc->memory[0], OBJECT(intc), &intc_ops1, | |
311 | + intc, "sh7619-intc-1", 0x10); | |
312 | + memory_region_init_io(&intc->memory[1], OBJECT(intc), &intc_ops2, | |
313 | + intc, "sh7619-intc-2", 0x10); | |
314 | + sysbus_init_mmio(d, &intc->memory[0]); | |
315 | + sysbus_init_mmio(d, &intc->memory[1]); | |
316 | + | |
317 | + qdev_init_gpio_in(DEVICE(d), sh7619intc_set_irq, 64); | |
318 | + sysbus_init_irq(d, &intc->irq); | |
319 | +} | |
320 | + | |
321 | +static const VMStateDescription vmstate_sh7619intc = { | |
322 | + .name = "sh7619-intc", | |
323 | + .version_id = 1, | |
324 | + .minimum_version_id = 1, | |
325 | + .fields = (VMStateField[]) { | |
326 | + VMSTATE_END_OF_LIST() | |
327 | + } | |
328 | +}; | |
329 | + | |
330 | +static void sh7619intc_class_init(ObjectClass *klass, void *data) | |
331 | +{ | |
332 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
333 | + | |
334 | + dc->realize = sh7619intc_realize; | |
335 | + dc->vmsd = &vmstate_sh7619intc; | |
336 | +} | |
337 | + | |
338 | +static const TypeInfo sh7619intc_info = { | |
339 | + .name = TYPE_SH7619INTC, | |
340 | + .parent = TYPE_SYS_BUS_DEVICE, | |
341 | + .instance_size = sizeof(SH7619INTCState), | |
342 | + .instance_init = sh7619intc_init, | |
343 | + .class_init = sh7619intc_class_init, | |
344 | +}; | |
345 | + | |
346 | +static void sh7619intc_register_types(void) | |
347 | +{ | |
348 | + type_register_static(&sh7619intc_info); | |
349 | +} | |
350 | + | |
351 | +type_init(sh7619intc_register_types) |
@@ -1,4 +1,5 @@ | ||
1 | -obj-y += shix.o r2d.o | |
1 | +obj-y += shix.o r2d.o ms7619se.o | |
2 | 2 | |
3 | 3 | obj-y += sh7750.o sh7750_regnames.o |
4 | 4 | obj-y += sh_pci.o |
5 | +obj-y += sh7619.o | |
\ No newline at end of file |
@@ -0,0 +1,157 @@ | ||
1 | +/* | |
2 | + * SolutionEngine MS7619SE emulation | |
3 | + * | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
23 | + */ | |
24 | + | |
25 | +#include "qemu/osdep.h" | |
26 | +#include "qemu/units.h" | |
27 | +#include "qapi/error.h" | |
28 | +#include "qemu-common.h" | |
29 | +#include "cpu.h" | |
30 | +#include "hw/hw.h" | |
31 | +#include "hw/sysbus.h" | |
32 | +#include "hw/loader.h" | |
33 | +#include "hw/sh4/sh7619.h" | |
34 | +#include "sysemu/sysemu.h" | |
35 | +#include "sysemu/qtest.h" | |
36 | +#include "sysemu/device_tree.h" | |
37 | +#include "hw/boards.h" | |
38 | +#include "hw/block/flash.h" | |
39 | +#include "exec/address-spaces.h" | |
40 | +#include "exec/cpu-all.h" | |
41 | + | |
42 | +#define FLASH_BASE 0x00000000 | |
43 | +#define FLASH_SIZE 0x02000000 | |
44 | + | |
45 | +#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ | |
46 | +#define SDRAM_SIZE 0x04000000 | |
47 | + | |
48 | +#define BOOT_PARAMS_OFFSET 0x0001000 | |
49 | +/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */ | |
50 | +#define LINUX_LOAD_OFFSET 0x0800000 | |
51 | +#define INITRD_LOAD_OFFSET 0x1800000 | |
52 | + | |
53 | +static struct QEMU_PACKED | |
54 | +{ | |
55 | + int mount_root_rdonly; | |
56 | + int ramdisk_flags; | |
57 | + int orig_root_dev; | |
58 | + int loader_type; | |
59 | + int initrd_start; | |
60 | + int initrd_size; | |
61 | + | |
62 | + char pad[232]; | |
63 | + | |
64 | + char kernel_cmdline[256]; | |
65 | +} boot_params; | |
66 | + | |
67 | +static void ms7619se_init(MachineState *machine) | |
68 | +{ | |
69 | + SuperHCPU *cpu; | |
70 | + SH7619State *s; | |
71 | + MemoryRegion *sysmem = get_system_memory(); | |
72 | + MemoryRegion *sdram = g_new(MemoryRegion, 1); | |
73 | + DriveInfo *dinfo; | |
74 | + const char *kernel_filename = machine->kernel_filename; | |
75 | + const char *kernel_cmdline = machine->kernel_cmdline; | |
76 | + const char *initrd_filename = machine->initrd_filename; | |
77 | + | |
78 | + /* Allocate memory space */ | |
79 | + memory_region_init_ram(sdram, NULL, "ms7619se.sdram", 0x04000000, | |
80 | + &error_fatal); | |
81 | + memory_region_add_subregion(sysmem, 0x0c000000, sdram); | |
82 | + dinfo = drive_get(IF_PFLASH, 0, 0); | |
83 | + pflash_cfi02_register(0x0, NULL, "ms7619se.flash", FLASH_SIZE, | |
84 | + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, | |
85 | + 16 * KiB, FLASH_SIZE >> 16, | |
86 | + 1, 4, 0x0000, 0x0000, 0x0000, 0x0000, | |
87 | + 0x555, 0x2aa, 0); | |
88 | + | |
89 | + cpu = SUPERH_CPU(cpu_create(machine->cpu_type)); | |
90 | + s = sh7619_init(cpu, sysmem); | |
91 | + | |
92 | + memset(&boot_params, 0, sizeof(boot_params)); | |
93 | + | |
94 | + if (kernel_filename) { | |
95 | + int kernel_size; | |
96 | + | |
97 | + kernel_size = load_image_targphys(kernel_filename, | |
98 | + SDRAM_BASE + LINUX_LOAD_OFFSET, | |
99 | + INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); | |
100 | + if (kernel_size < 0) { | |
101 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); | |
102 | + exit(1); | |
103 | + } | |
104 | + cpu->env.pc = 0x80000000 + SDRAM_BASE + LINUX_LOAD_OFFSET; | |
105 | + s->frqcr = 0x1103; | |
106 | + } | |
107 | + | |
108 | + if (initrd_filename) { | |
109 | + int initrd_size; | |
110 | + | |
111 | + initrd_size = load_image_targphys(initrd_filename, | |
112 | + SDRAM_BASE + INITRD_LOAD_OFFSET, | |
113 | + SDRAM_SIZE - INITRD_LOAD_OFFSET); | |
114 | + | |
115 | + if (initrd_size < 0) { | |
116 | + fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename); | |
117 | + exit(1); | |
118 | + } | |
119 | + | |
120 | + /* initialization which should be done by firmware */ | |
121 | + boot_params.loader_type = tswap32(1); | |
122 | + boot_params.initrd_start = tswap32(INITRD_LOAD_OFFSET); | |
123 | + boot_params.initrd_size = tswap32(initrd_size); | |
124 | + } | |
125 | + | |
126 | + if (kernel_cmdline) { | |
127 | + /* I see no evidence that this .kernel_cmdline buffer requires | |
128 | + NUL-termination, so using strncpy should be ok. */ | |
129 | + strncpy(boot_params.kernel_cmdline, kernel_cmdline, | |
130 | + sizeof(boot_params.kernel_cmdline)); | |
131 | + } | |
132 | + | |
133 | + rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params), | |
134 | + SDRAM_BASE + BOOT_PARAMS_OFFSET); | |
135 | +} | |
136 | + | |
137 | +static void ms7619se_class_init(ObjectClass *oc, void *data) | |
138 | +{ | |
139 | + MachineClass *mc = MACHINE_CLASS(oc); | |
140 | + | |
141 | + mc->desc = "MS7619SE"; | |
142 | + mc->init = ms7619se_init; | |
143 | + mc->default_cpu_type = TYPE_SH7619_CPU; | |
144 | +} | |
145 | + | |
146 | +static const TypeInfo ms7619se_type = { | |
147 | + .name = MACHINE_TYPE_NAME("ms7619se"), | |
148 | + .parent = TYPE_MACHINE, | |
149 | + .class_init = ms7619se_class_init, | |
150 | +}; | |
151 | + | |
152 | +static void ms7619se_machine_init(void) | |
153 | +{ | |
154 | + type_register_static(&ms7619se_type); | |
155 | +} | |
156 | + | |
157 | +type_init(ms7619se_machine_init) |
@@ -0,0 +1,171 @@ | ||
1 | +/* | |
2 | + * SH7619 device | |
3 | + * | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
23 | + */ | |
24 | +#include "qemu/osdep.h" | |
25 | +#include "qapi/error.h" | |
26 | +#include "hw/hw.h" | |
27 | +#include "hw/sh4/sh7619.h" | |
28 | +#include "sysemu/sysemu.h" | |
29 | +#include "hw/loader.h" | |
30 | +#include "hw/intc/sh7619intc.h" | |
31 | +#include "hw/timer/renesas_cmt.h" | |
32 | +#include "cpu.h" | |
33 | +#include "exec/exec-all.h" | |
34 | + | |
35 | +#define SCIF0_ERI (88 - 64) | |
36 | +#define SCIF0_RXI (89 - 64) | |
37 | +#define SCIF0_BRI (90 - 64) | |
38 | +#define SCIF0_TXI (91 - 64) | |
39 | +#define SCIF1_ERI (92 - 64) | |
40 | +#define SCIF1_RXI (93 - 64) | |
41 | +#define SCIF1_BRI (94 - 64) | |
42 | +#define SCIF1_TXI (95 - 64) | |
43 | +#define SCIF2_ERI (96 - 64) | |
44 | +#define SCIF2_RXI (97 - 64) | |
45 | +#define SCIF2_BRI (98 - 64) | |
46 | +#define SCIF2_TXI (99 - 64) | |
47 | + | |
48 | +static void sh7619_set_irq(void *opaque, int no, int request) | |
49 | +{ | |
50 | + SuperHCPU *cpu = SUPERH_CPU(opaque); | |
51 | + CPUState *cs = CPU(cpu); | |
52 | + if (request) | |
53 | + cpu_interrupt(cs, CPU_INTERRUPT_HARD); | |
54 | + else | |
55 | + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); | |
56 | +} | |
57 | + | |
58 | +static SH7619INTCState *register_intc(SH7619State *s) | |
59 | +{ | |
60 | + SysBusDevice *intc; | |
61 | + int i; | |
62 | + | |
63 | + intc = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_SH7619INTC)); | |
64 | + sysbus_mmio_map(intc, 0, 0xf8080000); | |
65 | + sysbus_mmio_map(intc, 1, 0xf8140000); | |
66 | + for (i = 0; i < 64; i++) | |
67 | + s->irq[i] = qdev_get_gpio_in(DEVICE(intc), i); | |
68 | + | |
69 | + qdev_init_nofail(DEVICE(intc)); | |
70 | + sysbus_connect_irq(SYS_BUS_DEVICE(intc), 0, | |
71 | + qdev_get_gpio_in(DEVICE(s->cpu), 0)); | |
72 | + | |
73 | + return SH7619INTC(intc); | |
74 | +} | |
75 | + | |
76 | +static RCMTState *register_cmt(SH7619State *s) | |
77 | +{ | |
78 | + SysBusDevice *cmt; | |
79 | + int i; | |
80 | + | |
81 | + cmt = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_RCMT)); | |
82 | + sysbus_mmio_map(cmt, 0, 0xf84a0070); | |
83 | + qdev_prop_set_uint64(DEVICE(cmt), "input-freq", 31250000); | |
84 | + | |
85 | + qdev_init_nofail(DEVICE(cmt)); | |
86 | + for (i = 0; i < 2; i++) | |
87 | + sysbus_connect_irq(cmt, i, s->irq[(86 + i) - 64]); | |
88 | + | |
89 | + return RCMT(cmt); | |
90 | +} | |
91 | + | |
92 | +static void cache_write(void *opaque, hwaddr addr, | |
93 | + uint64_t mem_value, unsigned size) | |
94 | +{ | |
95 | +} | |
96 | + | |
97 | +static uint64_t cache_read(void *opaque, hwaddr addr, | |
98 | + unsigned size) | |
99 | +{ | |
100 | + return 0; | |
101 | +} | |
102 | + | |
103 | + | |
104 | +static const MemoryRegionOps cache_ops = { | |
105 | + .read = cache_read, | |
106 | + .write = cache_write, | |
107 | + .endianness = DEVICE_BIG_ENDIAN, | |
108 | +}; | |
109 | + | |
110 | +static void cpg_write(void *opaque, hwaddr addr, | |
111 | + uint64_t mem_value, unsigned size) | |
112 | +{ | |
113 | + SH7619State *s = opaque; | |
114 | + s->frqcr = mem_value; | |
115 | +} | |
116 | + | |
117 | +static uint64_t cpg_read(void *opaque, hwaddr addr, | |
118 | + unsigned size) | |
119 | +{ | |
120 | + SH7619State *s = opaque; | |
121 | + return s->frqcr; | |
122 | +} | |
123 | + | |
124 | + | |
125 | +static const MemoryRegionOps cpg_ops = { | |
126 | + .read = cpg_read, | |
127 | + .write = cpg_write, | |
128 | + .endianness = DEVICE_BIG_ENDIAN, | |
129 | + .impl = { | |
130 | + .min_access_size = 2, | |
131 | + .max_access_size = 2, | |
132 | + }, | |
133 | +}; | |
134 | + | |
135 | +#define SCIF(no) \ | |
136 | + sh_serial_init(s->sysmem, 0xf8400000 + no * 0x00010000, \ | |
137 | + SH_SERIAL_FEAT_SCIF, \ | |
138 | + 31250000, serial_hd(no), \ | |
139 | + s->irq[SCIF ## no ## _ERI], \ | |
140 | + s->irq[SCIF ## no ## _RXI], \ | |
141 | + s->irq[SCIF ## no ## _TXI], \ | |
142 | + NULL, \ | |
143 | + s->irq[SCIF ## no ## _BRI]) | |
144 | + | |
145 | +SH7619State *sh7619_init(SuperHCPU *cpu, MemoryRegion *sysmem) | |
146 | +{ | |
147 | + SH7619State *s; | |
148 | + | |
149 | + s = g_malloc0(sizeof(SH7619State)); | |
150 | + s->cpu = cpu; | |
151 | + s->sysmem = sysmem; | |
152 | + | |
153 | + memory_region_init_io(&s->cache, NULL, &cache_ops, | |
154 | + NULL, "cache", 0x02000000); | |
155 | + memory_region_add_subregion(s->sysmem, 0xf0000000, &s->cache); | |
156 | + memory_region_init_io(&s->cpg, NULL, &cpg_ops, | |
157 | + s, "cpg", 0x00000002); | |
158 | + memory_region_add_subregion(s->sysmem, 0xf815ff80, &s->cpg); | |
159 | + memory_region_init_ram(&s->uram, NULL, "uram", 0x4000, NULL); | |
160 | + memory_region_add_subregion(s->sysmem, 0xe55fc000, &s->uram); | |
161 | + | |
162 | + qdev_init_gpio_in(DEVICE(cpu), sh7619_set_irq, 1); | |
163 | + s->intc = register_intc(s); | |
164 | + s->cpu->env.intc_handle = s->intc; | |
165 | + register_cmt(s); | |
166 | + SCIF(0); | |
167 | + SCIF(1); | |
168 | + SCIF(2); | |
169 | + | |
170 | + return s; | |
171 | +} |
@@ -32,6 +32,7 @@ obj-$(CONFIG_OMAP) += omap_gptimer.o | ||
32 | 32 | obj-$(CONFIG_OMAP) += omap_synctimer.o |
33 | 33 | obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o |
34 | 34 | obj-$(CONFIG_SH4) += sh_timer.o |
35 | +obj-$(CONFIG_RENESAS_CMT) += renesas_cmt.o | |
35 | 36 | obj-$(CONFIG_DIGIC) += digic-timer.o |
36 | 37 | obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o |
37 | 38 |
@@ -0,0 +1,218 @@ | ||
1 | +/* | |
2 | + * Renesas Compare-match timer | |
3 | + * | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | + * | |
6 | + * This code is licensed under the GPL version 2 or later. | |
7 | + * | |
8 | + */ | |
9 | + | |
10 | +#include "qemu/osdep.h" | |
11 | +#include "qemu-common.h" | |
12 | +#include "qemu/timer.h" | |
13 | +#include "cpu.h" | |
14 | +#include "hw/hw.h" | |
15 | +#include "hw/sysbus.h" | |
16 | +#include "hw/timer/renesas_cmt.h" | |
17 | +#include "qemu/error-report.h" | |
18 | + | |
19 | +#define freq_to_ns(freq) (1000000000LL / freq) | |
20 | +static const int clkdiv[] = {8,32,128,512}; | |
21 | + | |
22 | +static void update_events(RCMTState *cmt, int ch) | |
23 | +{ | |
24 | + uint16_t diff; | |
25 | + | |
26 | + if ((cmt->cmstr & (1 << ch))== 0) | |
27 | + return ; | |
28 | + diff = cmt->cmcor[ch] - cmt->cmcnt[ch]; | |
29 | + timer_mod(cmt->timer[ch], | |
30 | + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + | |
31 | + diff * freq_to_ns(cmt->input_freq) * | |
32 | + clkdiv[cmt->cmcr[ch] & 3]); | |
33 | +} | |
34 | + | |
35 | +static uint64_t read_cmcnt(RCMTState *cmt, int ch) | |
36 | +{ | |
37 | + int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
38 | + | |
39 | + if (cmt->cmstr & (1 << ch)) { | |
40 | + delta = (now - cmt->tick[ch]) / freq_to_ns(cmt->input_freq); | |
41 | + delta /= clkdiv[cmt->cmcr[ch] & 0x03]; | |
42 | + return cmt->cmcnt[ch] + delta; | |
43 | + } else | |
44 | + return cmt->cmcnt[ch]; | |
45 | +} | |
46 | + | |
47 | +static uint64_t cmt_read(void *opaque, hwaddr addr, unsigned size) | |
48 | +{ | |
49 | + hwaddr offset = addr & 0x0f; | |
50 | + RCMTState *cmt = opaque; | |
51 | + int ch = offset / 0x08; | |
52 | + int error = 1; | |
53 | + | |
54 | + if (offset == 0) { | |
55 | + return cmt->cmstr; | |
56 | + error = 0; | |
57 | + } else { | |
58 | + offset &= 0x07; | |
59 | + if (ch == 0) | |
60 | + offset -= 0x02; | |
61 | + error = 0; | |
62 | + switch(offset) { | |
63 | + case 0: | |
64 | + return cmt->cmcr[ch]; | |
65 | + case 2: | |
66 | + return read_cmcnt(cmt, ch); | |
67 | + case 4: | |
68 | + return cmt->cmcor[ch]; | |
69 | + default: | |
70 | + error = 1; | |
71 | + } | |
72 | + } | |
73 | + if (error) | |
74 | + error_report("rcmt: unsupported read request to %08lx", addr); | |
75 | + return 0xffffffffffffffffUL; | |
76 | +} | |
77 | + | |
78 | +static void start_stop(RCMTState *cmt, int ch, int st) | |
79 | +{ | |
80 | + if (st) | |
81 | + update_events(cmt, ch); | |
82 | + else | |
83 | + timer_del(cmt->timer[ch]); | |
84 | +} | |
85 | + | |
86 | +static void cmt_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
87 | +{ | |
88 | + hwaddr offset = addr & 0x0f; | |
89 | + RCMTState *cmt = opaque; | |
90 | + int ch = offset / 0x08; | |
91 | + int error = 1; | |
92 | + | |
93 | + if (offset == 0) { | |
94 | + cmt->cmstr = val; | |
95 | + start_stop(cmt, 0, cmt->cmstr & 1); | |
96 | + start_stop(cmt, 1, (cmt->cmstr >> 1) & 1); | |
97 | + error = 0; | |
98 | + } else { | |
99 | + offset &= 0x07; | |
100 | + if (ch == 0) | |
101 | + offset -= 0x02; | |
102 | + error = 0; | |
103 | + switch(offset) { | |
104 | + case 0: | |
105 | + cmt->cmcr[ch] = val; | |
106 | + break; | |
107 | + case 2: | |
108 | + cmt->cmcnt[ch] = val; | |
109 | + break; | |
110 | + case 4: | |
111 | + cmt->cmcor[ch] = val; | |
112 | + break; | |
113 | + default: | |
114 | + error = 1; | |
115 | + } | |
116 | + if (error == 0 && cmt->cmstr & (1 << ch)) | |
117 | + update_events(cmt, ch); | |
118 | + } | |
119 | + if (error) | |
120 | + error_report("rcmt: unsupported write request to %08lx", addr); | |
121 | +} | |
122 | + | |
123 | +static const MemoryRegionOps cmt_ops = { | |
124 | + .write = cmt_write, | |
125 | + .read = cmt_read, | |
126 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
127 | + .impl = { | |
128 | + .min_access_size = 2, | |
129 | + .max_access_size = 2, | |
130 | + }, | |
131 | +}; | |
132 | + | |
133 | +static void timer_events(RCMTState *cmt, int ch) | |
134 | +{ | |
135 | + cmt->cmcnt[ch] = 0; | |
136 | + cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
137 | + update_events(cmt, ch); | |
138 | + if (cmt->cmcr[ch] & 0x40) | |
139 | + qemu_irq_pulse(cmt->cmi[ch]); | |
140 | +} | |
141 | + | |
142 | +static void timer_event0(void *opaque) | |
143 | +{ | |
144 | + RCMTState *cmt = opaque; | |
145 | + | |
146 | + timer_events(cmt, 0); | |
147 | +} | |
148 | + | |
149 | +static void timer_event1(void *opaque) | |
150 | +{ | |
151 | + RCMTState *cmt = opaque; | |
152 | + | |
153 | + timer_events(cmt, 1); | |
154 | +} | |
155 | + | |
156 | +static void rcmt_reset(DeviceState *dev) | |
157 | +{ | |
158 | + RCMTState *cmt = RCMT(dev); | |
159 | + cmt->cmstr = 0; | |
160 | + cmt->cmcr[0] = cmt->cmcr[1] = 0; | |
161 | + cmt->cmcnt[0] = cmt->cmcnt[1] = 0; | |
162 | + cmt->cmcor[0] = cmt->cmcor[1] = 0xffff; | |
163 | +} | |
164 | + | |
165 | +static void rcmt_init(Object *obj) | |
166 | +{ | |
167 | + SysBusDevice *d = SYS_BUS_DEVICE(obj); | |
168 | + RCMTState *cmt = RCMT(obj); | |
169 | + int i; | |
170 | + | |
171 | + memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops, | |
172 | + cmt, "renesas-cmt", 0x10); | |
173 | + sysbus_init_mmio(d, &cmt->memory); | |
174 | + | |
175 | + for (i = 0; i < 2; i++) { | |
176 | + sysbus_init_irq(d, &cmt->cmi[i]); | |
177 | + } | |
178 | + cmt->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, cmt); | |
179 | + cmt->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, cmt); | |
180 | +} | |
181 | + | |
182 | +static const VMStateDescription vmstate_rcmt = { | |
183 | + .name = "rx-cmt", | |
184 | + .version_id = 1, | |
185 | + .minimum_version_id = 1, | |
186 | + .fields = (VMStateField[]) { | |
187 | + VMSTATE_END_OF_LIST() | |
188 | + } | |
189 | +}; | |
190 | + | |
191 | +static Property rcmt_properties[] = { | |
192 | + DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0), | |
193 | + DEFINE_PROP_END_OF_LIST(), | |
194 | +}; | |
195 | + | |
196 | +static void rcmt_class_init(ObjectClass *klass, void *data) | |
197 | +{ | |
198 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
199 | + | |
200 | + dc->props = rcmt_properties; | |
201 | + dc->vmsd = &vmstate_rcmt; | |
202 | + dc->reset = rcmt_reset; | |
203 | +} | |
204 | + | |
205 | +static const TypeInfo rcmt_info = { | |
206 | + .name = TYPE_RCMT, | |
207 | + .parent = TYPE_SYS_BUS_DEVICE, | |
208 | + .instance_size = sizeof(RCMTState), | |
209 | + .instance_init = rcmt_init, | |
210 | + .class_init = rcmt_class_init, | |
211 | +}; | |
212 | + | |
213 | +static void rcmt_register_types(void) | |
214 | +{ | |
215 | + type_register_static(&rcmt_info); | |
216 | +} | |
217 | + | |
218 | +type_init(rcmt_register_types) |
@@ -0,0 +1,36 @@ | ||
1 | +#ifndef SH7619INTC_H | |
2 | +#define SH7619INTC_H | |
3 | + | |
4 | +#include "qemu-common.h" | |
5 | +#include "hw/irq.h" | |
6 | + | |
7 | +struct IRQSource { | |
8 | + int sense; | |
9 | + int level; | |
10 | + int req; | |
11 | +}; | |
12 | + | |
13 | +struct SH7619INTCState { | |
14 | + SysBusDevice parent_obj; | |
15 | + | |
16 | + MemoryRegion memory[2]; | |
17 | + unsigned int icr0; | |
18 | + unsigned int irqcr; | |
19 | + unsigned int irqsr; | |
20 | + unsigned int ipr[7]; | |
21 | + struct IRQSource src[64]; | |
22 | + qemu_irq irq; | |
23 | + int req_irq; | |
24 | + unsigned int read_sr; | |
25 | +}; | |
26 | +typedef struct SH7619INTCState SH7619INTCState; | |
27 | + | |
28 | +#define TYPE_SH7619INTC "sh7619-intc" | |
29 | +#define SH7619INTC(obj) OBJECT_CHECK(SH7619INTCState, (obj), TYPE_SH7619INTC) | |
30 | + | |
31 | +#define TRG_LEVEL 0 | |
32 | +#define TRG_NEDGE 1 | |
33 | +#define TRG_PEDGE 2 | |
34 | +#define TRG_BEDGE 3 | |
35 | + | |
36 | +#endif /* SH7619INTC_H */ |
@@ -55,4 +55,8 @@ qemu_irq sh7750_irl(struct SH7750State *s); | ||
55 | 55 | /* tc58128.c */ |
56 | 56 | int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2); |
57 | 57 | |
58 | +/* sh7619.c */ | |
59 | +struct SH7619State; | |
60 | +struct SH7619State *sh7619_init(SuperHCPU *cpu, struct MemoryRegion *sysmem); | |
61 | + | |
58 | 62 | #endif |
@@ -0,0 +1,36 @@ | ||
1 | +/* | |
2 | + * SH7619 Object | |
3 | + * | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | + * | |
6 | + * This code is licensed under the GPL version 2 or later. | |
7 | + * | |
8 | + */ | |
9 | + | |
10 | +#ifndef HW_RX_SH7619_H | |
11 | +#define HW_RX_SH7619_H | |
12 | + | |
13 | +#include "hw/sysbus.h" | |
14 | +#include "hw/sh4/sh.h" | |
15 | +#include "hw/intc/sh7619intc.h" | |
16 | +#include "target/sh4/cpu-qom.h" | |
17 | + | |
18 | +#define SH7619(obj) OBJECT_CHECK(SH7619State, (obj), TYPE_SH7619_CPU) | |
19 | + | |
20 | +typedef struct SH7619State { | |
21 | + SysBusDevice parent_obj; | |
22 | + | |
23 | + SuperHCPU *cpu; | |
24 | + SH7619INTCState *intc; | |
25 | + | |
26 | + MemoryRegion *sysmem; | |
27 | + bool kernel; | |
28 | + | |
29 | + MemoryRegion uram; | |
30 | + MemoryRegion cache; | |
31 | + MemoryRegion cpg; | |
32 | + qemu_irq irq[64]; | |
33 | + uint16_t frqcr; | |
34 | +} SH7619State; | |
35 | + | |
36 | +#endif |
@@ -59,6 +59,7 @@ struct intc_desc { | ||
59 | 59 | }; |
60 | 60 | |
61 | 61 | int sh_intc_get_pending_vector(struct intc_desc *desc, int imask); |
62 | +int sh2_intc_get_pending_vector(void *state, int imask, int *level); | |
62 | 63 | struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id); |
63 | 64 | void sh_intc_toggle_source(struct intc_source *source, |
64 | 65 | int enable_adj, int assert_adj); |
@@ -0,0 +1,33 @@ | ||
1 | +/* | |
2 | + * Renesas Compare-match timer Object | |
3 | + * | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | + * | |
6 | + * This code is licensed under the GPL version 2 or later. | |
7 | + * | |
8 | + */ | |
9 | + | |
10 | +#ifndef HW_RENESAS_CMT_H | |
11 | +#define HW_RENESAS_CMT_H | |
12 | + | |
13 | +#include "hw/sysbus.h" | |
14 | + | |
15 | +#define TYPE_RCMT "rcmt" | |
16 | +#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RCMT) | |
17 | + | |
18 | +typedef struct RCMTState { | |
19 | + SysBusDevice parent_obj; | |
20 | + | |
21 | + uint64_t input_freq; | |
22 | + MemoryRegion memory; | |
23 | + | |
24 | + uint16_t cmstr; | |
25 | + uint16_t cmcr[2]; | |
26 | + uint16_t cmcnt[2]; | |
27 | + uint16_t cmcor[2]; | |
28 | + int64_t tick[2]; | |
29 | + qemu_irq cmi[2]; | |
30 | + QEMUTimer *timer[2]; | |
31 | +} RCMTState; | |
32 | + | |
33 | +#endif |
@@ -24,6 +24,7 @@ | ||
24 | 24 | |
25 | 25 | #define TYPE_SUPERH_CPU "superh-cpu" |
26 | 26 | |
27 | +#define TYPE_SH7619_CPU SUPERH_CPU_TYPE_NAME("sh7619") | |
27 | 28 | #define TYPE_SH7750R_CPU SUPERH_CPU_TYPE_NAME("sh7750r") |
28 | 29 | #define TYPE_SH7751R_CPU SUPERH_CPU_TYPE_NAME("sh7751r") |
29 | 30 | #define TYPE_SH7785_CPU SUPERH_CPU_TYPE_NAME("sh7785") |
@@ -59,14 +59,23 @@ static void superh_cpu_reset(CPUState *s) | ||
59 | 59 | |
60 | 60 | memset(env, 0, offsetof(CPUSH4State, end_reset_fields)); |
61 | 61 | |
62 | - env->pc = 0xA0000000; | |
62 | + if (env->features != SH_FEATURE_SH2) | |
63 | + env->pc = 0xA0000000; | |
64 | + else { | |
65 | + env->pc = ldl_phys(s->as, 0x00000000); | |
66 | + env->gregs[15] = ldl_phys(s->as, 0x00000004); | |
67 | + } | |
63 | 68 | #if defined(CONFIG_USER_ONLY) |
64 | 69 | env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */ |
65 | 70 | set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */ |
66 | 71 | #else |
67 | - env->sr = (1u << SR_MD) | (1u << SR_RB) | (1u << SR_BL) | | |
68 | - (1u << SR_I3) | (1u << SR_I2) | (1u << SR_I1) | (1u << SR_I0); | |
69 | - env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */ | |
72 | + if (env->features != SH_FEATURE_SH2) { | |
73 | + env->sr = (1u << SR_MD) | (1u << SR_RB) | (1u << SR_BL) | | |
74 | + (1u << SR_I3) | (1u << SR_I2) | (1u << SR_I1) | (1u << SR_I0); | |
75 | + env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */ | |
76 | + } else { | |
77 | + env->sr = (1u << SR_I3) | (1u << SR_I2) | (1u << SR_I1) | (1u << SR_I0); | |
78 | + } | |
70 | 79 | set_float_rounding_mode(float_round_to_zero, &env->fp_status); |
71 | 80 | set_flush_to_zero(1, &env->fp_status); |
72 | 81 | #endif |
@@ -129,6 +138,19 @@ out: | ||
129 | 138 | return oc; |
130 | 139 | } |
131 | 140 | |
141 | +static void sh7619_cpu_initfn(Object *obj) | |
142 | +{ | |
143 | + SuperHCPU *cpu = SUPERH_CPU(obj); | |
144 | + CPUSH4State *env = &cpu->env; | |
145 | + | |
146 | + env->id = SH_CPU_SH7619; | |
147 | + env->features = SH_FEATURE_SH2; | |
148 | +} | |
149 | + | |
150 | +static void sh7619_class_init(ObjectClass *oc, void *data) | |
151 | +{ | |
152 | +} | |
153 | + | |
132 | 154 | static void sh7750r_cpu_initfn(Object *obj) |
133 | 155 | { |
134 | 156 | SuperHCPU *cpu = SUPERH_CPU(obj); |
@@ -195,8 +217,8 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp) | ||
195 | 217 | return; |
196 | 218 | } |
197 | 219 | |
198 | - cpu_reset(cs); | |
199 | 220 | qemu_init_vcpu(cs); |
221 | + cpu_reset(cs); | |
200 | 222 | |
201 | 223 | scc->parent_realize(dev, errp); |
202 | 224 | } |
@@ -269,6 +291,8 @@ static const TypeInfo superh_cpu_type_infos[] = { | ||
269 | 291 | .class_size = sizeof(SuperHCPUClass), |
270 | 292 | .class_init = superh_cpu_class_init, |
271 | 293 | }, |
294 | + DEFINE_SUPERH_CPU_TYPE(TYPE_SH7619_CPU, sh7619_class_init, | |
295 | + sh7619_cpu_initfn), | |
272 | 296 | DEFINE_SUPERH_CPU_TYPE(TYPE_SH7750R_CPU, sh7750r_class_init, |
273 | 297 | sh7750r_cpu_initfn), |
274 | 298 | DEFINE_SUPERH_CPU_TYPE(TYPE_SH7751R_CPU, sh7751r_class_init, |
@@ -33,6 +33,7 @@ | ||
33 | 33 | #define SH_CPU_SH7751 (1 << 3) |
34 | 34 | #define SH_CPU_SH7751R (1 << 4) |
35 | 35 | #define SH_CPU_SH7785 (1 << 5) |
36 | +#define SH_CPU_SH7619 (1 << 6) | |
36 | 37 | #define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R) |
37 | 38 | #define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R) |
38 | 39 |
@@ -138,6 +139,7 @@ typedef struct tlb_t { | ||
138 | 139 | enum sh_features { |
139 | 140 | SH_FEATURE_SH4A = 1, |
140 | 141 | SH_FEATURE_BCR3_AND_BCR4 = 2, |
142 | + SH_FEATURE_SH2 = 3, | |
141 | 143 | }; |
142 | 144 | |
143 | 145 | typedef struct memory_content { |
@@ -20,6 +20,7 @@ | ||
20 | 20 | |
21 | 21 | #include "cpu.h" |
22 | 22 | #include "exec/exec-all.h" |
23 | +#include "exec/cpu_ldst.h" | |
23 | 24 | #include "exec/log.h" |
24 | 25 | #include "sysemu/sysemu.h" |
25 | 26 |
@@ -85,13 +86,14 @@ void superh_cpu_do_interrupt(CPUState *cs) | ||
85 | 86 | CPUSH4State *env = &cpu->env; |
86 | 87 | int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD; |
87 | 88 | int do_exp, irq_vector = cs->exception_index; |
89 | + int level = 0; | |
88 | 90 | |
89 | 91 | /* prioritize exceptions over interrupts */ |
90 | 92 | |
91 | 93 | do_exp = cs->exception_index != -1; |
92 | 94 | do_irq = do_irq && (cs->exception_index == -1); |
93 | 95 | |
94 | - if (env->sr & (1u << SR_BL)) { | |
96 | + if ((env->features != SH_FEATURE_SH2) && (env->sr & (1u << SR_BL))) { | |
95 | 97 | if (do_exp && cs->exception_index != 0x1e0) { |
96 | 98 | /* In theory a masked exception generates a reset exception, |
97 | 99 | which in turn jumps to the reset vector. However this only |
@@ -109,8 +111,13 @@ void superh_cpu_do_interrupt(CPUState *cs) | ||
109 | 111 | env->in_sleep = 0; |
110 | 112 | |
111 | 113 | if (do_irq) { |
112 | - irq_vector = sh_intc_get_pending_vector(env->intc_handle, | |
113 | - (env->sr >> 4) & 0xf); | |
114 | + if (env->features != SH_FEATURE_SH2) | |
115 | + irq_vector = sh_intc_get_pending_vector(env->intc_handle, | |
116 | + (env->sr >> 4) & 0xf); | |
117 | + else | |
118 | + irq_vector = sh2_intc_get_pending_vector(env->intc_handle, | |
119 | + (env->sr >> 4) & 0xf, | |
120 | + &level); | |
114 | 121 | if (irq_vector == -1) { |
115 | 122 | return; /* masked */ |
116 | 123 | } |
@@ -170,8 +177,10 @@ void superh_cpu_do_interrupt(CPUState *cs) | ||
170 | 177 | env->ssr = cpu_read_sr(env); |
171 | 178 | env->spc = env->pc; |
172 | 179 | env->sgr = env->gregs[15]; |
173 | - env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB); | |
174 | - env->lock_addr = -1; | |
180 | + if (env->features != SH_FEATURE_SH2) { | |
181 | + env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB); | |
182 | + env->lock_addr = -1; | |
183 | + } | |
175 | 184 | |
176 | 185 | if (env->flags & DELAY_SLOT_MASK) { |
177 | 186 | /* Branch instruction should be executed again before delay slot. */ |
@@ -180,34 +189,67 @@ void superh_cpu_do_interrupt(CPUState *cs) | ||
180 | 189 | env->flags &= ~DELAY_SLOT_MASK; |
181 | 190 | } |
182 | 191 | |
183 | - if (do_exp) { | |
184 | - env->expevt = cs->exception_index; | |
185 | - switch (cs->exception_index) { | |
186 | - case 0x000: | |
187 | - case 0x020: | |
188 | - case 0x140: | |
189 | - env->sr &= ~(1u << SR_FD); | |
190 | - env->sr |= 0xf << 4; /* IMASK */ | |
191 | - env->pc = 0xa0000000; | |
192 | - break; | |
193 | - case 0x040: | |
194 | - case 0x060: | |
195 | - env->pc = env->vbr + 0x400; | |
196 | - break; | |
197 | - case 0x160: | |
198 | - env->spc += 2; /* special case for TRAPA */ | |
199 | - /* fall through */ | |
200 | - default: | |
201 | - env->pc = env->vbr + 0x100; | |
202 | - break; | |
192 | + if (env->features == SH_FEATURE_SH2) { | |
193 | + int v = -1; | |
194 | + uint32_t sp = env->gregs[15]; | |
195 | + cpu_stl_kernel(env, sp, env->ssr); | |
196 | + sp -= 4; | |
197 | + if (!do_exp || cs->exception_index != 0x160) | |
198 | + cpu_stl_kernel(env, sp, env->spc); | |
199 | + else | |
200 | + cpu_stl_kernel(env, sp, env->spc + 2); | |
201 | + sp -= 4; | |
202 | + env->gregs[15] = sp; | |
203 | + env->sr &= (~0xf0); | |
204 | + env->sr |= level << 4; | |
205 | + if (do_exp) { | |
206 | + switch(cs->exception_index) { | |
207 | + case 0x180: | |
208 | + v = 4; break; | |
209 | + case 0x1a0: | |
210 | + v = 6; break; | |
211 | + case 0x0e0: | |
212 | + case 0x100: | |
213 | + v = 9; break; | |
214 | + case 0x160: | |
215 | + v = env->tra; break; | |
216 | + } | |
217 | + } | |
218 | + if (do_irq) { | |
219 | + v = irq_vector; | |
203 | 220 | } |
221 | + env->pc = cpu_ldl_kernel(env, env->vbr + v * 4); | |
204 | 222 | return; |
205 | - } | |
223 | + } else { | |
224 | + if (do_exp) { | |
225 | + env->expevt = cs->exception_index; | |
226 | + switch (cs->exception_index) { | |
227 | + case 0x000: | |
228 | + case 0x020: | |
229 | + case 0x140: | |
230 | + env->sr &= ~(1u << SR_FD); | |
231 | + env->sr |= 0xf << 4; /* IMASK */ | |
232 | + env->pc = 0xa0000000; | |
233 | + break; | |
234 | + case 0x040: | |
235 | + case 0x060: | |
236 | + env->pc = env->vbr + 0x400; | |
237 | + break; | |
238 | + case 0x160: | |
239 | + env->spc += 2; /* special case for TRAPA */ | |
240 | + /* fall through */ | |
241 | + default: | |
242 | + env->pc = env->vbr + 0x100; | |
243 | + break; | |
244 | + } | |
245 | + return; | |
246 | + } | |
206 | 247 | |
207 | - if (do_irq) { | |
208 | - env->intevt = irq_vector; | |
209 | - env->pc = env->vbr + 0x600; | |
210 | - return; | |
248 | + if (do_irq) { | |
249 | + env->intevt = irq_vector; | |
250 | + env->pc = env->vbr + 0x600; | |
251 | + return; | |
252 | + } | |
211 | 253 | } |
212 | 254 | } |
213 | 255 |
@@ -458,6 +500,34 @@ static int get_physical_address(CPUSH4State * env, target_ulong * physical, | ||
458 | 500 | return get_mmu_address(env, physical, prot, address, rw, access_type); |
459 | 501 | } |
460 | 502 | |
503 | +static int get_physical_address_sh2(CPUSH4State * env, target_ulong * physical, | |
504 | + int *prot, target_ulong address) | |
505 | +{ | |
506 | + /* P1, P2 and P4 areas do not use translation */ | |
507 | + if ((address >= 0x80000000 && address < 0xc0000000) || | |
508 | + address >= 0xe0000000) { | |
509 | + if (address >= 0x80000000 && address < 0xc0000000) { | |
510 | + /* Mask upper 3 bits for P1 and P2 areas */ | |
511 | + *physical = address & 0x1fffffff; | |
512 | + } else { | |
513 | + *physical = address; | |
514 | + } | |
515 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
516 | + return MMU_OK; | |
517 | + } | |
518 | + | |
519 | + if (address < 0x80000000) { | |
520 | + /* P0 */ | |
521 | + *physical = address & 0x7FFFFFFF; | |
522 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
523 | + } else { | |
524 | + /* P3 */ | |
525 | + *physical = address & 0x1FFFFFFF; | |
526 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
527 | + } | |
528 | + return MMU_OK; | |
529 | +} | |
530 | + | |
461 | 531 | int superh_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, |
462 | 532 | int mmu_idx) |
463 | 533 | { |
@@ -466,10 +536,15 @@ int superh_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, | ||
466 | 536 | target_ulong physical; |
467 | 537 | int prot, ret, access_type; |
468 | 538 | |
469 | - access_type = ACCESS_INT; | |
470 | - ret = | |
471 | - get_physical_address(env, &physical, &prot, address, rw, | |
472 | - access_type); | |
539 | + if (env->features != SH_FEATURE_SH2) { | |
540 | + access_type = ACCESS_INT; | |
541 | + ret = | |
542 | + get_physical_address(env, &physical, &prot, address, rw, | |
543 | + access_type); | |
544 | + } else { | |
545 | + ret = | |
546 | + get_physical_address_sh2(env, &physical, &prot, address); | |
547 | + } | |
473 | 548 | |
474 | 549 | if (ret != MMU_OK) { |
475 | 550 | env->tea = address; |
@@ -527,7 +602,11 @@ hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||
527 | 602 | target_ulong physical; |
528 | 603 | int prot; |
529 | 604 | |
530 | - get_physical_address(&cpu->env, &physical, &prot, addr, 0, 0); | |
605 | + if (cpu->env.features != SH_FEATURE_SH2) | |
606 | + get_physical_address(&cpu->env, &physical, &prot, addr, 0, 0); | |
607 | + else | |
608 | + get_physical_address_sh2(&cpu->env, &physical, &prot, addr); | |
609 | + | |
531 | 610 | return physical; |
532 | 611 | } |
533 | 612 |
@@ -373,7 +373,7 @@ static inline void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) | ||
373 | 373 | } |
374 | 374 | |
375 | 375 | #define CHECK_PRIVILEGED \ |
376 | - if (IS_USER(ctx)) { \ | |
376 | + if (!(ctx->features & SH_FEATURE_SH2) && IS_USER(ctx)) { \ | |
377 | 377 | goto do_illegal; \ |
378 | 378 | } |
379 | 379 |
@@ -397,6 +397,11 @@ static inline void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) | ||
397 | 397 | goto do_illegal; \ |
398 | 398 | } |
399 | 399 | |
400 | +#define CHECK_SH2 \ | |
401 | + if (!(ctx->features & SH_FEATURE_SH2)) { \ | |
402 | + goto do_illegal; \ | |
403 | + } | |
404 | + | |
400 | 405 | static void _decode_opc(DisasContext * ctx) |
401 | 406 | { |
402 | 407 | /* This code tries to make movcal emulation sufficiently |
@@ -451,36 +456,51 @@ static void _decode_opc(DisasContext * ctx) | ||
451 | 456 | tcg_gen_movi_i32(cpu_macl, 0); |
452 | 457 | return; |
453 | 458 | case 0x0048: /* clrs */ |
459 | + CHECK_SH2 | |
454 | 460 | tcg_gen_andi_i32(cpu_sr, cpu_sr, ~(1u << SR_S)); |
455 | 461 | return; |
456 | 462 | case 0x0008: /* clrt */ |
457 | 463 | tcg_gen_movi_i32(cpu_sr_t, 0); |
458 | 464 | return; |
459 | 465 | case 0x0038: /* ldtlb */ |
466 | + CHECK_SH2 | |
460 | 467 | CHECK_PRIVILEGED |
461 | 468 | gen_helper_ldtlb(cpu_env); |
462 | 469 | return; |
463 | 470 | case 0x002b: /* rte */ |
464 | 471 | CHECK_PRIVILEGED |
465 | 472 | CHECK_NOT_DELAY_SLOT |
466 | - gen_write_sr(cpu_ssr); | |
467 | - tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); | |
473 | + if (ctx->features != SH_FEATURE_SH2) { | |
474 | + gen_write_sr(cpu_ssr); | |
475 | + tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); | |
476 | + } else { | |
477 | + TCGv sr = tcg_temp_local_new(); | |
478 | + tcg_gen_qemu_ld32u(sr, cpu_gregs[15], 0); | |
479 | + tcg_gen_addi_i32(cpu_gregs[15], cpu_gregs[15], 4); | |
480 | + tcg_gen_qemu_ld32u(cpu_delayed_pc, cpu_gregs[15], 0); | |
481 | + tcg_gen_addi_i32(cpu_gregs[15], cpu_gregs[15], 4); | |
482 | + gen_write_sr(sr); | |
483 | + tcg_temp_free(sr); | |
484 | + } | |
468 | 485 | ctx->envflags |= DELAY_SLOT_RTE; |
469 | 486 | ctx->delayed_pc = (uint32_t) - 1; |
470 | 487 | ctx->base.is_jmp = DISAS_STOP; |
471 | 488 | return; |
472 | 489 | case 0x0058: /* sets */ |
490 | + CHECK_SH2 | |
473 | 491 | tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S)); |
474 | 492 | return; |
475 | 493 | case 0x0018: /* sett */ |
476 | 494 | tcg_gen_movi_i32(cpu_sr_t, 1); |
477 | 495 | return; |
478 | 496 | case 0xfbfd: /* frchg */ |
497 | + CHECK_SH2 | |
479 | 498 | CHECK_FPSCR_PR_0 |
480 | 499 | tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR); |
481 | 500 | ctx->base.is_jmp = DISAS_STOP; |
482 | 501 | return; |
483 | 502 | case 0xf3fd: /* fschg */ |
503 | + CHECK_SH2 | |
484 | 504 | CHECK_FPSCR_PR_0 |
485 | 505 | tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ); |
486 | 506 | ctx->base.is_jmp = DISAS_STOP; |
@@ -894,6 +914,7 @@ static void _decode_opc(DisasContext * ctx) | ||
894 | 914 | return; |
895 | 915 | case 0x400c: /* shad Rm,Rn */ |
896 | 916 | { |
917 | + CHECK_SH2 | |
897 | 918 | TCGv t0 = tcg_temp_new(); |
898 | 919 | TCGv t1 = tcg_temp_new(); |
899 | 920 | TCGv t2 = tcg_temp_new(); |
@@ -920,6 +941,7 @@ static void _decode_opc(DisasContext * ctx) | ||
920 | 941 | return; |
921 | 942 | case 0x400d: /* shld Rm,Rn */ |
922 | 943 | { |
944 | + CHECK_SH2 | |
923 | 945 | TCGv t0 = tcg_temp_new(); |
924 | 946 | TCGv t1 = tcg_temp_new(); |
925 | 947 | TCGv t2 = tcg_temp_new(); |
@@ -989,6 +1011,7 @@ static void _decode_opc(DisasContext * ctx) | ||
989 | 1011 | tcg_gen_xor_i32(REG(B11_8), REG(B11_8), REG(B7_4)); |
990 | 1012 | return; |
991 | 1013 | case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */ |
1014 | + CHECK_SH2 | |
992 | 1015 | CHECK_FPU_ENABLED |
993 | 1016 | if (ctx->tbflags & FPSCR_SZ) { |
994 | 1017 | int xsrc = XHACK(B7_4); |
@@ -1000,6 +1023,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1000 | 1023 | } |
1001 | 1024 | return; |
1002 | 1025 | case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */ |
1026 | + CHECK_SH2 | |
1003 | 1027 | CHECK_FPU_ENABLED |
1004 | 1028 | if (ctx->tbflags & FPSCR_SZ) { |
1005 | 1029 | TCGv_i64 fp = tcg_temp_new_i64(); |
@@ -1011,6 +1035,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1011 | 1035 | } |
1012 | 1036 | return; |
1013 | 1037 | case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */ |
1038 | + CHECK_SH2 | |
1014 | 1039 | CHECK_FPU_ENABLED |
1015 | 1040 | if (ctx->tbflags & FPSCR_SZ) { |
1016 | 1041 | TCGv_i64 fp = tcg_temp_new_i64(); |
@@ -1022,6 +1047,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1022 | 1047 | } |
1023 | 1048 | return; |
1024 | 1049 | case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */ |
1050 | + CHECK_SH2 | |
1025 | 1051 | CHECK_FPU_ENABLED |
1026 | 1052 | if (ctx->tbflags & FPSCR_SZ) { |
1027 | 1053 | TCGv_i64 fp = tcg_temp_new_i64(); |
@@ -1035,6 +1061,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1035 | 1061 | } |
1036 | 1062 | return; |
1037 | 1063 | case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */ |
1064 | + CHECK_SH2 | |
1038 | 1065 | CHECK_FPU_ENABLED |
1039 | 1066 | { |
1040 | 1067 | TCGv addr = tcg_temp_new_i32(); |
@@ -1053,6 +1080,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1053 | 1080 | } |
1054 | 1081 | return; |
1055 | 1082 | case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ |
1083 | + CHECK_SH2 | |
1056 | 1084 | CHECK_FPU_ENABLED |
1057 | 1085 | { |
1058 | 1086 | TCGv addr = tcg_temp_new_i32(); |
@@ -1069,6 +1097,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1069 | 1097 | } |
1070 | 1098 | return; |
1071 | 1099 | case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */ |
1100 | + CHECK_SH2 | |
1072 | 1101 | CHECK_FPU_ENABLED |
1073 | 1102 | { |
1074 | 1103 | TCGv addr = tcg_temp_new(); |
@@ -1091,6 +1120,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1091 | 1120 | case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ |
1092 | 1121 | case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ |
1093 | 1122 | { |
1123 | + CHECK_SH2 | |
1094 | 1124 | CHECK_FPU_ENABLED |
1095 | 1125 | if (ctx->tbflags & FPSCR_PR) { |
1096 | 1126 | TCGv_i64 fp0, fp1; |
@@ -1156,6 +1186,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1156 | 1186 | } |
1157 | 1187 | return; |
1158 | 1188 | case 0xf00e: /* fmac FR0,RM,Rn */ |
1189 | + CHECK_SH2 | |
1159 | 1190 | CHECK_FPU_ENABLED |
1160 | 1191 | CHECK_FPSCR_PR_0 |
1161 | 1192 | gen_helper_fmac_FT(FREG(B11_8), cpu_env, |
@@ -1352,19 +1383,23 @@ static void _decode_opc(DisasContext * ctx) | ||
1352 | 1383 | |
1353 | 1384 | switch (ctx->opcode & 0xf08f) { |
1354 | 1385 | case 0x408e: /* ldc Rm,Rn_BANK */ |
1386 | + CHECK_SH2 | |
1355 | 1387 | CHECK_PRIVILEGED |
1356 | 1388 | tcg_gen_mov_i32(ALTREG(B6_4), REG(B11_8)); |
1357 | 1389 | return; |
1358 | 1390 | case 0x4087: /* ldc.l @Rm+,Rn_BANK */ |
1391 | + CHECK_SH2 | |
1359 | 1392 | CHECK_PRIVILEGED |
1360 | 1393 | tcg_gen_qemu_ld_i32(ALTREG(B6_4), REG(B11_8), ctx->memidx, MO_TESL); |
1361 | 1394 | tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); |
1362 | 1395 | return; |
1363 | 1396 | case 0x0082: /* stc Rm_BANK,Rn */ |
1397 | + CHECK_SH2 | |
1364 | 1398 | CHECK_PRIVILEGED |
1365 | 1399 | tcg_gen_mov_i32(REG(B11_8), ALTREG(B6_4)); |
1366 | 1400 | return; |
1367 | 1401 | case 0x4083: /* stc.l Rm_BANK,@-Rn */ |
1402 | + CHECK_SH2 | |
1368 | 1403 | CHECK_PRIVILEGED |
1369 | 1404 | { |
1370 | 1405 | TCGv addr = tcg_temp_new(); |
@@ -1497,6 +1532,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1497 | 1532 | ctx->base.is_jmp = DISAS_STOP; |
1498 | 1533 | return; |
1499 | 1534 | case 0x4066: /* lds.l @Rm+,FPSCR */ |
1535 | + CHECK_SH2 | |
1500 | 1536 | CHECK_FPU_ENABLED |
1501 | 1537 | { |
1502 | 1538 | TCGv addr = tcg_temp_new(); |
@@ -1508,10 +1544,12 @@ static void _decode_opc(DisasContext * ctx) | ||
1508 | 1544 | } |
1509 | 1545 | return; |
1510 | 1546 | case 0x006a: /* sts FPSCR,Rn */ |
1547 | + CHECK_SH2 | |
1511 | 1548 | CHECK_FPU_ENABLED |
1512 | 1549 | tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff); |
1513 | 1550 | return; |
1514 | 1551 | case 0x4062: /* sts FPSCR,@-Rn */ |
1552 | + CHECK_SH2 | |
1515 | 1553 | CHECK_FPU_ENABLED |
1516 | 1554 | { |
1517 | 1555 | TCGv addr, val; |
@@ -1615,17 +1653,20 @@ static void _decode_opc(DisasContext * ctx) | ||
1615 | 1653 | } |
1616 | 1654 | return; |
1617 | 1655 | case 0x0093: /* ocbi @Rn */ |
1656 | + CHECK_SH2 | |
1618 | 1657 | { |
1619 | 1658 | gen_helper_ocbi(cpu_env, REG(B11_8)); |
1620 | 1659 | } |
1621 | 1660 | return; |
1622 | 1661 | case 0x00a3: /* ocbp @Rn */ |
1623 | 1662 | case 0x00b3: /* ocbwb @Rn */ |
1663 | + CHECK_SH2 | |
1624 | 1664 | /* These instructions are supposed to do nothing in case of |
1625 | 1665 | a cache miss. Given that we only partially emulate caches |
1626 | 1666 | it is safe to simply ignore them. */ |
1627 | 1667 | return; |
1628 | 1668 | case 0x0083: /* pref @Rn */ |
1669 | + CHECK_SH2 | |
1629 | 1670 | return; |
1630 | 1671 | case 0x00d3: /* prefi @Rn */ |
1631 | 1672 | CHECK_SH4A |
@@ -1707,14 +1748,17 @@ static void _decode_opc(DisasContext * ctx) | ||
1707 | 1748 | } |
1708 | 1749 | return; |
1709 | 1750 | case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */ |
1751 | + CHECK_SH2 | |
1710 | 1752 | CHECK_FPU_ENABLED |
1711 | 1753 | tcg_gen_mov_i32(FREG(B11_8), cpu_fpul); |
1712 | 1754 | return; |
1713 | 1755 | case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */ |
1756 | + CHECK_SH2 | |
1714 | 1757 | CHECK_FPU_ENABLED |
1715 | 1758 | tcg_gen_mov_i32(cpu_fpul, FREG(B11_8)); |
1716 | 1759 | return; |
1717 | 1760 | case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */ |
1761 | + CHECK_SH2 | |
1718 | 1762 | CHECK_FPU_ENABLED |
1719 | 1763 | if (ctx->tbflags & FPSCR_PR) { |
1720 | 1764 | TCGv_i64 fp; |
@@ -1731,6 +1775,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1731 | 1775 | } |
1732 | 1776 | return; |
1733 | 1777 | case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ |
1778 | + CHECK_SH2 | |
1734 | 1779 | CHECK_FPU_ENABLED |
1735 | 1780 | if (ctx->tbflags & FPSCR_PR) { |
1736 | 1781 | TCGv_i64 fp; |
@@ -1747,14 +1792,17 @@ static void _decode_opc(DisasContext * ctx) | ||
1747 | 1792 | } |
1748 | 1793 | return; |
1749 | 1794 | case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */ |
1795 | + CHECK_SH2 | |
1750 | 1796 | CHECK_FPU_ENABLED |
1751 | 1797 | tcg_gen_xori_i32(FREG(B11_8), FREG(B11_8), 0x80000000); |
1752 | 1798 | return; |
1753 | 1799 | case 0xf05d: /* fabs FRn/DRn - FPCSR: Nothing */ |
1800 | + CHECK_SH2 | |
1754 | 1801 | CHECK_FPU_ENABLED |
1755 | 1802 | tcg_gen_andi_i32(FREG(B11_8), FREG(B11_8), 0x7fffffff); |
1756 | 1803 | return; |
1757 | 1804 | case 0xf06d: /* fsqrt FRn */ |
1805 | + CHECK_SH2 | |
1758 | 1806 | CHECK_FPU_ENABLED |
1759 | 1807 | if (ctx->tbflags & FPSCR_PR) { |
1760 | 1808 | if (ctx->opcode & 0x0100) { |
@@ -1770,21 +1818,25 @@ static void _decode_opc(DisasContext * ctx) | ||
1770 | 1818 | } |
1771 | 1819 | return; |
1772 | 1820 | case 0xf07d: /* fsrra FRn */ |
1821 | + CHECK_SH2 | |
1773 | 1822 | CHECK_FPU_ENABLED |
1774 | 1823 | CHECK_FPSCR_PR_0 |
1775 | 1824 | gen_helper_fsrra_FT(FREG(B11_8), cpu_env, FREG(B11_8)); |
1776 | 1825 | break; |
1777 | 1826 | case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */ |
1827 | + CHECK_SH2 | |
1778 | 1828 | CHECK_FPU_ENABLED |
1779 | 1829 | CHECK_FPSCR_PR_0 |
1780 | 1830 | tcg_gen_movi_i32(FREG(B11_8), 0); |
1781 | 1831 | return; |
1782 | 1832 | case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */ |
1833 | + CHECK_SH2 | |
1783 | 1834 | CHECK_FPU_ENABLED |
1784 | 1835 | CHECK_FPSCR_PR_0 |
1785 | 1836 | tcg_gen_movi_i32(FREG(B11_8), 0x3f800000); |
1786 | 1837 | return; |
1787 | 1838 | case 0xf0ad: /* fcnvsd FPUL,DRn */ |
1839 | + CHECK_SH2 | |
1788 | 1840 | CHECK_FPU_ENABLED |
1789 | 1841 | { |
1790 | 1842 | TCGv_i64 fp = tcg_temp_new_i64(); |
@@ -1794,6 +1846,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1794 | 1846 | } |
1795 | 1847 | return; |
1796 | 1848 | case 0xf0bd: /* fcnvds DRn,FPUL */ |
1849 | + CHECK_SH2 | |
1797 | 1850 | CHECK_FPU_ENABLED |
1798 | 1851 | { |
1799 | 1852 | TCGv_i64 fp = tcg_temp_new_i64(); |
@@ -1803,6 +1856,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1803 | 1856 | } |
1804 | 1857 | return; |
1805 | 1858 | case 0xf0ed: /* fipr FVm,FVn */ |
1859 | + CHECK_SH2 | |
1806 | 1860 | CHECK_FPU_ENABLED |
1807 | 1861 | CHECK_FPSCR_PR_1 |
1808 | 1862 | { |
@@ -1815,6 +1869,7 @@ static void _decode_opc(DisasContext * ctx) | ||
1815 | 1869 | } |
1816 | 1870 | break; |
1817 | 1871 | case 0xf0fd: /* ftrv XMTRX,FVn */ |
1872 | + CHECK_SH2 | |
1818 | 1873 | CHECK_FPU_ENABLED |
1819 | 1874 | CHECK_FPSCR_PR_1 |
1820 | 1875 | { |
@@ -2256,8 +2311,11 @@ static void sh4_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) | ||
2256 | 2311 | ctx->delayed_pc = -1; /* use delayed pc from env pointer */ |
2257 | 2312 | ctx->features = env->features; |
2258 | 2313 | ctx->has_movcal = (tbflags & TB_FLAG_PENDING_MOVCA); |
2259 | - ctx->gbank = ((tbflags & (1 << SR_MD)) && | |
2260 | - (tbflags & (1 << SR_RB))) * 0x10; | |
2314 | + if (env->features != SH_FEATURE_SH2) | |
2315 | + ctx->gbank = ((tbflags & (1 << SR_MD)) && | |
2316 | + (tbflags & (1 << SR_RB))) * 0x10; | |
2317 | + else | |
2318 | + ctx->gbank = 0; | |
2261 | 2319 | ctx->fbank = tbflags & FPSCR_FR ? 0x10 : 0; |
2262 | 2320 | |
2263 | 2321 | if (tbflags & GUSA_MASK) { |