Revision | 2308ac2b7c0a49a0cf66ac4877871461e2cd00fc (tree) |
---|---|
Time | 2019-08-29 22:56:39 |
Author | Yoshinori Sato <ysato@user...> |
Commiter | Yoshinori Sato |
SH initial submit
@@ -77,8 +77,8 @@ int graphic_depth = 32; | ||
77 | 77 | #define QEMU_ARCH QEMU_ARCH_RX |
78 | 78 | #elif defined(TARGET_S390X) |
79 | 79 | #define QEMU_ARCH QEMU_ARCH_S390X |
80 | -#elif defined(TARGET_SH4) | |
81 | -#define QEMU_ARCH QEMU_ARCH_SH4 | |
80 | +#elif defined(TARGET_SH) | |
81 | +#define QEMU_ARCH QEMU_ARCH_SH | |
82 | 82 | #elif defined(TARGET_SPARC) |
83 | 83 | #define QEMU_ARCH QEMU_ARCH_SPARC |
84 | 84 | #elif defined(TARGET_TRICORE) |
@@ -7427,7 +7427,7 @@ target_name=$(echo $target | cut -d '-' -f 1) | ||
7427 | 7427 | target_bigendian="no" |
7428 | 7428 | |
7429 | 7429 | case "$target_name" in |
7430 | - armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppc64|ppc64abi32|s390x|sh2|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) | |
7430 | + armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppc64|ppc64abi32|s390x|sh|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) | |
7431 | 7431 | target_bigendian=yes |
7432 | 7432 | ;; |
7433 | 7433 | esac |
@@ -7600,9 +7600,13 @@ case "$target_name" in | ||
7600 | 7600 | target_compiler=$cross_cc_riscv64 |
7601 | 7601 | ;; |
7602 | 7602 | rx) |
7603 | - TARGET_ARCH=rx | |
7603 | + TARGET_ARCH=rx | |
7604 | + ;; | |
7605 | + sh) | |
7606 | + TARGET_ARCH=sh | |
7604 | 7607 | bflt="yes" |
7605 | - target_compiler=$cross_cc_rx | |
7608 | + gdb_xml_files="sh-core.xml sh2a-nofpu.xml sh2a-fpu.xml sh3.xml sh4-dfp.xml sh4-vfp.xml" | |
7609 | + target_compiler=$cross_cc_sh | |
7606 | 7610 | ;; |
7607 | 7611 | sh4|sh4eb) |
7608 | 7612 | TARGET_ARCH=sh4 |
@@ -56,7 +56,7 @@ source ppc/Kconfig | ||
56 | 56 | source riscv/Kconfig |
57 | 57 | source rx/Kconfig |
58 | 58 | source s390x/Kconfig |
59 | -source sh4/Kconfig | |
59 | +source sh/Kconfig | |
60 | 60 | source sparc/Kconfig |
61 | 61 | source sparc64/Kconfig |
62 | 62 | source tricore/Kconfig |
@@ -16,7 +16,7 @@ common-obj-$(CONFIG_CADENCE) += cadence_uart.o | ||
16 | 16 | obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o |
17 | 17 | obj-$(CONFIG_COLDFIRE) += mcf_uart.o |
18 | 18 | obj-$(CONFIG_OMAP) += omap_uart.o |
19 | -obj-$(CONFIG_SH4) += sh_serial.o | |
19 | +obj-$(CONFIG_SH) += sh_serial.o | |
20 | 20 | obj-$(CONFIG_PSERIES) += spapr_vty.o |
21 | 21 | obj-$(CONFIG_DIGIC) += digic-uart.o |
22 | 22 | obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o |
@@ -33,7 +33,9 @@ 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 sh7619_intc.o | |
36 | +obj-$(CONFIG_SH7750) += sh_intc.o | |
37 | +obj-$(CONFIG_SH7751) += sh_intc.o | |
38 | +obj-$(CONFIG_SH7619) += sh7619_intc.o | |
37 | 39 | obj-$(CONFIG_XICS) += xics.o |
38 | 40 | obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o |
39 | 41 | obj-$(CONFIG_XICS_KVM) += xics_kvm.o |
@@ -1,7 +1,7 @@ | ||
1 | 1 | /* |
2 | 2 | * SH7619 Interrupt controller |
3 | 3 | * |
4 | - * Copyright (c) 2018 Yoshinori Sato | |
4 | + * Copyright (c) 2019 Yoshinori Sato | |
5 | 5 | * |
6 | 6 | * This code is licensed under the GPL. |
7 | 7 | */ |
@@ -15,11 +15,31 @@ | ||
15 | 15 | #include "hw/intc/sh7619intc.h" |
16 | 16 | #include "qemu/error-report.h" |
17 | 17 | |
18 | +static int priority(SH7619INTCState *intc, int req) | |
19 | +{ | |
20 | + static const int map[] = { | |
21 | + 3, 2, 1, 0, -1, -1, -1, -1, | |
22 | + -1, -1, -1, -1, -1, -1, -1, -1, | |
23 | + 7, 6, 5, 4, 11, 10, 9, 8, | |
24 | + 15, 15, 15, 15, 14, 14, 14, 14, | |
25 | + 13, 13, 13, 13, 19, 18, -1, -1, | |
26 | + 23, 22, 21, 20, 27, -1, -1, -1, | |
27 | + -1, -1, -1, -1, -1, -1, -1, -1, | |
28 | + -1, -1, -1, -1, -1, -1, -1, -1, | |
29 | + }; | |
30 | + int offset; | |
31 | + int pos; | |
32 | + offset = map[req - 64] / 4; | |
33 | + pos = map[req - 64] % 4; | |
34 | + return (intc->ipr[offset] >> pos) & 0x000f; | |
35 | +} | |
36 | + | |
18 | 37 | static void sh7619intc_set_irq(void *opaque, int n_IRQ, int level) |
19 | 38 | { |
20 | 39 | SH7619INTCState *intc = opaque; |
21 | 40 | struct IRQSource *src; |
22 | 41 | int issue = 0; |
42 | + int p; | |
23 | 43 | |
24 | 44 | n_IRQ += 64; |
25 | 45 | if (n_IRQ < 64 || n_IRQ >= 128) { |
@@ -67,42 +87,21 @@ static void sh7619intc_set_irq(void *opaque, int n_IRQ, int level) | ||
67 | 87 | intc->irqsr |= (1 << (n_IRQ - 64)); |
68 | 88 | src->req = 1; |
69 | 89 | if(intc->req_irq < 0) { |
70 | - qemu_set_irq(intc->irq, 1); | |
90 | + p = priority(intc, n_IRQ); | |
91 | + qemu_set_irq(intc->irq, (p << 8) |n_IRQ); | |
71 | 92 | intc->req_irq = n_IRQ; |
72 | 93 | } |
73 | 94 | } |
74 | 95 | } |
75 | 96 | |
76 | -static int priority(SH7619INTCState *intc, int req) | |
97 | +static void intc_ack(void *opaque, int no, int request) | |
77 | 98 | { |
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); | |
99 | + SH7619INTCState *intc = SH7619INTC(opaque); | |
98 | 100 | int pri = priority(intc, intc->req_irq); |
99 | - int ret = -1; | |
100 | 101 | int i; |
101 | 102 | int pend; |
102 | 103 | |
103 | - if (pri > imask) { | |
104 | - *level = pri; | |
105 | - ret = intc->req_irq; | |
104 | + if (request == intc->req_irq) { | |
106 | 105 | intc->src[intc->req_irq - 64].req = 0; |
107 | 106 | intc->req_irq = -1; |
108 | 107 | } |
@@ -115,10 +114,9 @@ int sh2_intc_get_pending_vector(void *state, int imask, int *level) | ||
115 | 114 | } |
116 | 115 | } |
117 | 116 | if (pend >= 0) { |
118 | - qemu_set_irq(intc->irq, 1); | |
117 | + qemu_set_irq(intc->irq, (pri << 8) | pend); | |
119 | 118 | intc->req_irq = pend; |
120 | 119 | } |
121 | - return ret; | |
122 | 120 | } |
123 | 121 | |
124 | 122 | static void intc_write1(void *opaque, hwaddr addr, uint64_t val, unsigned size) |
@@ -315,6 +313,7 @@ static void sh7619intc_init(Object *obj) | ||
315 | 313 | sysbus_init_mmio(d, &intc->memory[1]); |
316 | 314 | |
317 | 315 | qdev_init_gpio_in(DEVICE(d), sh7619intc_set_irq, 64); |
316 | + qdev_init_gpio_in_named(DEVICE(d), intc_ack, "ack", 1); | |
318 | 317 | sysbus_init_irq(d, &intc->irq); |
319 | 318 | } |
320 | 319 |
@@ -0,0 +1,12 @@ | ||
1 | +config MS7619SE | |
2 | + bool | |
3 | + select SH7619 | |
4 | + select PFLASH_CFI01 | |
5 | + | |
6 | +config SH7619 | |
7 | + bool | |
8 | + select SH | |
9 | + select RENESAS_CMT | |
10 | + | |
11 | +config SH | |
12 | + bool |
@@ -0,0 +1,6 @@ | ||
1 | +obj-$(CONFIG_SH7750) += sh7750.o sh7750_regnames.o | |
2 | +obj-$(CONFIG_SH7751) += sh7750.o sh7750_regnames.o sh_pci.o | |
3 | +obj-$(CONFIG_SH7619) += sh7619.o | |
4 | +obj-$(CONFIG_R2D) += r2d.o | |
5 | +obj-$(CONFIG_SHIX) += shix.o | |
6 | +obj-$(CONFIG_MS7619SE) += ms7619se.o |
@@ -0,0 +1,166 @@ | ||
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/error-report.h" | |
27 | +#include "qemu/units.h" | |
28 | +#include "qapi/error.h" | |
29 | +#include "qemu-common.h" | |
30 | +#include "cpu.h" | |
31 | +#include "hw/hw.h" | |
32 | +#include "hw/sysbus.h" | |
33 | +#include "hw/loader.h" | |
34 | +#include "hw/sh/sh7619.h" | |
35 | +#include "sysemu/sysemu.h" | |
36 | +#include "sysemu/qtest.h" | |
37 | +#include "sysemu/device_tree.h" | |
38 | +#include "hw/boards.h" | |
39 | +#include "hw/block/flash.h" | |
40 | +#include "exec/address-spaces.h" | |
41 | +#include "exec/cpu-all.h" | |
42 | + | |
43 | +#define FLASH_BASE 0x00000000 | |
44 | +#define FLASH_SIZE 0x02000000 | |
45 | + | |
46 | +#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ | |
47 | +#define SDRAM_SIZE 0x04000000 | |
48 | + | |
49 | +#define BOOT_PARAMS_OFFSET 0x0001000 | |
50 | +/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */ | |
51 | +#define LINUX_LOAD_OFFSET 0x0800000 | |
52 | +#define INITRD_LOAD_OFFSET 0x1800000 | |
53 | + | |
54 | +static struct QEMU_PACKED | |
55 | +{ | |
56 | + int mount_root_rdonly; | |
57 | + int ramdisk_flags; | |
58 | + int orig_root_dev; | |
59 | + int loader_type; | |
60 | + int initrd_start; | |
61 | + int initrd_size; | |
62 | + | |
63 | + char pad[232]; | |
64 | + | |
65 | + char kernel_cmdline[256]; | |
66 | +} boot_params; | |
67 | + | |
68 | +static void ms7619se_init(MachineState *machine) | |
69 | +{ | |
70 | + SH7619State *s = g_new(SH7619State, 1); | |
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", 64 * MiB, | |
80 | + &error_fatal); | |
81 | + memory_region_add_subregion(sysmem, 0x0c000000, sdram); | |
82 | + dinfo = drive_get(IF_PFLASH, 0, 0); | |
83 | + pflash_cfi01_register(0x0, "ms7619se.flash", 16 * MiB, | |
84 | + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, | |
85 | + 64 * KiB, 2, 0x0000, 0x0102, 0x0e1c, 0x0f1e, | |
86 | + 0); | |
87 | + object_initialize_child(OBJECT(machine), "sh7619", s, | |
88 | + sizeof(SH7619State), TYPE_SH7619, | |
89 | + &error_fatal, NULL); | |
90 | + object_property_set_link(OBJECT(s), OBJECT(sysmem), | |
91 | + "memory", &error_abort); | |
92 | + | |
93 | + memset(&boot_params, 0, sizeof(boot_params)); | |
94 | + | |
95 | + if (kernel_filename) { | |
96 | + int kernel_size; | |
97 | + | |
98 | + kernel_size = load_image_targphys(kernel_filename, | |
99 | + SDRAM_BASE + LINUX_LOAD_OFFSET, | |
100 | + INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); | |
101 | + if (kernel_size < 0) { | |
102 | + error_report("could not load kernel '%s'\n", kernel_filename); | |
103 | + exit(1); | |
104 | + } | |
105 | + SUPERH_CPU(first_cpu)->env.pc = 0x80000000 + | |
106 | + SDRAM_BASE + LINUX_LOAD_OFFSET; | |
107 | + s->frqcr = 0x1103; | |
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 | + error_report("qemu: could not load initrd '%s'\n", | |
117 | + initrd_filename); | |
118 | + exit(1); | |
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 | + if (bios_name) { | |
137 | + load_image_targphys(bios_name, 0, 16 * MiB); | |
138 | + } | |
139 | + if (bios_name == NULL && kernel_filename == NULL && !qtest_enabled()) { | |
140 | + error_report("No bios or kernel specified"); | |
141 | + exit(1); | |
142 | + } | |
143 | + object_property_set_bool(OBJECT(s), true, "realized", &error_abort); | |
144 | +} | |
145 | + | |
146 | +static void ms7619se_class_init(ObjectClass *oc, void *data) | |
147 | +{ | |
148 | + MachineClass *mc = MACHINE_CLASS(oc); | |
149 | + | |
150 | + mc->desc = "SolutionEngine 7619"; | |
151 | + mc->init = ms7619se_init; | |
152 | + mc->default_cpu_type = TYPE_SH2_CPU; | |
153 | +} | |
154 | + | |
155 | +static const TypeInfo ms7619se_type = { | |
156 | + .name = MACHINE_TYPE_NAME("ms7619se"), | |
157 | + .parent = TYPE_MACHINE, | |
158 | + .class_init = ms7619se_class_init, | |
159 | +}; | |
160 | + | |
161 | +static void ms7619se_machine_init(void) | |
162 | +{ | |
163 | + type_register_static(&ms7619se_type); | |
164 | +} | |
165 | + | |
166 | +type_init(ms7619se_machine_init) |
@@ -0,0 +1,371 @@ | ||
1 | +/* | |
2 | + * Renesas SH7751R R2D-PLUS emulation | |
3 | + * | |
4 | + * Copyright (c) 2007 Magnus Damm | |
5 | + * Copyright (c) 2008 Paul Mundt | |
6 | + * | |
7 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | + * of this software and associated documentation files (the "Software"), to deal | |
9 | + * in the Software without restriction, including without limitation the rights | |
10 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | + * copies of the Software, and to permit persons to whom the Software is | |
12 | + * furnished to do so, subject to the following conditions: | |
13 | + * | |
14 | + * The above copyright notice and this permission notice shall be included in | |
15 | + * all copies or substantial portions of the Software. | |
16 | + * | |
17 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
20 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | + * THE SOFTWARE. | |
24 | + */ | |
25 | + | |
26 | +#include "qemu/osdep.h" | |
27 | +#include "qemu/units.h" | |
28 | +#include "qapi/error.h" | |
29 | +#include "cpu.h" | |
30 | +#include "hw/sysbus.h" | |
31 | +#include "hw/hw.h" | |
32 | +#include "hw/sh4/sh.h" | |
33 | +#include "sysemu/sysemu.h" | |
34 | +#include "hw/boards.h" | |
35 | +#include "hw/pci/pci.h" | |
36 | +#include "net/net.h" | |
37 | +#include "sh7750_regs.h" | |
38 | +#include "hw/ide.h" | |
39 | +#include "hw/loader.h" | |
40 | +#include "hw/usb.h" | |
41 | +#include "hw/block/flash.h" | |
42 | +#include "exec/address-spaces.h" | |
43 | + | |
44 | +#define FLASH_BASE 0x00000000 | |
45 | +#define FLASH_SIZE (16 * MiB) | |
46 | + | |
47 | +#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ | |
48 | +#define SDRAM_SIZE 0x04000000 | |
49 | + | |
50 | +#define SM501_VRAM_SIZE 0x800000 | |
51 | + | |
52 | +#define BOOT_PARAMS_OFFSET 0x0010000 | |
53 | +/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */ | |
54 | +#define LINUX_LOAD_OFFSET 0x0800000 | |
55 | +#define INITRD_LOAD_OFFSET 0x1800000 | |
56 | + | |
57 | +#define PA_IRLMSK 0x00 | |
58 | +#define PA_POWOFF 0x30 | |
59 | +#define PA_VERREG 0x32 | |
60 | +#define PA_OUTPORT 0x36 | |
61 | + | |
62 | +typedef struct { | |
63 | + uint16_t bcr; | |
64 | + uint16_t irlmsk; | |
65 | + uint16_t irlmon; | |
66 | + uint16_t cfctl; | |
67 | + uint16_t cfpow; | |
68 | + uint16_t dispctl; | |
69 | + uint16_t sdmpow; | |
70 | + uint16_t rtcce; | |
71 | + uint16_t pcicd; | |
72 | + uint16_t voyagerrts; | |
73 | + uint16_t cfrst; | |
74 | + uint16_t admrts; | |
75 | + uint16_t extrst; | |
76 | + uint16_t cfcdintclr; | |
77 | + uint16_t keyctlclr; | |
78 | + uint16_t pad0; | |
79 | + uint16_t pad1; | |
80 | + uint16_t verreg; | |
81 | + uint16_t inport; | |
82 | + uint16_t outport; | |
83 | + uint16_t bverreg; | |
84 | + | |
85 | +/* output pin */ | |
86 | + qemu_irq irl; | |
87 | + MemoryRegion iomem; | |
88 | +} r2d_fpga_t; | |
89 | + | |
90 | +enum r2d_fpga_irq { | |
91 | + PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T, | |
92 | + SDCARD, PCI_INTA, PCI_INTB, EXT, TP, | |
93 | + NR_IRQS | |
94 | +}; | |
95 | + | |
96 | +static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = { | |
97 | + [CF_IDE] = { 1, 1<<9 }, | |
98 | + [CF_CD] = { 2, 1<<8 }, | |
99 | + [PCI_INTA] = { 9, 1<<14 }, | |
100 | + [PCI_INTB] = { 10, 1<<13 }, | |
101 | + [PCI_INTC] = { 3, 1<<12 }, | |
102 | + [PCI_INTD] = { 0, 1<<11 }, | |
103 | + [SM501] = { 4, 1<<10 }, | |
104 | + [KEY] = { 5, 1<<6 }, | |
105 | + [RTC_A] = { 6, 1<<5 }, | |
106 | + [RTC_T] = { 7, 1<<4 }, | |
107 | + [SDCARD] = { 8, 1<<7 }, | |
108 | + [EXT] = { 11, 1<<0 }, | |
109 | + [TP] = { 12, 1<<15 }, | |
110 | +}; | |
111 | + | |
112 | +static void update_irl(r2d_fpga_t *fpga) | |
113 | +{ | |
114 | + int i, irl = 15; | |
115 | + for (i = 0; i < NR_IRQS; i++) | |
116 | + if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk) | |
117 | + if (irqtab[i].irl < irl) | |
118 | + irl = irqtab[i].irl; | |
119 | + qemu_set_irq(fpga->irl, irl ^ 15); | |
120 | +} | |
121 | + | |
122 | +static void r2d_fpga_irq_set(void *opaque, int n, int level) | |
123 | +{ | |
124 | + r2d_fpga_t *fpga = opaque; | |
125 | + if (level) | |
126 | + fpga->irlmon |= irqtab[n].msk; | |
127 | + else | |
128 | + fpga->irlmon &= ~irqtab[n].msk; | |
129 | + update_irl(fpga); | |
130 | +} | |
131 | + | |
132 | +static uint64_t r2d_fpga_read(void *opaque, hwaddr addr, unsigned int size) | |
133 | +{ | |
134 | + r2d_fpga_t *s = opaque; | |
135 | + | |
136 | + switch (addr) { | |
137 | + case PA_IRLMSK: | |
138 | + return s->irlmsk; | |
139 | + case PA_OUTPORT: | |
140 | + return s->outport; | |
141 | + case PA_POWOFF: | |
142 | + return 0x00; | |
143 | + case PA_VERREG: | |
144 | + return 0x10; | |
145 | + } | |
146 | + | |
147 | + return 0; | |
148 | +} | |
149 | + | |
150 | +static void | |
151 | +r2d_fpga_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) | |
152 | +{ | |
153 | + r2d_fpga_t *s = opaque; | |
154 | + | |
155 | + switch (addr) { | |
156 | + case PA_IRLMSK: | |
157 | + s->irlmsk = value; | |
158 | + update_irl(s); | |
159 | + break; | |
160 | + case PA_OUTPORT: | |
161 | + s->outport = value; | |
162 | + break; | |
163 | + case PA_POWOFF: | |
164 | + if (value & 1) { | |
165 | + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); | |
166 | + } | |
167 | + break; | |
168 | + case PA_VERREG: | |
169 | + /* Discard writes */ | |
170 | + break; | |
171 | + } | |
172 | +} | |
173 | + | |
174 | +static const MemoryRegionOps r2d_fpga_ops = { | |
175 | + .read = r2d_fpga_read, | |
176 | + .write = r2d_fpga_write, | |
177 | + .impl.min_access_size = 2, | |
178 | + .impl.max_access_size = 2, | |
179 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
180 | +}; | |
181 | + | |
182 | +static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem, | |
183 | + hwaddr base, qemu_irq irl) | |
184 | +{ | |
185 | + r2d_fpga_t *s; | |
186 | + | |
187 | + s = g_malloc0(sizeof(r2d_fpga_t)); | |
188 | + | |
189 | + s->irl = irl; | |
190 | + | |
191 | + memory_region_init_io(&s->iomem, NULL, &r2d_fpga_ops, s, "r2d-fpga", 0x40); | |
192 | + memory_region_add_subregion(sysmem, base, &s->iomem); | |
193 | + return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS); | |
194 | +} | |
195 | + | |
196 | +typedef struct ResetData { | |
197 | + SuperHCPU *cpu; | |
198 | + uint32_t vector; | |
199 | +} ResetData; | |
200 | + | |
201 | +static void main_cpu_reset(void *opaque) | |
202 | +{ | |
203 | + ResetData *s = (ResetData *)opaque; | |
204 | + CPUSH4State *env = &s->cpu->env; | |
205 | + | |
206 | + cpu_reset(CPU(s->cpu)); | |
207 | + env->pc = s->vector; | |
208 | +} | |
209 | + | |
210 | +static struct QEMU_PACKED | |
211 | +{ | |
212 | + int mount_root_rdonly; | |
213 | + int ramdisk_flags; | |
214 | + int orig_root_dev; | |
215 | + int loader_type; | |
216 | + int initrd_start; | |
217 | + int initrd_size; | |
218 | + | |
219 | + char pad[232]; | |
220 | + | |
221 | + char kernel_cmdline[256] QEMU_NONSTRING; | |
222 | +} boot_params; | |
223 | + | |
224 | +static void r2d_init(MachineState *machine) | |
225 | +{ | |
226 | + const char *kernel_filename = machine->kernel_filename; | |
227 | + const char *kernel_cmdline = machine->kernel_cmdline; | |
228 | + const char *initrd_filename = machine->initrd_filename; | |
229 | + SuperHCPU *cpu; | |
230 | + CPUSH4State *env; | |
231 | + ResetData *reset_info; | |
232 | + struct SH7750State *s; | |
233 | + MemoryRegion *sdram = g_new(MemoryRegion, 1); | |
234 | + qemu_irq *irq; | |
235 | + DriveInfo *dinfo; | |
236 | + int i; | |
237 | + DeviceState *dev; | |
238 | + SysBusDevice *busdev; | |
239 | + MemoryRegion *address_space_mem = get_system_memory(); | |
240 | + PCIBus *pci_bus; | |
241 | + | |
242 | + cpu = SUPERH_CPU(cpu_create(machine->cpu_type)); | |
243 | + env = &cpu->env; | |
244 | + | |
245 | + reset_info = g_malloc0(sizeof(ResetData)); | |
246 | + reset_info->cpu = cpu; | |
247 | + reset_info->vector = env->pc; | |
248 | + qemu_register_reset(main_cpu_reset, reset_info); | |
249 | + | |
250 | + /* Allocate memory space */ | |
251 | + memory_region_init_ram(sdram, NULL, "r2d.sdram", SDRAM_SIZE, &error_fatal); | |
252 | + memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram); | |
253 | + /* Register peripherals */ | |
254 | + s = sh7750_init(cpu, address_space_mem); | |
255 | + irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s)); | |
256 | + | |
257 | + dev = qdev_create(NULL, "sh_pci"); | |
258 | + busdev = SYS_BUS_DEVICE(dev); | |
259 | + qdev_init_nofail(dev); | |
260 | + pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); | |
261 | + sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000)); | |
262 | + sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000)); | |
263 | + sysbus_connect_irq(busdev, 0, irq[PCI_INTA]); | |
264 | + sysbus_connect_irq(busdev, 1, irq[PCI_INTB]); | |
265 | + sysbus_connect_irq(busdev, 2, irq[PCI_INTC]); | |
266 | + sysbus_connect_irq(busdev, 3, irq[PCI_INTD]); | |
267 | + | |
268 | + dev = qdev_create(NULL, "sysbus-sm501"); | |
269 | + busdev = SYS_BUS_DEVICE(dev); | |
270 | + qdev_prop_set_uint32(dev, "vram-size", SM501_VRAM_SIZE); | |
271 | + qdev_prop_set_uint32(dev, "base", 0x10000000); | |
272 | + qdev_prop_set_ptr(dev, "chr-state", serial_hd(2)); | |
273 | + qdev_init_nofail(dev); | |
274 | + sysbus_mmio_map(busdev, 0, 0x10000000); | |
275 | + sysbus_mmio_map(busdev, 1, 0x13e00000); | |
276 | + sysbus_connect_irq(busdev, 0, irq[SM501]); | |
277 | + | |
278 | + /* onboard CF (True IDE mode, Master only). */ | |
279 | + dinfo = drive_get(IF_IDE, 0, 0); | |
280 | + dev = qdev_create(NULL, "mmio-ide"); | |
281 | + busdev = SYS_BUS_DEVICE(dev); | |
282 | + sysbus_connect_irq(busdev, 0, irq[CF_IDE]); | |
283 | + qdev_prop_set_uint32(dev, "shift", 1); | |
284 | + qdev_init_nofail(dev); | |
285 | + sysbus_mmio_map(busdev, 0, 0x14001000); | |
286 | + sysbus_mmio_map(busdev, 1, 0x1400080c); | |
287 | + mmio_ide_init_drives(dev, dinfo, NULL); | |
288 | + | |
289 | + /* | |
290 | + * Onboard flash memory | |
291 | + * According to the old board user document in Japanese (under | |
292 | + * NDA) what is referred to as FROM (Area0) is connected via a | |
293 | + * 32-bit bus and CS0 to CN8. The docs mention a Cypress | |
294 | + * S29PL127J60TFI130 chipsset. Per the 'S29PL-J 002-00615 | |
295 | + * Rev. *E' datasheet, it is a 128Mbit NOR parallel flash | |
296 | + * addressable in words of 16bit. | |
297 | + */ | |
298 | + dinfo = drive_get(IF_PFLASH, 0, 0); | |
299 | + pflash_cfi02_register(0x0, "r2d.flash", FLASH_SIZE, | |
300 | + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, | |
301 | + 64 * KiB, 1, 2, 0x0001, 0x227e, 0x2220, 0x2200, | |
302 | + 0x555, 0x2aa, 0); | |
303 | + | |
304 | + /* NIC: rtl8139 on-board, and 2 slots. */ | |
305 | + for (i = 0; i < nb_nics; i++) | |
306 | + pci_nic_init_nofail(&nd_table[i], pci_bus, | |
307 | + "rtl8139", i==0 ? "2" : NULL); | |
308 | + | |
309 | + /* USB keyboard */ | |
310 | + usb_create_simple(usb_bus_find(-1), "usb-kbd"); | |
311 | + | |
312 | + /* Todo: register on board registers */ | |
313 | + memset(&boot_params, 0, sizeof(boot_params)); | |
314 | + | |
315 | + if (kernel_filename) { | |
316 | + int kernel_size; | |
317 | + | |
318 | + kernel_size = load_image_targphys(kernel_filename, | |
319 | + SDRAM_BASE + LINUX_LOAD_OFFSET, | |
320 | + INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); | |
321 | + if (kernel_size < 0) { | |
322 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); | |
323 | + exit(1); | |
324 | + } | |
325 | + | |
326 | + /* initialization which should be done by firmware */ | |
327 | + address_space_stl(&address_space_memory, SH7750_BCR1, 1 << 3, | |
328 | + MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 SDRAM */ | |
329 | + address_space_stw(&address_space_memory, SH7750_BCR2, 3 << (3 * 2), | |
330 | + MEMTXATTRS_UNSPECIFIED, NULL); /* cs3 32bit */ | |
331 | + reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */ | |
332 | + } | |
333 | + | |
334 | + if (initrd_filename) { | |
335 | + int initrd_size; | |
336 | + | |
337 | + initrd_size = load_image_targphys(initrd_filename, | |
338 | + SDRAM_BASE + INITRD_LOAD_OFFSET, | |
339 | + SDRAM_SIZE - INITRD_LOAD_OFFSET); | |
340 | + | |
341 | + if (initrd_size < 0) { | |
342 | + fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename); | |
343 | + exit(1); | |
344 | + } | |
345 | + | |
346 | + /* initialization which should be done by firmware */ | |
347 | + boot_params.loader_type = tswap32(1); | |
348 | + boot_params.initrd_start = tswap32(INITRD_LOAD_OFFSET); | |
349 | + boot_params.initrd_size = tswap32(initrd_size); | |
350 | + } | |
351 | + | |
352 | + if (kernel_cmdline) { | |
353 | + /* I see no evidence that this .kernel_cmdline buffer requires | |
354 | + NUL-termination, so using strncpy should be ok. */ | |
355 | + strncpy(boot_params.kernel_cmdline, kernel_cmdline, | |
356 | + sizeof(boot_params.kernel_cmdline)); | |
357 | + } | |
358 | + | |
359 | + rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params), | |
360 | + SDRAM_BASE + BOOT_PARAMS_OFFSET); | |
361 | +} | |
362 | + | |
363 | +static void r2d_machine_init(MachineClass *mc) | |
364 | +{ | |
365 | + mc->desc = "r2d-plus board"; | |
366 | + mc->init = r2d_init; | |
367 | + mc->block_default_type = IF_IDE; | |
368 | + mc->default_cpu_type = TYPE_SH7751R_CPU; | |
369 | +} | |
370 | + | |
371 | +DEFINE_MACHINE("r2d", r2d_machine_init) |
@@ -0,0 +1,203 @@ | ||
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/sh/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 | + int irq = request & 0xff; | |
53 | + | |
54 | + if (irq) { | |
55 | + cpu->env.req_irq = irq; | |
56 | + cpu->env.req_ipl = (request >> 8) & 0x0f; | |
57 | + cpu_interrupt(cs, CPU_INTERRUPT_HARD); | |
58 | + } else { | |
59 | + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); | |
60 | + } | |
61 | +} | |
62 | + | |
63 | +static SH7619INTCState *register_intc(SH7619State *s) | |
64 | +{ | |
65 | + SysBusDevice *intc; | |
66 | + int i; | |
67 | + | |
68 | + intc = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_SH7619INTC)); | |
69 | + sysbus_mmio_map(intc, 0, 0xf8080000); | |
70 | + sysbus_mmio_map(intc, 1, 0xf8140000); | |
71 | + for (i = 0; i < 64; i++) | |
72 | + s->irq[i] = qdev_get_gpio_in(DEVICE(intc), i); | |
73 | + | |
74 | + qdev_init_nofail(DEVICE(intc)); | |
75 | + sysbus_connect_irq(SYS_BUS_DEVICE(intc), 0, | |
76 | + qdev_get_gpio_in(DEVICE(s), 0)); | |
77 | + | |
78 | + return SH7619INTC(intc); | |
79 | +} | |
80 | + | |
81 | +static RCMTState *register_cmt(SH7619State *s) | |
82 | +{ | |
83 | + SysBusDevice *cmt; | |
84 | + int i; | |
85 | + | |
86 | + cmt = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_RENESAS_CMT)); | |
87 | + sysbus_mmio_map(cmt, 0, 0xf84a0070); | |
88 | + qdev_prop_set_uint64(DEVICE(cmt), "input-freq", 31250000); | |
89 | + | |
90 | + qdev_init_nofail(DEVICE(cmt)); | |
91 | + for (i = 0; i < 2; i++) | |
92 | + sysbus_connect_irq(cmt, i, s->irq[(86 + i) - 64]); | |
93 | + | |
94 | + return RCMT(cmt); | |
95 | +} | |
96 | + | |
97 | +static void cache_write(void *opaque, hwaddr addr, | |
98 | + uint64_t mem_value, unsigned size) | |
99 | +{ | |
100 | +} | |
101 | + | |
102 | +static uint64_t cache_read(void *opaque, hwaddr addr, | |
103 | + unsigned size) | |
104 | +{ | |
105 | + return 0; | |
106 | +} | |
107 | + | |
108 | + | |
109 | +static const MemoryRegionOps cache_ops = { | |
110 | + .read = cache_read, | |
111 | + .write = cache_write, | |
112 | + .endianness = DEVICE_BIG_ENDIAN, | |
113 | +}; | |
114 | + | |
115 | +static void cpg_write(void *opaque, hwaddr addr, | |
116 | + uint64_t mem_value, unsigned size) | |
117 | +{ | |
118 | + SH7619State *s = opaque; | |
119 | + s->frqcr = mem_value; | |
120 | +} | |
121 | + | |
122 | +static uint64_t cpg_read(void *opaque, hwaddr addr, | |
123 | + unsigned size) | |
124 | +{ | |
125 | + SH7619State *s = opaque; | |
126 | + return s->frqcr; | |
127 | +} | |
128 | + | |
129 | + | |
130 | +static const MemoryRegionOps cpg_ops = { | |
131 | + .read = cpg_read, | |
132 | + .write = cpg_write, | |
133 | + .endianness = DEVICE_BIG_ENDIAN, | |
134 | + .impl = { | |
135 | + .min_access_size = 2, | |
136 | + .max_access_size = 2, | |
137 | + }, | |
138 | +}; | |
139 | + | |
140 | +#define SCIF(no) \ | |
141 | + sh_serial_init(s->sysmem, 0xf8400000 + no * 0x00010000, \ | |
142 | + SH_SERIAL_FEAT_SCIF, \ | |
143 | + 31250000, serial_hd(no), \ | |
144 | + s->irq[SCIF ## no ## _ERI], \ | |
145 | + s->irq[SCIF ## no ## _RXI], \ | |
146 | + s->irq[SCIF ## no ## _TXI], \ | |
147 | + NULL, \ | |
148 | + s->irq[SCIF ## no ## _BRI]) | |
149 | + | |
150 | +static void sh7619_reallize(DeviceState *dev, Error **errp) | |
151 | +{ | |
152 | + SH7619State *s = SH7619State(dev); | |
153 | + | |
154 | + memory_region_init_io(&s->cache, NULL, &cache_ops, | |
155 | + NULL, "cache", 0x02000000); | |
156 | + memory_region_add_subregion(s->sysmem, 0xf0000000, &s->cache); | |
157 | + memory_region_init_io(&s->cpg, NULL, &cpg_ops, | |
158 | + s, "cpg", 0x00000002); | |
159 | + memory_region_add_subregion(s->sysmem, 0xf815ff80, &s->cpg); | |
160 | + memory_region_init_ram(&s->uram, NULL, "uram", 0x4000, NULL); | |
161 | + memory_region_add_subregion(s->sysmem, 0xe55fc000, &s->uram); | |
162 | + | |
163 | + /* Initialize CPU */ | |
164 | + object_initialize_child(OBJECT(s), "cpu", &s->cpu, sizeof(SuperHCPU), | |
165 | + TYPE_SH2_CPU, errp, NULL); | |
166 | + s->cpu.env.features = SH_FEATURE_SH2; | |
167 | + object_property_set_bool(OBJECT(&s->cpu), true, "realized", errp); | |
168 | + qdev_init_gpio_in(DEVICE(s), sh7619_set_irq, 1); | |
169 | + s->intc = register_intc(s); | |
170 | + s->cpu.env.ack = qdev_get_gpio_in_named(DEVICE(s->intc), "ack", 0); | |
171 | + register_cmt(s); | |
172 | + SCIF(0); | |
173 | + SCIF(1); | |
174 | + SCIF(2); | |
175 | +} | |
176 | + | |
177 | +static Property sh7619_properties[] = { | |
178 | + DEFINE_PROP_LINK("memory", SH7619State, sysmem, TYPE_MEMORY_REGION, | |
179 | + MemoryRegion *), | |
180 | + DEFINE_PROP_END_OF_LIST(), | |
181 | +}; | |
182 | + | |
183 | +static void sh7619_class_init(ObjectClass *klass, void *data) | |
184 | +{ | |
185 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
186 | + | |
187 | + dc->realize = sh7619_reallize; | |
188 | + dc->props = sh7619_properties; | |
189 | +} | |
190 | + | |
191 | +static const TypeInfo sh7619_info = { | |
192 | + .name = TYPE_SH7619, | |
193 | + .parent = TYPE_SYS_BUS_DEVICE, | |
194 | + .instance_size = sizeof(SH7619State), | |
195 | + .class_init = sh7619_class_init, | |
196 | +}; | |
197 | + | |
198 | +static void sh7619_register_types(void) | |
199 | +{ | |
200 | + type_register_static(&sh7619_info); | |
201 | +} | |
202 | + | |
203 | +type_init(sh7619_register_types) |
@@ -0,0 +1,760 @@ | ||
1 | +/* | |
2 | + * SH7750 device | |
3 | + * | |
4 | + * Copyright (c) 2007 Magnus Damm | |
5 | + * Copyright (c) 2005 Samuel Tardieu | |
6 | + * | |
7 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | + * of this software and associated documentation files (the "Software"), to deal | |
9 | + * in the Software without restriction, including without limitation the rights | |
10 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | + * copies of the Software, and to permit persons to whom the Software is | |
12 | + * furnished to do so, subject to the following conditions: | |
13 | + * | |
14 | + * The above copyright notice and this permission notice shall be included in | |
15 | + * all copies or substantial portions of the Software. | |
16 | + * | |
17 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
20 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | + * THE SOFTWARE. | |
24 | + */ | |
25 | +#include "qemu/osdep.h" | |
26 | +#include "hw/hw.h" | |
27 | +#include "hw/sh4/sh.h" | |
28 | +#include "sysemu/sysemu.h" | |
29 | +#include "sh7750_regs.h" | |
30 | +#include "sh7750_regnames.h" | |
31 | +#include "hw/sh4/sh_intc.h" | |
32 | +#include "cpu.h" | |
33 | +#include "exec/exec-all.h" | |
34 | + | |
35 | +#define NB_DEVICES 4 | |
36 | + | |
37 | +typedef struct SH7750State { | |
38 | + MemoryRegion iomem; | |
39 | + MemoryRegion iomem_1f0; | |
40 | + MemoryRegion iomem_ff0; | |
41 | + MemoryRegion iomem_1f8; | |
42 | + MemoryRegion iomem_ff8; | |
43 | + MemoryRegion iomem_1fc; | |
44 | + MemoryRegion iomem_ffc; | |
45 | + MemoryRegion mmct_iomem; | |
46 | + /* CPU */ | |
47 | + SuperHCPU *cpu; | |
48 | + /* Peripheral frequency in Hz */ | |
49 | + uint32_t periph_freq; | |
50 | + /* SDRAM controller */ | |
51 | + uint32_t bcr1; | |
52 | + uint16_t bcr2; | |
53 | + uint16_t bcr3; | |
54 | + uint32_t bcr4; | |
55 | + uint16_t rfcr; | |
56 | + /* PCMCIA controller */ | |
57 | + uint16_t pcr; | |
58 | + /* IO ports */ | |
59 | + uint16_t gpioic; | |
60 | + uint32_t pctra; | |
61 | + uint32_t pctrb; | |
62 | + uint16_t portdira; /* Cached */ | |
63 | + uint16_t portpullupa; /* Cached */ | |
64 | + uint16_t portdirb; /* Cached */ | |
65 | + uint16_t portpullupb; /* Cached */ | |
66 | + uint16_t pdtra; | |
67 | + uint16_t pdtrb; | |
68 | + uint16_t periph_pdtra; /* Imposed by the peripherals */ | |
69 | + uint16_t periph_portdira; /* Direction seen from the peripherals */ | |
70 | + uint16_t periph_pdtrb; /* Imposed by the peripherals */ | |
71 | + uint16_t periph_portdirb; /* Direction seen from the peripherals */ | |
72 | + sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ | |
73 | + | |
74 | + /* Cache */ | |
75 | + uint32_t ccr; | |
76 | + | |
77 | + struct intc_desc intc; | |
78 | +} SH7750State; | |
79 | + | |
80 | +static inline int has_bcr3_and_bcr4(SH7750State * s) | |
81 | +{ | |
82 | + return s->cpu->env.features & FEATURE_R; | |
83 | +} | |
84 | +/********************************************************************** | |
85 | + I/O ports | |
86 | +**********************************************************************/ | |
87 | + | |
88 | +int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device) | |
89 | +{ | |
90 | + int i; | |
91 | + | |
92 | + for (i = 0; i < NB_DEVICES; i++) { | |
93 | + if (s->devices[i] == NULL) { | |
94 | + s->devices[i] = device; | |
95 | + return 0; | |
96 | + } | |
97 | + } | |
98 | + return -1; | |
99 | +} | |
100 | + | |
101 | +static uint16_t portdir(uint32_t v) | |
102 | +{ | |
103 | +#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n)) | |
104 | + return | |
105 | + EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) | | |
106 | + EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) | | |
107 | + EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) | | |
108 | + EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) | | |
109 | + EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) | | |
110 | + EVENPORTMASK(0); | |
111 | +} | |
112 | + | |
113 | +static uint16_t portpullup(uint32_t v) | |
114 | +{ | |
115 | +#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n)) | |
116 | + return | |
117 | + ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) | | |
118 | + ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) | | |
119 | + ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) | | |
120 | + ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) | | |
121 | + ODDPORTMASK(1) | ODDPORTMASK(0); | |
122 | +} | |
123 | + | |
124 | +static uint16_t porta_lines(SH7750State * s) | |
125 | +{ | |
126 | + return (s->portdira & s->pdtra) | /* CPU */ | |
127 | + (s->periph_portdira & s->periph_pdtra) | /* Peripherals */ | |
128 | + (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */ | |
129 | +} | |
130 | + | |
131 | +static uint16_t portb_lines(SH7750State * s) | |
132 | +{ | |
133 | + return (s->portdirb & s->pdtrb) | /* CPU */ | |
134 | + (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */ | |
135 | + (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */ | |
136 | +} | |
137 | + | |
138 | +static void gen_port_interrupts(SH7750State * s) | |
139 | +{ | |
140 | + /* XXXXX interrupts not generated */ | |
141 | +} | |
142 | + | |
143 | +static void porta_changed(SH7750State * s, uint16_t prev) | |
144 | +{ | |
145 | + uint16_t currenta, changes; | |
146 | + int i, r = 0; | |
147 | + | |
148 | +#if 0 | |
149 | + fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n", | |
150 | + prev, porta_lines(s)); | |
151 | + fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra); | |
152 | +#endif | |
153 | + currenta = porta_lines(s); | |
154 | + if (currenta == prev) | |
155 | + return; | |
156 | + changes = currenta ^ prev; | |
157 | + | |
158 | + for (i = 0; i < NB_DEVICES; i++) { | |
159 | + if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) { | |
160 | + r |= s->devices[i]->port_change_cb(currenta, portb_lines(s), | |
161 | + &s->periph_pdtra, | |
162 | + &s->periph_portdira, | |
163 | + &s->periph_pdtrb, | |
164 | + &s->periph_portdirb); | |
165 | + } | |
166 | + } | |
167 | + | |
168 | + if (r) | |
169 | + gen_port_interrupts(s); | |
170 | +} | |
171 | + | |
172 | +static void portb_changed(SH7750State * s, uint16_t prev) | |
173 | +{ | |
174 | + uint16_t currentb, changes; | |
175 | + int i, r = 0; | |
176 | + | |
177 | + currentb = portb_lines(s); | |
178 | + if (currentb == prev) | |
179 | + return; | |
180 | + changes = currentb ^ prev; | |
181 | + | |
182 | + for (i = 0; i < NB_DEVICES; i++) { | |
183 | + if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) { | |
184 | + r |= s->devices[i]->port_change_cb(portb_lines(s), currentb, | |
185 | + &s->periph_pdtra, | |
186 | + &s->periph_portdira, | |
187 | + &s->periph_pdtrb, | |
188 | + &s->periph_portdirb); | |
189 | + } | |
190 | + } | |
191 | + | |
192 | + if (r) | |
193 | + gen_port_interrupts(s); | |
194 | +} | |
195 | + | |
196 | +/********************************************************************** | |
197 | + Memory | |
198 | +**********************************************************************/ | |
199 | + | |
200 | +static void error_access(const char *kind, hwaddr addr) | |
201 | +{ | |
202 | + fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n", | |
203 | + kind, regname(addr), addr); | |
204 | +} | |
205 | + | |
206 | +static void ignore_access(const char *kind, hwaddr addr) | |
207 | +{ | |
208 | + fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n", | |
209 | + kind, regname(addr), addr); | |
210 | +} | |
211 | + | |
212 | +static uint32_t sh7750_mem_readb(void *opaque, hwaddr addr) | |
213 | +{ | |
214 | + switch (addr) { | |
215 | + default: | |
216 | + error_access("byte read", addr); | |
217 | + abort(); | |
218 | + } | |
219 | +} | |
220 | + | |
221 | +static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr) | |
222 | +{ | |
223 | + SH7750State *s = opaque; | |
224 | + | |
225 | + switch (addr) { | |
226 | + case SH7750_BCR2_A7: | |
227 | + return s->bcr2; | |
228 | + case SH7750_BCR3_A7: | |
229 | + if(!has_bcr3_and_bcr4(s)) | |
230 | + error_access("word read", addr); | |
231 | + return s->bcr3; | |
232 | + case SH7750_FRQCR_A7: | |
233 | + return 0; | |
234 | + case SH7750_PCR_A7: | |
235 | + return s->pcr; | |
236 | + case SH7750_RFCR_A7: | |
237 | + fprintf(stderr, | |
238 | + "Read access to refresh count register, incrementing\n"); | |
239 | + return s->rfcr++; | |
240 | + case SH7750_PDTRA_A7: | |
241 | + return porta_lines(s); | |
242 | + case SH7750_PDTRB_A7: | |
243 | + return portb_lines(s); | |
244 | + case SH7750_RTCOR_A7: | |
245 | + case SH7750_RTCNT_A7: | |
246 | + case SH7750_RTCSR_A7: | |
247 | + ignore_access("word read", addr); | |
248 | + return 0; | |
249 | + default: | |
250 | + error_access("word read", addr); | |
251 | + abort(); | |
252 | + } | |
253 | +} | |
254 | + | |
255 | +static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) | |
256 | +{ | |
257 | + SH7750State *s = opaque; | |
258 | + SuperHCPUClass *scc; | |
259 | + | |
260 | + switch (addr) { | |
261 | + case SH7750_BCR1_A7: | |
262 | + return s->bcr1; | |
263 | + case SH7750_BCR4_A7: | |
264 | + if(!has_bcr3_and_bcr4(s)) | |
265 | + error_access("long read", addr); | |
266 | + return s->bcr4; | |
267 | + case SH7750_WCR1_A7: | |
268 | + case SH7750_WCR2_A7: | |
269 | + case SH7750_WCR3_A7: | |
270 | + case SH7750_MCR_A7: | |
271 | + ignore_access("long read", addr); | |
272 | + return 0; | |
273 | + case SH7750_MMUCR_A7: | |
274 | + return s->cpu->env.mmucr; | |
275 | + case SH7750_PTEH_A7: | |
276 | + return s->cpu->env.pteh; | |
277 | + case SH7750_PTEL_A7: | |
278 | + return s->cpu->env.ptel; | |
279 | + case SH7750_TTB_A7: | |
280 | + return s->cpu->env.ttb; | |
281 | + case SH7750_TEA_A7: | |
282 | + return s->cpu->env.tea; | |
283 | + case SH7750_TRA_A7: | |
284 | + return s->cpu->env.tra; | |
285 | + case SH7750_EXPEVT_A7: | |
286 | + return s->cpu->env.expevt; | |
287 | + case SH7750_INTEVT_A7: | |
288 | + return s->cpu->env.intevt; | |
289 | + case SH7750_CCR_A7: | |
290 | + return s->ccr; | |
291 | + case 0x1f000030: /* Processor version */ | |
292 | + scc = SUPERH_CPU_GET_CLASS(s->cpu); | |
293 | + return scc->pvr; | |
294 | + case 0x1f000040: /* Cache version */ | |
295 | + scc = SUPERH_CPU_GET_CLASS(s->cpu); | |
296 | + return scc->cvr; | |
297 | + case 0x1f000044: /* Processor revision */ | |
298 | + scc = SUPERH_CPU_GET_CLASS(s->cpu); | |
299 | + return scc->prr; | |
300 | + default: | |
301 | + error_access("long read", addr); | |
302 | + abort(); | |
303 | + } | |
304 | +} | |
305 | + | |
306 | +#define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \ | |
307 | + && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB)) | |
308 | +static void sh7750_mem_writeb(void *opaque, hwaddr addr, | |
309 | + uint32_t mem_value) | |
310 | +{ | |
311 | + | |
312 | + if (is_in_sdrmx(addr, 2) || is_in_sdrmx(addr, 3)) { | |
313 | + ignore_access("byte write", addr); | |
314 | + return; | |
315 | + } | |
316 | + | |
317 | + error_access("byte write", addr); | |
318 | + abort(); | |
319 | +} | |
320 | + | |
321 | +static void sh7750_mem_writew(void *opaque, hwaddr addr, | |
322 | + uint32_t mem_value) | |
323 | +{ | |
324 | + SH7750State *s = opaque; | |
325 | + uint16_t temp; | |
326 | + | |
327 | + switch (addr) { | |
328 | + /* SDRAM controller */ | |
329 | + case SH7750_BCR2_A7: | |
330 | + s->bcr2 = mem_value; | |
331 | + return; | |
332 | + case SH7750_BCR3_A7: | |
333 | + if(!has_bcr3_and_bcr4(s)) | |
334 | + error_access("word write", addr); | |
335 | + s->bcr3 = mem_value; | |
336 | + return; | |
337 | + case SH7750_PCR_A7: | |
338 | + s->pcr = mem_value; | |
339 | + return; | |
340 | + case SH7750_RTCNT_A7: | |
341 | + case SH7750_RTCOR_A7: | |
342 | + case SH7750_RTCSR_A7: | |
343 | + ignore_access("word write", addr); | |
344 | + return; | |
345 | + /* IO ports */ | |
346 | + case SH7750_PDTRA_A7: | |
347 | + temp = porta_lines(s); | |
348 | + s->pdtra = mem_value; | |
349 | + porta_changed(s, temp); | |
350 | + return; | |
351 | + case SH7750_PDTRB_A7: | |
352 | + temp = portb_lines(s); | |
353 | + s->pdtrb = mem_value; | |
354 | + portb_changed(s, temp); | |
355 | + return; | |
356 | + case SH7750_RFCR_A7: | |
357 | + fprintf(stderr, "Write access to refresh count register\n"); | |
358 | + s->rfcr = mem_value; | |
359 | + return; | |
360 | + case SH7750_GPIOIC_A7: | |
361 | + s->gpioic = mem_value; | |
362 | + if (mem_value != 0) { | |
363 | + fprintf(stderr, "I/O interrupts not implemented\n"); | |
364 | + abort(); | |
365 | + } | |
366 | + return; | |
367 | + default: | |
368 | + error_access("word write", addr); | |
369 | + abort(); | |
370 | + } | |
371 | +} | |
372 | + | |
373 | +static void sh7750_mem_writel(void *opaque, hwaddr addr, | |
374 | + uint32_t mem_value) | |
375 | +{ | |
376 | + SH7750State *s = opaque; | |
377 | + uint16_t temp; | |
378 | + | |
379 | + switch (addr) { | |
380 | + /* SDRAM controller */ | |
381 | + case SH7750_BCR1_A7: | |
382 | + s->bcr1 = mem_value; | |
383 | + return; | |
384 | + case SH7750_BCR4_A7: | |
385 | + if(!has_bcr3_and_bcr4(s)) | |
386 | + error_access("long write", addr); | |
387 | + s->bcr4 = mem_value; | |
388 | + return; | |
389 | + case SH7750_WCR1_A7: | |
390 | + case SH7750_WCR2_A7: | |
391 | + case SH7750_WCR3_A7: | |
392 | + case SH7750_MCR_A7: | |
393 | + ignore_access("long write", addr); | |
394 | + return; | |
395 | + /* IO ports */ | |
396 | + case SH7750_PCTRA_A7: | |
397 | + temp = porta_lines(s); | |
398 | + s->pctra = mem_value; | |
399 | + s->portdira = portdir(mem_value); | |
400 | + s->portpullupa = portpullup(mem_value); | |
401 | + porta_changed(s, temp); | |
402 | + return; | |
403 | + case SH7750_PCTRB_A7: | |
404 | + temp = portb_lines(s); | |
405 | + s->pctrb = mem_value; | |
406 | + s->portdirb = portdir(mem_value); | |
407 | + s->portpullupb = portpullup(mem_value); | |
408 | + portb_changed(s, temp); | |
409 | + return; | |
410 | + case SH7750_MMUCR_A7: | |
411 | + if (mem_value & MMUCR_TI) { | |
412 | + cpu_sh4_invalidate_tlb(&s->cpu->env); | |
413 | + } | |
414 | + s->cpu->env.mmucr = mem_value & ~MMUCR_TI; | |
415 | + return; | |
416 | + case SH7750_PTEH_A7: | |
417 | + /* If asid changes, clear all registered tlb entries. */ | |
418 | + if ((s->cpu->env.pteh & 0xff) != (mem_value & 0xff)) { | |
419 | + tlb_flush(CPU(s->cpu)); | |
420 | + } | |
421 | + s->cpu->env.pteh = mem_value; | |
422 | + return; | |
423 | + case SH7750_PTEL_A7: | |
424 | + s->cpu->env.ptel = mem_value; | |
425 | + return; | |
426 | + case SH7750_PTEA_A7: | |
427 | + s->cpu->env.ptea = mem_value & 0x0000000f; | |
428 | + return; | |
429 | + case SH7750_TTB_A7: | |
430 | + s->cpu->env.ttb = mem_value; | |
431 | + return; | |
432 | + case SH7750_TEA_A7: | |
433 | + s->cpu->env.tea = mem_value; | |
434 | + return; | |
435 | + case SH7750_TRA_A7: | |
436 | + s->cpu->env.tra = mem_value & 0x000007ff; | |
437 | + return; | |
438 | + case SH7750_EXPEVT_A7: | |
439 | + s->cpu->env.expevt = mem_value & 0x000007ff; | |
440 | + return; | |
441 | + case SH7750_INTEVT_A7: | |
442 | + s->cpu->env.intevt = mem_value & 0x000007ff; | |
443 | + return; | |
444 | + case SH7750_CCR_A7: | |
445 | + s->ccr = mem_value; | |
446 | + return; | |
447 | + default: | |
448 | + error_access("long write", addr); | |
449 | + abort(); | |
450 | + } | |
451 | +} | |
452 | + | |
453 | +static uint64_t sh7750_mem_readfn(void *opaque, hwaddr addr, unsigned size) | |
454 | +{ | |
455 | + switch (size) { | |
456 | + case 1: | |
457 | + return sh7750_mem_readb(opaque, addr); | |
458 | + case 2: | |
459 | + return sh7750_mem_readw(opaque, addr); | |
460 | + case 4: | |
461 | + return sh7750_mem_readl(opaque, addr); | |
462 | + default: | |
463 | + g_assert_not_reached(); | |
464 | + } | |
465 | +} | |
466 | + | |
467 | +static void sh7750_mem_writefn(void *opaque, hwaddr addr, | |
468 | + uint64_t value, unsigned size) | |
469 | +{ | |
470 | + switch (size) { | |
471 | + case 1: | |
472 | + sh7750_mem_writeb(opaque, addr, value); | |
473 | + break; | |
474 | + case 2: | |
475 | + sh7750_mem_writew(opaque, addr, value); | |
476 | + break; | |
477 | + case 4: | |
478 | + sh7750_mem_writel(opaque, addr, value); | |
479 | + break; | |
480 | + default: | |
481 | + g_assert_not_reached(); | |
482 | + } | |
483 | +} | |
484 | + | |
485 | +static const MemoryRegionOps sh7750_mem_ops = { | |
486 | + .read = sh7750_mem_readfn, | |
487 | + .write = sh7750_mem_writefn, | |
488 | + .valid.min_access_size = 1, | |
489 | + .valid.max_access_size = 4, | |
490 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
491 | +}; | |
492 | + | |
493 | +/* sh775x interrupt controller tables for sh_intc.c | |
494 | + * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c | |
495 | + */ | |
496 | + | |
497 | +enum { | |
498 | + UNUSED = 0, | |
499 | + | |
500 | + /* interrupt sources */ | |
501 | + IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7, | |
502 | + IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E, | |
503 | + IRL0, IRL1, IRL2, IRL3, | |
504 | + HUDI, GPIOI, | |
505 | + DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, | |
506 | + DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, | |
507 | + DMAC_DMAE, | |
508 | + PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, | |
509 | + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3, | |
510 | + TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, | |
511 | + RTC_ATI, RTC_PRI, RTC_CUI, | |
512 | + SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI, | |
513 | + SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI, | |
514 | + WDT, | |
515 | + REF_RCMI, REF_ROVI, | |
516 | + | |
517 | + /* interrupt groups */ | |
518 | + DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, | |
519 | + /* irl bundle */ | |
520 | + IRL, | |
521 | + | |
522 | + NR_SOURCES, | |
523 | +}; | |
524 | + | |
525 | +static struct intc_vect vectors[] = { | |
526 | + INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), | |
527 | + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), | |
528 | + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), | |
529 | + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), | |
530 | + INTC_VECT(RTC_CUI, 0x4c0), | |
531 | + INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500), | |
532 | + INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540), | |
533 | + INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720), | |
534 | + INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760), | |
535 | + INTC_VECT(WDT, 0x560), | |
536 | + INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), | |
537 | +}; | |
538 | + | |
539 | +static struct intc_group groups[] = { | |
540 | + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), | |
541 | + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), | |
542 | + INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), | |
543 | + INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI), | |
544 | + INTC_GROUP(REF, REF_RCMI, REF_ROVI), | |
545 | +}; | |
546 | + | |
547 | +static struct intc_prio_reg prio_registers[] = { | |
548 | + { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, | |
549 | + { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, | |
550 | + { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, | |
551 | + { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, | |
552 | + { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, | |
553 | + TMU4, TMU3, | |
554 | + PCIC1, PCIC0_PCISERR } }, | |
555 | +}; | |
556 | + | |
557 | +/* SH7750R and SH7751R both have 8-channel DMA controllers */ | |
558 | + | |
559 | +/* SH7750R, SH7751 and SH7751R all have two extra timer channels */ | |
560 | + | |
561 | +static struct intc_mask_reg mask_registers[] = { | |
562 | + { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ | |
563 | + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
564 | + 0, 0, 0, 0, 0, 0, TMU4, TMU3, | |
565 | + PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, | |
566 | + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, | |
567 | + PCIC1_PCIDMA3, PCIC0_PCISERR } }, | |
568 | +}; | |
569 | + | |
570 | +/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */ | |
571 | + | |
572 | +/* SH7751 and SH7751R both have PCI */ | |
573 | + | |
574 | +/********************************************************************** | |
575 | + Memory mapped cache and TLB | |
576 | +**********************************************************************/ | |
577 | + | |
578 | +#define MM_REGION_MASK 0x07000000 | |
579 | +#define MM_ICACHE_ADDR (0) | |
580 | +#define MM_ICACHE_DATA (1) | |
581 | +#define MM_ITLB_ADDR (2) | |
582 | +#define MM_ITLB_DATA (3) | |
583 | +#define MM_OCACHE_ADDR (4) | |
584 | +#define MM_OCACHE_DATA (5) | |
585 | +#define MM_UTLB_ADDR (6) | |
586 | +#define MM_UTLB_DATA (7) | |
587 | +#define MM_REGION_TYPE(addr) ((addr & MM_REGION_MASK) >> 24) | |
588 | + | |
589 | +static uint64_t invalid_read(void *opaque, hwaddr addr) | |
590 | +{ | |
591 | + abort(); | |
592 | + | |
593 | + return 0; | |
594 | +} | |
595 | + | |
596 | +static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr, | |
597 | + unsigned size) | |
598 | +{ | |
599 | + SH7750State *s = opaque; | |
600 | + uint32_t ret = 0; | |
601 | + | |
602 | + if (size != 4) { | |
603 | + return invalid_read(opaque, addr); | |
604 | + } | |
605 | + | |
606 | + switch (MM_REGION_TYPE(addr)) { | |
607 | + case MM_ICACHE_ADDR: | |
608 | + case MM_ICACHE_DATA: | |
609 | + /* do nothing */ | |
610 | + break; | |
611 | + case MM_ITLB_ADDR: | |
612 | + ret = cpu_sh4_read_mmaped_itlb_addr(&s->cpu->env, addr); | |
613 | + break; | |
614 | + case MM_ITLB_DATA: | |
615 | + ret = cpu_sh4_read_mmaped_itlb_data(&s->cpu->env, addr); | |
616 | + break; | |
617 | + case MM_OCACHE_ADDR: | |
618 | + case MM_OCACHE_DATA: | |
619 | + /* do nothing */ | |
620 | + break; | |
621 | + case MM_UTLB_ADDR: | |
622 | + ret = cpu_sh4_read_mmaped_utlb_addr(&s->cpu->env, addr); | |
623 | + break; | |
624 | + case MM_UTLB_DATA: | |
625 | + ret = cpu_sh4_read_mmaped_utlb_data(&s->cpu->env, addr); | |
626 | + break; | |
627 | + default: | |
628 | + abort(); | |
629 | + } | |
630 | + | |
631 | + return ret; | |
632 | +} | |
633 | + | |
634 | +static void invalid_write(void *opaque, hwaddr addr, | |
635 | + uint64_t mem_value) | |
636 | +{ | |
637 | + abort(); | |
638 | +} | |
639 | + | |
640 | +static void sh7750_mmct_write(void *opaque, hwaddr addr, | |
641 | + uint64_t mem_value, unsigned size) | |
642 | +{ | |
643 | + SH7750State *s = opaque; | |
644 | + | |
645 | + if (size != 4) { | |
646 | + invalid_write(opaque, addr, mem_value); | |
647 | + } | |
648 | + | |
649 | + switch (MM_REGION_TYPE(addr)) { | |
650 | + case MM_ICACHE_ADDR: | |
651 | + case MM_ICACHE_DATA: | |
652 | + /* do nothing */ | |
653 | + break; | |
654 | + case MM_ITLB_ADDR: | |
655 | + cpu_sh4_write_mmaped_itlb_addr(&s->cpu->env, addr, mem_value); | |
656 | + break; | |
657 | + case MM_ITLB_DATA: | |
658 | + cpu_sh4_write_mmaped_itlb_data(&s->cpu->env, addr, mem_value); | |
659 | + abort(); | |
660 | + break; | |
661 | + case MM_OCACHE_ADDR: | |
662 | + case MM_OCACHE_DATA: | |
663 | + /* do nothing */ | |
664 | + break; | |
665 | + case MM_UTLB_ADDR: | |
666 | + cpu_sh4_write_mmaped_utlb_addr(&s->cpu->env, addr, mem_value); | |
667 | + break; | |
668 | + case MM_UTLB_DATA: | |
669 | + cpu_sh4_write_mmaped_utlb_data(&s->cpu->env, addr, mem_value); | |
670 | + break; | |
671 | + default: | |
672 | + abort(); | |
673 | + break; | |
674 | + } | |
675 | +} | |
676 | + | |
677 | +static const MemoryRegionOps sh7750_mmct_ops = { | |
678 | + .read = sh7750_mmct_read, | |
679 | + .write = sh7750_mmct_write, | |
680 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
681 | +}; | |
682 | + | |
683 | +SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem) | |
684 | +{ | |
685 | + SH7750State *s; | |
686 | + | |
687 | + s = g_malloc0(sizeof(SH7750State)); | |
688 | + s->cpu = cpu; | |
689 | + s->periph_freq = 60000000; /* 60MHz */ | |
690 | + memory_region_init_io(&s->iomem, NULL, &sh7750_mem_ops, s, | |
691 | + "memory", 0x1fc01000); | |
692 | + | |
693 | + memory_region_init_alias(&s->iomem_1f0, NULL, "memory-1f0", | |
694 | + &s->iomem, 0x1f000000, 0x1000); | |
695 | + memory_region_add_subregion(sysmem, 0x1f000000, &s->iomem_1f0); | |
696 | + | |
697 | + memory_region_init_alias(&s->iomem_ff0, NULL, "memory-ff0", | |
698 | + &s->iomem, 0x1f000000, 0x1000); | |
699 | + memory_region_add_subregion(sysmem, 0xff000000, &s->iomem_ff0); | |
700 | + | |
701 | + memory_region_init_alias(&s->iomem_1f8, NULL, "memory-1f8", | |
702 | + &s->iomem, 0x1f800000, 0x1000); | |
703 | + memory_region_add_subregion(sysmem, 0x1f800000, &s->iomem_1f8); | |
704 | + | |
705 | + memory_region_init_alias(&s->iomem_ff8, NULL, "memory-ff8", | |
706 | + &s->iomem, 0x1f800000, 0x1000); | |
707 | + memory_region_add_subregion(sysmem, 0xff800000, &s->iomem_ff8); | |
708 | + | |
709 | + memory_region_init_alias(&s->iomem_1fc, NULL, "memory-1fc", | |
710 | + &s->iomem, 0x1fc00000, 0x1000); | |
711 | + memory_region_add_subregion(sysmem, 0x1fc00000, &s->iomem_1fc); | |
712 | + | |
713 | + memory_region_init_alias(&s->iomem_ffc, NULL, "memory-ffc", | |
714 | + &s->iomem, 0x1fc00000, 0x1000); | |
715 | + memory_region_add_subregion(sysmem, 0xffc00000, &s->iomem_ffc); | |
716 | + | |
717 | + memory_region_init_io(&s->mmct_iomem, NULL, &sh7750_mmct_ops, s, | |
718 | + "cache-and-tlb", 0x08000000); | |
719 | + memory_region_add_subregion(sysmem, 0xf0000000, &s->mmct_iomem); | |
720 | + | |
721 | + sh_intc_init(sysmem, &s->intc, NR_SOURCES, | |
722 | + _INTC_ARRAY(mask_registers), | |
723 | + _INTC_ARRAY(prio_registers)); | |
724 | + | |
725 | + sh_intc_register_sources(&s->intc, | |
726 | + _INTC_ARRAY(vectors), | |
727 | + _INTC_ARRAY(groups)); | |
728 | + | |
729 | + sh_serial_init(sysmem, 0x1fe00000, | |
730 | + 0, s->periph_freq, serial_hd(0), | |
731 | + s->intc.irqs[SCI1_ERI], | |
732 | + s->intc.irqs[SCI1_RXI], | |
733 | + s->intc.irqs[SCI1_TXI], | |
734 | + s->intc.irqs[SCI1_TEI], | |
735 | + NULL); | |
736 | + sh_serial_init(sysmem, 0x1fe80000, | |
737 | + SH_SERIAL_FEAT_SCIF, | |
738 | + s->periph_freq, serial_hd(1), | |
739 | + s->intc.irqs[SCIF_ERI], | |
740 | + s->intc.irqs[SCIF_RXI], | |
741 | + s->intc.irqs[SCIF_TXI], | |
742 | + NULL, | |
743 | + s->intc.irqs[SCIF_BRI]); | |
744 | + | |
745 | + tmu012_init(sysmem, 0x1fd80000, | |
746 | + TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, | |
747 | + s->periph_freq, | |
748 | + s->intc.irqs[TMU0], | |
749 | + s->intc.irqs[TMU1], | |
750 | + s->intc.irqs[TMU2_TUNI], | |
751 | + s->intc.irqs[TMU2_TICPI]); | |
752 | + | |
753 | + return s; | |
754 | +} | |
755 | + | |
756 | +qemu_irq sh7750_irl(SH7750State *s) | |
757 | +{ | |
758 | + sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */ | |
759 | + return qemu_allocate_irq(sh_intc_set_irl, sh_intc_source(&s->intc, IRL), 0); | |
760 | +} |
@@ -0,0 +1,98 @@ | ||
1 | +#include "qemu/osdep.h" | |
2 | +#include "hw/hw.h" | |
3 | +#include "hw/sh4/sh.h" | |
4 | +#include "sh7750_regs.h" | |
5 | +#include "sh7750_regnames.h" | |
6 | + | |
7 | +#define REGNAME(r) {r, #r}, | |
8 | + | |
9 | +typedef struct { | |
10 | + uint32_t regaddr; | |
11 | + const char *regname; | |
12 | +} regname_t; | |
13 | + | |
14 | +static regname_t regnames[] = { | |
15 | + REGNAME(SH7750_PTEH_A7) | |
16 | + REGNAME(SH7750_PTEL_A7) | |
17 | + REGNAME(SH7750_PTEA_A7) | |
18 | + REGNAME(SH7750_TTB_A7) | |
19 | + REGNAME(SH7750_TEA_A7) | |
20 | + REGNAME(SH7750_MMUCR_A7) | |
21 | + REGNAME(SH7750_CCR_A7) | |
22 | + REGNAME(SH7750_QACR0_A7) | |
23 | + REGNAME(SH7750_QACR1_A7) | |
24 | + REGNAME(SH7750_TRA_A7) | |
25 | + REGNAME(SH7750_EXPEVT_A7) | |
26 | + REGNAME(SH7750_INTEVT_A7) | |
27 | + REGNAME(SH7750_STBCR_A7) | |
28 | + REGNAME(SH7750_STBCR2_A7) | |
29 | + REGNAME(SH7750_FRQCR_A7) | |
30 | + REGNAME(SH7750_WTCNT_A7) | |
31 | + REGNAME(SH7750_WTCSR_A7) | |
32 | + REGNAME(SH7750_R64CNT_A7) | |
33 | + REGNAME(SH7750_RSECCNT_A7) | |
34 | + REGNAME(SH7750_RMINCNT_A7) | |
35 | + REGNAME(SH7750_RHRCNT_A7) | |
36 | + REGNAME(SH7750_RWKCNT_A7) | |
37 | + REGNAME(SH7750_RDAYCNT_A7) | |
38 | + REGNAME(SH7750_RMONCNT_A7) | |
39 | + REGNAME(SH7750_RYRCNT_A7) | |
40 | + REGNAME(SH7750_RSECAR_A7) | |
41 | + REGNAME(SH7750_RMINAR_A7) | |
42 | + REGNAME(SH7750_RHRAR_A7) | |
43 | + REGNAME(SH7750_RWKAR_A7) | |
44 | + REGNAME(SH7750_RDAYAR_A7) | |
45 | + REGNAME(SH7750_RMONAR_A7) | |
46 | + REGNAME(SH7750_RCR1_A7) | |
47 | + REGNAME(SH7750_RCR2_A7) | |
48 | + REGNAME(SH7750_BCR1_A7) | |
49 | + REGNAME(SH7750_BCR2_A7) | |
50 | + REGNAME(SH7750_WCR1_A7) | |
51 | + REGNAME(SH7750_WCR2_A7) | |
52 | + REGNAME(SH7750_WCR3_A7) | |
53 | + REGNAME(SH7750_MCR_A7) | |
54 | + REGNAME(SH7750_PCR_A7) | |
55 | + REGNAME(SH7750_RTCSR_A7) | |
56 | + REGNAME(SH7750_RTCNT_A7) | |
57 | + REGNAME(SH7750_RTCOR_A7) | |
58 | + REGNAME(SH7750_RFCR_A7) | |
59 | + REGNAME(SH7750_SAR0_A7) | |
60 | + REGNAME(SH7750_SAR1_A7) | |
61 | + REGNAME(SH7750_SAR2_A7) | |
62 | + REGNAME(SH7750_SAR3_A7) | |
63 | + REGNAME(SH7750_DAR0_A7) | |
64 | + REGNAME(SH7750_DAR1_A7) | |
65 | + REGNAME(SH7750_DAR2_A7) | |
66 | + REGNAME(SH7750_DAR3_A7) | |
67 | + REGNAME(SH7750_DMATCR0_A7) | |
68 | + REGNAME(SH7750_DMATCR1_A7) | |
69 | + REGNAME(SH7750_DMATCR2_A7) | |
70 | + REGNAME(SH7750_DMATCR3_A7) | |
71 | + REGNAME(SH7750_CHCR0_A7) | |
72 | + REGNAME(SH7750_CHCR1_A7) | |
73 | + REGNAME(SH7750_CHCR2_A7) | |
74 | + REGNAME(SH7750_CHCR3_A7) | |
75 | + REGNAME(SH7750_DMAOR_A7) | |
76 | + REGNAME(SH7750_PCTRA_A7) | |
77 | + REGNAME(SH7750_PDTRA_A7) | |
78 | + REGNAME(SH7750_PCTRB_A7) | |
79 | + REGNAME(SH7750_PDTRB_A7) | |
80 | + REGNAME(SH7750_GPIOIC_A7) | |
81 | + REGNAME(SH7750_ICR_A7) | |
82 | + REGNAME(SH7750_BCR3_A7) | |
83 | + REGNAME(SH7750_BCR4_A7) | |
84 | + REGNAME(SH7750_SDMR2_A7) | |
85 | + REGNAME(SH7750_SDMR3_A7) {(uint32_t) - 1, NULL} | |
86 | +}; | |
87 | + | |
88 | +const char *regname(uint32_t addr) | |
89 | +{ | |
90 | + unsigned int i; | |
91 | + | |
92 | + for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) { | |
93 | + if (regnames[i].regaddr == addr) | |
94 | + return regnames[i].regname; | |
95 | + } | |
96 | + | |
97 | + return "<unknown reg>"; | |
98 | +} |
@@ -0,0 +1,6 @@ | ||
1 | +#ifndef SH7750_REGNAMES_H | |
2 | +#define SH7750_REGNAMES_H | |
3 | + | |
4 | +const char *regname(uint32_t addr); | |
5 | + | |
6 | +#endif /* SH7750_REGNAMES_H */ |
@@ -0,0 +1,1277 @@ | ||
1 | +/* | |
2 | + * SH-7750 memory-mapped registers | |
3 | + * This file based on information provided in the following document: | |
4 | + * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S) | |
5 | + * Hardware Manual" | |
6 | + * Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd. | |
7 | + * | |
8 | + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia | |
9 | + * Author: Alexandra Kossovsky <sasha@oktet.ru> | |
10 | + * Victor V. Vengerov <vvv@oktet.ru> | |
11 | + * | |
12 | + * The license and distribution terms for this file may be | |
13 | + * found in the file LICENSE in this distribution or at | |
14 | + * http://www.rtems.com/license/LICENSE. | |
15 | + * | |
16 | + * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp | |
17 | + */ | |
18 | + | |
19 | +#ifndef SH7750_REGS_H | |
20 | +#define SH7750_REGS_H | |
21 | + | |
22 | +/* | |
23 | + * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and | |
24 | + * in 0x1f000000 - 0x1fffffff (area 7 address) | |
25 | + */ | |
26 | +#define SH7750_P4_BASE 0xff000000 /* Accessible only in | |
27 | + privileged mode */ | |
28 | +#define SH7750_A7_BASE 0x1f000000 /* Accessible only using TLB */ | |
29 | + | |
30 | +#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs)) | |
31 | +#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs)) | |
32 | + | |
33 | +/* | |
34 | + * MMU Registers | |
35 | + */ | |
36 | + | |
37 | +/* Page Table Entry High register - PTEH */ | |
38 | +#define SH7750_PTEH_REGOFS 0x000000 /* offset */ | |
39 | +#define SH7750_PTEH SH7750_P4_REG32(SH7750_PTEH_REGOFS) | |
40 | +#define SH7750_PTEH_A7 SH7750_A7_REG32(SH7750_PTEH_REGOFS) | |
41 | +#define SH7750_PTEH_VPN 0xfffffd00 /* Virtual page number */ | |
42 | +#define SH7750_PTEH_VPN_S 10 | |
43 | +#define SH7750_PTEH_ASID 0x000000ff /* Address space identifier */ | |
44 | +#define SH7750_PTEH_ASID_S 0 | |
45 | + | |
46 | +/* Page Table Entry Low register - PTEL */ | |
47 | +#define SH7750_PTEL_REGOFS 0x000004 /* offset */ | |
48 | +#define SH7750_PTEL SH7750_P4_REG32(SH7750_PTEL_REGOFS) | |
49 | +#define SH7750_PTEL_A7 SH7750_A7_REG32(SH7750_PTEL_REGOFS) | |
50 | +#define SH7750_PTEL_PPN 0x1ffffc00 /* Physical page number */ | |
51 | +#define SH7750_PTEL_PPN_S 10 | |
52 | +#define SH7750_PTEL_V 0x00000100 /* Validity (0-entry is invalid) */ | |
53 | +#define SH7750_PTEL_SZ1 0x00000080 /* Page size bit 1 */ | |
54 | +#define SH7750_PTEL_SZ0 0x00000010 /* Page size bit 0 */ | |
55 | +#define SH7750_PTEL_SZ_1KB 0x00000000 /* 1-kbyte page */ | |
56 | +#define SH7750_PTEL_SZ_4KB 0x00000010 /* 4-kbyte page */ | |
57 | +#define SH7750_PTEL_SZ_64KB 0x00000080 /* 64-kbyte page */ | |
58 | +#define SH7750_PTEL_SZ_1MB 0x00000090 /* 1-Mbyte page */ | |
59 | +#define SH7750_PTEL_PR 0x00000060 /* Protection Key Data */ | |
60 | +#define SH7750_PTEL_PR_ROPO 0x00000000 /* read-only in priv mode */ | |
61 | +#define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */ | |
62 | +#define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */ | |
63 | +#define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */ | |
64 | +#define SH7750_PTEL_C 0x00000008 /* Cacheability | |
65 | + (0 - page not cacheable) */ | |
66 | +#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been | |
67 | + performed to a page) */ | |
68 | +#define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are | |
69 | + shared by processes) */ | |
70 | +#define SH7750_PTEL_WT 0x00000001 /* Write-through bit, specifies the | |
71 | + cache write mode: | |
72 | + 0 - Copy-back mode | |
73 | + 1 - Write-through mode */ | |
74 | + | |
75 | +/* Page Table Entry Assistance register - PTEA */ | |
76 | +#define SH7750_PTEA_REGOFS 0x000034 /* offset */ | |
77 | +#define SH7750_PTEA SH7750_P4_REG32(SH7750_PTEA_REGOFS) | |
78 | +#define SH7750_PTEA_A7 SH7750_A7_REG32(SH7750_PTEA_REGOFS) | |
79 | +#define SH7750_PTEA_TC 0x00000008 /* Timing Control bit | |
80 | + 0 - use area 5 wait states | |
81 | + 1 - use area 6 wait states */ | |
82 | +#define SH7750_PTEA_SA 0x00000007 /* Space Attribute bits: */ | |
83 | +#define SH7750_PTEA_SA_UNDEF 0x00000000 /* 0 - undefined */ | |
84 | +#define SH7750_PTEA_SA_IOVAR 0x00000001 /* 1 - variable-size I/O space */ | |
85 | +#define SH7750_PTEA_SA_IO8 0x00000002 /* 2 - 8-bit I/O space */ | |
86 | +#define SH7750_PTEA_SA_IO16 0x00000003 /* 3 - 16-bit I/O space */ | |
87 | +#define SH7750_PTEA_SA_CMEM8 0x00000004 /* 4 - 8-bit common memory space */ | |
88 | +#define SH7750_PTEA_SA_CMEM16 0x00000005 /* 5 - 16-bit common memory space */ | |
89 | +#define SH7750_PTEA_SA_AMEM8 0x00000006 /* 6 - 8-bit attr memory space */ | |
90 | +#define SH7750_PTEA_SA_AMEM16 0x00000007 /* 7 - 16-bit attr memory space */ | |
91 | + | |
92 | + | |
93 | +/* Translation table base register */ | |
94 | +#define SH7750_TTB_REGOFS 0x000008 /* offset */ | |
95 | +#define SH7750_TTB SH7750_P4_REG32(SH7750_TTB_REGOFS) | |
96 | +#define SH7750_TTB_A7 SH7750_A7_REG32(SH7750_TTB_REGOFS) | |
97 | + | |
98 | +/* TLB exeption address register - TEA */ | |
99 | +#define SH7750_TEA_REGOFS 0x00000c /* offset */ | |
100 | +#define SH7750_TEA SH7750_P4_REG32(SH7750_TEA_REGOFS) | |
101 | +#define SH7750_TEA_A7 SH7750_A7_REG32(SH7750_TEA_REGOFS) | |
102 | + | |
103 | +/* MMU control register - MMUCR */ | |
104 | +#define SH7750_MMUCR_REGOFS 0x000010 /* offset */ | |
105 | +#define SH7750_MMUCR SH7750_P4_REG32(SH7750_MMUCR_REGOFS) | |
106 | +#define SH7750_MMUCR_A7 SH7750_A7_REG32(SH7750_MMUCR_REGOFS) | |
107 | +#define SH7750_MMUCR_AT 0x00000001 /* Address translation bit */ | |
108 | +#define SH7750_MMUCR_TI 0x00000004 /* TLB invalidate */ | |
109 | +#define SH7750_MMUCR_SV 0x00000100 /* Single Virtual Mode bit */ | |
110 | +#define SH7750_MMUCR_SQMD 0x00000200 /* Store Queue Mode bit */ | |
111 | +#define SH7750_MMUCR_URC 0x0000FC00 /* UTLB Replace Counter */ | |
112 | +#define SH7750_MMUCR_URC_S 10 | |
113 | +#define SH7750_MMUCR_URB 0x00FC0000 /* UTLB Replace Boundary */ | |
114 | +#define SH7750_MMUCR_URB_S 18 | |
115 | +#define SH7750_MMUCR_LRUI 0xFC000000 /* Least Recently Used ITLB */ | |
116 | +#define SH7750_MMUCR_LRUI_S 26 | |
117 | + | |
118 | + | |
119 | + | |
120 | + | |
121 | +/* | |
122 | + * Cache registers | |
123 | + * IC -- instructions cache | |
124 | + * OC -- operand cache | |
125 | + */ | |
126 | + | |
127 | +/* Cache Control Register - CCR */ | |
128 | +#define SH7750_CCR_REGOFS 0x00001c /* offset */ | |
129 | +#define SH7750_CCR SH7750_P4_REG32(SH7750_CCR_REGOFS) | |
130 | +#define SH7750_CCR_A7 SH7750_A7_REG32(SH7750_CCR_REGOFS) | |
131 | + | |
132 | +#define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */ | |
133 | +#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit: | |
134 | + set it to clear IC */ | |
135 | +#define SH7750_CCR_ICE 0x00000100 /* IC enable bit */ | |
136 | +#define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */ | |
137 | +#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit | |
138 | + if you set OCE = 0, | |
139 | + you should set ORA = 0 */ | |
140 | +#define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */ | |
141 | +#define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */ | |
142 | +#define SH7750_CCR_WT 0x00000002 /* Write-through bit for P0,U0,P3 area */ | |
143 | +#define SH7750_CCR_OCE 0x00000001 /* OC enable bit */ | |
144 | + | |
145 | +/* Queue address control register 0 - QACR0 */ | |
146 | +#define SH7750_QACR0_REGOFS 0x000038 /* offset */ | |
147 | +#define SH7750_QACR0 SH7750_P4_REG32(SH7750_QACR0_REGOFS) | |
148 | +#define SH7750_QACR0_A7 SH7750_A7_REG32(SH7750_QACR0_REGOFS) | |
149 | + | |
150 | +/* Queue address control register 1 - QACR1 */ | |
151 | +#define SH7750_QACR1_REGOFS 0x00003c /* offset */ | |
152 | +#define SH7750_QACR1 SH7750_P4_REG32(SH7750_QACR1_REGOFS) | |
153 | +#define SH7750_QACR1_A7 SH7750_A7_REG32(SH7750_QACR1_REGOFS) | |
154 | + | |
155 | + | |
156 | +/* | |
157 | + * Exeption-related registers | |
158 | + */ | |
159 | + | |
160 | +/* Immediate data for TRAPA instruction - TRA */ | |
161 | +#define SH7750_TRA_REGOFS 0x000020 /* offset */ | |
162 | +#define SH7750_TRA SH7750_P4_REG32(SH7750_TRA_REGOFS) | |
163 | +#define SH7750_TRA_A7 SH7750_A7_REG32(SH7750_TRA_REGOFS) | |
164 | + | |
165 | +#define SH7750_TRA_IMM 0x000003fd /* Immediate data operand */ | |
166 | +#define SH7750_TRA_IMM_S 2 | |
167 | + | |
168 | +/* Exeption event register - EXPEVT */ | |
169 | +#define SH7750_EXPEVT_REGOFS 0x000024 | |
170 | +#define SH7750_EXPEVT SH7750_P4_REG32(SH7750_EXPEVT_REGOFS) | |
171 | +#define SH7750_EXPEVT_A7 SH7750_A7_REG32(SH7750_EXPEVT_REGOFS) | |
172 | + | |
173 | +#define SH7750_EXPEVT_EX 0x00000fff /* Exeption code */ | |
174 | +#define SH7750_EXPEVT_EX_S 0 | |
175 | + | |
176 | +/* Interrupt event register */ | |
177 | +#define SH7750_INTEVT_REGOFS 0x000028 | |
178 | +#define SH7750_INTEVT SH7750_P4_REG32(SH7750_INTEVT_REGOFS) | |
179 | +#define SH7750_INTEVT_A7 SH7750_A7_REG32(SH7750_INTEVT_REGOFS) | |
180 | +#define SH7750_INTEVT_EX 0x00000fff /* Exeption code */ | |
181 | +#define SH7750_INTEVT_EX_S 0 | |
182 | + | |
183 | +/* | |
184 | + * Exception/interrupt codes | |
185 | + */ | |
186 | +#define SH7750_EVT_TO_NUM(evt) ((evt) >> 5) | |
187 | + | |
188 | +/* Reset exception category */ | |
189 | +#define SH7750_EVT_POWER_ON_RST 0x000 /* Power-on reset */ | |
190 | +#define SH7750_EVT_MANUAL_RST 0x020 /* Manual reset */ | |
191 | +#define SH7750_EVT_TLB_MULT_HIT 0x140 /* TLB multiple-hit exception */ | |
192 | + | |
193 | +/* General exception category */ | |
194 | +#define SH7750_EVT_USER_BREAK 0x1E0 /* User break */ | |
195 | +#define SH7750_EVT_IADDR_ERR 0x0E0 /* Instruction address error */ | |
196 | +#define SH7750_EVT_TLB_READ_MISS 0x040 /* ITLB miss exception / | |
197 | + DTLB miss exception (read) */ | |
198 | +#define SH7750_EVT_TLB_READ_PROTV 0x0A0 /* ITLB protection violation / | |
199 | + DTLB protection violation (read) */ | |
200 | +#define SH7750_EVT_ILLEGAL_INSTR 0x180 /* General Illegal Instruction | |
201 | + exception */ | |
202 | +#define SH7750_EVT_SLOT_ILLEGAL_INSTR 0x1A0 /* Slot Illegal Instruction | |
203 | + exception */ | |
204 | +#define SH7750_EVT_FPU_DISABLE 0x800 /* General FPU disable exception */ | |
205 | +#define SH7750_EVT_SLOT_FPU_DISABLE 0x820 /* Slot FPU disable exception */ | |
206 | +#define SH7750_EVT_DATA_READ_ERR 0x0E0 /* Data address error (read) */ | |
207 | +#define SH7750_EVT_DATA_WRITE_ERR 0x100 /* Data address error (write) */ | |
208 | +#define SH7750_EVT_DTLB_WRITE_MISS 0x060 /* DTLB miss exception (write) */ | |
209 | +#define SH7750_EVT_DTLB_WRITE_PROTV 0x0C0 /* DTLB protection violation | |
210 | + exception (write) */ | |
211 | +#define SH7750_EVT_FPU_EXCEPTION 0x120 /* FPU exception */ | |
212 | +#define SH7750_EVT_INITIAL_PGWRITE 0x080 /* Initial Page Write exception */ | |
213 | +#define SH7750_EVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */ | |
214 | + | |
215 | +/* Interrupt exception category */ | |
216 | +#define SH7750_EVT_NMI 0x1C0 /* Non-maskable interrupt */ | |
217 | +#define SH7750_EVT_IRQ0 0x200 /* External Interrupt 0 */ | |
218 | +#define SH7750_EVT_IRQ1 0x220 /* External Interrupt 1 */ | |
219 | +#define SH7750_EVT_IRQ2 0x240 /* External Interrupt 2 */ | |
220 | +#define SH7750_EVT_IRQ3 0x260 /* External Interrupt 3 */ | |
221 | +#define SH7750_EVT_IRQ4 0x280 /* External Interrupt 4 */ | |
222 | +#define SH7750_EVT_IRQ5 0x2A0 /* External Interrupt 5 */ | |
223 | +#define SH7750_EVT_IRQ6 0x2C0 /* External Interrupt 6 */ | |
224 | +#define SH7750_EVT_IRQ7 0x2E0 /* External Interrupt 7 */ | |
225 | +#define SH7750_EVT_IRQ8 0x300 /* External Interrupt 8 */ | |
226 | +#define SH7750_EVT_IRQ9 0x320 /* External Interrupt 9 */ | |
227 | +#define SH7750_EVT_IRQA 0x340 /* External Interrupt A */ | |
228 | +#define SH7750_EVT_IRQB 0x360 /* External Interrupt B */ | |
229 | +#define SH7750_EVT_IRQC 0x380 /* External Interrupt C */ | |
230 | +#define SH7750_EVT_IRQD 0x3A0 /* External Interrupt D */ | |
231 | +#define SH7750_EVT_IRQE 0x3C0 /* External Interrupt E */ | |
232 | + | |
233 | +/* Peripheral Module Interrupts - Timer Unit (TMU) */ | |
234 | +#define SH7750_EVT_TUNI0 0x400 /* TMU Underflow Interrupt 0 */ | |
235 | +#define SH7750_EVT_TUNI1 0x420 /* TMU Underflow Interrupt 1 */ | |
236 | +#define SH7750_EVT_TUNI2 0x440 /* TMU Underflow Interrupt 2 */ | |
237 | +#define SH7750_EVT_TICPI2 0x460 /* TMU Input Capture Interrupt 2 */ | |
238 | + | |
239 | +/* Peripheral Module Interrupts - Real-Time Clock (RTC) */ | |
240 | +#define SH7750_EVT_RTC_ATI 0x480 /* Alarm Interrupt Request */ | |
241 | +#define SH7750_EVT_RTC_PRI 0x4A0 /* Periodic Interrupt Request */ | |
242 | +#define SH7750_EVT_RTC_CUI 0x4C0 /* Carry Interrupt Request */ | |
243 | + | |
244 | +/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */ | |
245 | +#define SH7750_EVT_SCI_ERI 0x4E0 /* Receive Error */ | |
246 | +#define SH7750_EVT_SCI_RXI 0x500 /* Receive Data Register Full */ | |
247 | +#define SH7750_EVT_SCI_TXI 0x520 /* Transmit Data Register Empty */ | |
248 | +#define SH7750_EVT_SCI_TEI 0x540 /* Transmit End */ | |
249 | + | |
250 | +/* Peripheral Module Interrupts - Watchdog Timer (WDT) */ | |
251 | +#define SH7750_EVT_WDT_ITI 0x560 /* Interval Timer Interrupt | |
252 | + (used when WDT operates in | |
253 | + interval timer mode) */ | |
254 | + | |
255 | +/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */ | |
256 | +#define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */ | |
257 | +#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow | |
258 | + interrupt */ | |
259 | + | |
260 | +/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */ | |
261 | +#define SH7750_EVT_HUDI 0x600 /* UDI interrupt */ | |
262 | + | |
263 | +/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */ | |
264 | +#define SH7750_EVT_GPIO 0x620 /* GPIO Interrupt */ | |
265 | + | |
266 | +/* Peripheral Module Interrupts - DMA Controller (DMAC) */ | |
267 | +#define SH7750_EVT_DMAC_DMTE0 0x640 /* DMAC 0 Transfer End Interrupt */ | |
268 | +#define SH7750_EVT_DMAC_DMTE1 0x660 /* DMAC 1 Transfer End Interrupt */ | |
269 | +#define SH7750_EVT_DMAC_DMTE2 0x680 /* DMAC 2 Transfer End Interrupt */ | |
270 | +#define SH7750_EVT_DMAC_DMTE3 0x6A0 /* DMAC 3 Transfer End Interrupt */ | |
271 | +#define SH7750_EVT_DMAC_DMAE 0x6C0 /* DMAC Address Error Interrupt */ | |
272 | + | |
273 | +/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */ | |
274 | +/* (SCIF) */ | |
275 | +#define SH7750_EVT_SCIF_ERI 0x700 /* Receive Error */ | |
276 | +#define SH7750_EVT_SCIF_RXI 0x720 /* Receive FIFO Data Full or | |
277 | + Receive Data ready interrupt */ | |
278 | +#define SH7750_EVT_SCIF_BRI 0x740 /* Break or overrun error */ | |
279 | +#define SH7750_EVT_SCIF_TXI 0x760 /* Transmit FIFO Data Empty */ | |
280 | + | |
281 | +/* | |
282 | + * Power Management | |
283 | + */ | |
284 | +#define SH7750_STBCR_REGOFS 0xC00004 /* offset */ | |
285 | +#define SH7750_STBCR SH7750_P4_REG32(SH7750_STBCR_REGOFS) | |
286 | +#define SH7750_STBCR_A7 SH7750_A7_REG32(SH7750_STBCR_REGOFS) | |
287 | + | |
288 | +#define SH7750_STBCR_STBY 0x80 /* Specifies a transition to standby mode: | |
289 | + 0 - Transition to SLEEP mode on SLEEP | |
290 | + 1 - Transition to STANDBY mode on SLEEP */ | |
291 | +#define SH7750_STBCR_PHZ 0x40 /* State of peripheral module pins in | |
292 | + standby mode: | |
293 | + 0 - normal state | |
294 | + 1 - high-impendance state */ | |
295 | + | |
296 | +#define SH7750_STBCR_PPU 0x20 /* Peripheral module pins pull-up controls */ | |
297 | +#define SH7750_STBCR_MSTP4 0x10 /* Stopping the clock supply to DMAC */ | |
298 | +#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4 | |
299 | +#define SH7750_STBCR_MSTP3 0x08 /* Stopping the clock supply to SCIF */ | |
300 | +#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3 | |
301 | +#define SH7750_STBCR_MSTP2 0x04 /* Stopping the clock supply to TMU */ | |
302 | +#define SH7750_STBCR_TMU_STP SH7750_STBCR_MSTP2 | |
303 | +#define SH7750_STBCR_MSTP1 0x02 /* Stopping the clock supply to RTC */ | |
304 | +#define SH7750_STBCR_RTC_STP SH7750_STBCR_MSTP1 | |
305 | +#define SH7750_STBCR_MSPT0 0x01 /* Stopping the clock supply to SCI */ | |
306 | +#define SH7750_STBCR_SCI_STP SH7750_STBCR_MSTP0 | |
307 | + | |
308 | +#define SH7750_STBCR_STBY 0x80 | |
309 | + | |
310 | + | |
311 | +#define SH7750_STBCR2_REGOFS 0xC00010 /* offset */ | |
312 | +#define SH7750_STBCR2 SH7750_P4_REG32(SH7750_STBCR2_REGOFS) | |
313 | +#define SH7750_STBCR2_A7 SH7750_A7_REG32(SH7750_STBCR2_REGOFS) | |
314 | + | |
315 | +#define SH7750_STBCR2_DSLP 0x80 /* Specifies transition to deep sleep mode: | |
316 | + 0 - transition to sleep or standby mode | |
317 | + as it is specified in STBY bit | |
318 | + 1 - transition to deep sleep mode on | |
319 | + execution of SLEEP instruction */ | |
320 | +#define SH7750_STBCR2_MSTP6 0x02 /* Stopping the clock supply to Store Queue | |
321 | + in the cache controller */ | |
322 | +#define SH7750_STBCR2_SQ_STP SH7750_STBCR2_MSTP6 | |
323 | +#define SH7750_STBCR2_MSTP5 0x01 /* Stopping the clock supply to the User | |
324 | + Break Controller (UBC) */ | |
325 | +#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5 | |
326 | + | |
327 | +/* | |
328 | + * Clock Pulse Generator (CPG) | |
329 | + */ | |
330 | +#define SH7750_FRQCR_REGOFS 0xC00000 /* offset */ | |
331 | +#define SH7750_FRQCR SH7750_P4_REG32(SH7750_FRQCR_REGOFS) | |
332 | +#define SH7750_FRQCR_A7 SH7750_A7_REG32(SH7750_FRQCR_REGOFS) | |
333 | + | |
334 | +#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable | |
335 | + 0 - CKIO pin goes to HiZ/pullup | |
336 | + 1 - Clock is output from CKIO */ | |
337 | +#define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */ | |
338 | +#define SH7750_FRQCR_PLL2EN 0x0200 /* PLL circuit 2 enable */ | |
339 | + | |
340 | +#define SH7750_FRQCR_IFC 0x01C0 /* CPU clock frequency division ratio: */ | |
341 | +#define SH7750_FRQCR_IFCDIV1 0x0000 /* 0 - * 1 */ | |
342 | +#define SH7750_FRQCR_IFCDIV2 0x0040 /* 1 - * 1/2 */ | |
343 | +#define SH7750_FRQCR_IFCDIV3 0x0080 /* 2 - * 1/3 */ | |
344 | +#define SH7750_FRQCR_IFCDIV4 0x00C0 /* 3 - * 1/4 */ | |
345 | +#define SH7750_FRQCR_IFCDIV6 0x0100 /* 4 - * 1/6 */ | |
346 | +#define SH7750_FRQCR_IFCDIV8 0x0140 /* 5 - * 1/8 */ | |
347 | + | |
348 | +#define SH7750_FRQCR_BFC 0x0038 /* Bus clock frequency division ratio: */ | |
349 | +#define SH7750_FRQCR_BFCDIV1 0x0000 /* 0 - * 1 */ | |
350 | +#define SH7750_FRQCR_BFCDIV2 0x0008 /* 1 - * 1/2 */ | |
351 | +#define SH7750_FRQCR_BFCDIV3 0x0010 /* 2 - * 1/3 */ | |
352 | +#define SH7750_FRQCR_BFCDIV4 0x0018 /* 3 - * 1/4 */ | |
353 | +#define SH7750_FRQCR_BFCDIV6 0x0020 /* 4 - * 1/6 */ | |
354 | +#define SH7750_FRQCR_BFCDIV8 0x0028 /* 5 - * 1/8 */ | |
355 | + | |
356 | +#define SH7750_FRQCR_PFC 0x0007 /* Peripheral module clock frequency | |
357 | + division ratio: */ | |
358 | +#define SH7750_FRQCR_PFCDIV2 0x0000 /* 0 - * 1/2 */ | |
359 | +#define SH7750_FRQCR_PFCDIV3 0x0001 /* 1 - * 1/3 */ | |
360 | +#define SH7750_FRQCR_PFCDIV4 0x0002 /* 2 - * 1/4 */ | |
361 | +#define SH7750_FRQCR_PFCDIV6 0x0003 /* 3 - * 1/6 */ | |
362 | +#define SH7750_FRQCR_PFCDIV8 0x0004 /* 4 - * 1/8 */ | |
363 | + | |
364 | +/* | |
365 | + * Watchdog Timer (WDT) | |
366 | + */ | |
367 | + | |
368 | +/* Watchdog Timer Counter register - WTCNT */ | |
369 | +#define SH7750_WTCNT_REGOFS 0xC00008 /* offset */ | |
370 | +#define SH7750_WTCNT SH7750_P4_REG32(SH7750_WTCNT_REGOFS) | |
371 | +#define SH7750_WTCNT_A7 SH7750_A7_REG32(SH7750_WTCNT_REGOFS) | |
372 | +#define SH7750_WTCNT_KEY 0x5A00 /* When WTCNT byte register written, | |
373 | + you have to set the upper byte to | |
374 | + 0x5A */ | |
375 | + | |
376 | +/* Watchdog Timer Control/Status register - WTCSR */ | |
377 | +#define SH7750_WTCSR_REGOFS 0xC0000C /* offset */ | |
378 | +#define SH7750_WTCSR SH7750_P4_REG32(SH7750_WTCSR_REGOFS) | |
379 | +#define SH7750_WTCSR_A7 SH7750_A7_REG32(SH7750_WTCSR_REGOFS) | |
380 | +#define SH7750_WTCSR_KEY 0xA500 /* When WTCSR byte register written, | |
381 | + you have to set the upper byte to | |
382 | + 0xA5 */ | |
383 | +#define SH7750_WTCSR_TME 0x80 /* Timer enable (1-upcount start) */ | |
384 | +#define SH7750_WTCSR_MODE 0x40 /* Timer Mode Select: */ | |
385 | +#define SH7750_WTCSR_MODE_WT 0x40 /* Watchdog Timer Mode */ | |
386 | +#define SH7750_WTCSR_MODE_IT 0x00 /* Interval Timer Mode */ | |
387 | +#define SH7750_WTCSR_RSTS 0x20 /* Reset Select: */ | |
388 | +#define SH7750_WTCSR_RST_MAN 0x20 /* Manual Reset */ | |
389 | +#define SH7750_WTCSR_RST_PWR 0x00 /* Power-on Reset */ | |
390 | +#define SH7750_WTCSR_WOVF 0x10 /* Watchdog Timer Overflow Flag */ | |
391 | +#define SH7750_WTCSR_IOVF 0x08 /* Interval Timer Overflow Flag */ | |
392 | +#define SH7750_WTCSR_CKS 0x07 /* Clock Select: */ | |
393 | +#define SH7750_WTCSR_CKS_DIV32 0x00 /* 1/32 of frequency divider 2 input */ | |
394 | +#define SH7750_WTCSR_CKS_DIV64 0x01 /* 1/64 */ | |
395 | +#define SH7750_WTCSR_CKS_DIV128 0x02 /* 1/128 */ | |
396 | +#define SH7750_WTCSR_CKS_DIV256 0x03 /* 1/256 */ | |
397 | +#define SH7750_WTCSR_CKS_DIV512 0x04 /* 1/512 */ | |
398 | +#define SH7750_WTCSR_CKS_DIV1024 0x05 /* 1/1024 */ | |
399 | +#define SH7750_WTCSR_CKS_DIV2048 0x06 /* 1/2048 */ | |
400 | +#define SH7750_WTCSR_CKS_DIV4096 0x07 /* 1/4096 */ | |
401 | + | |
402 | +/* | |
403 | + * Real-Time Clock (RTC) | |
404 | + */ | |
405 | +/* 64-Hz Counter Register (byte, read-only) - R64CNT */ | |
406 | +#define SH7750_R64CNT_REGOFS 0xC80000 /* offset */ | |
407 | +#define SH7750_R64CNT SH7750_P4_REG32(SH7750_R64CNT_REGOFS) | |
408 | +#define SH7750_R64CNT_A7 SH7750_A7_REG32(SH7750_R64CNT_REGOFS) | |
409 | + | |
410 | +/* Second Counter Register (byte, BCD-coded) - RSECCNT */ | |
411 | +#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */ | |
412 | +#define SH7750_RSECCNT SH7750_P4_REG32(SH7750_RSECCNT_REGOFS) | |
413 | +#define SH7750_RSECCNT_A7 SH7750_A7_REG32(SH7750_RSECCNT_REGOFS) | |
414 | + | |
415 | +/* Minute Counter Register (byte, BCD-coded) - RMINCNT */ | |
416 | +#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */ | |
417 | +#define SH7750_RMINCNT SH7750_P4_REG32(SH7750_RMINCNT_REGOFS) | |
418 | +#define SH7750_RMINCNT_A7 SH7750_A7_REG32(SH7750_RMINCNT_REGOFS) | |
419 | + | |
420 | +/* Hour Counter Register (byte, BCD-coded) - RHRCNT */ | |
421 | +#define SH7750_RHRCNT_REGOFS 0xC8000C /* offset */ | |
422 | +#define SH7750_RHRCNT SH7750_P4_REG32(SH7750_RHRCNT_REGOFS) | |
423 | +#define SH7750_RHRCNT_A7 SH7750_A7_REG32(SH7750_RHRCNT_REGOFS) | |
424 | + | |
425 | +/* Day-of-Week Counter Register (byte) - RWKCNT */ | |
426 | +#define SH7750_RWKCNT_REGOFS 0xC80010 /* offset */ | |
427 | +#define SH7750_RWKCNT SH7750_P4_REG32(SH7750_RWKCNT_REGOFS) | |
428 | +#define SH7750_RWKCNT_A7 SH7750_A7_REG32(SH7750_RWKCNT_REGOFS) | |
429 | + | |
430 | +#define SH7750_RWKCNT_SUN 0 /* Sunday */ | |
431 | +#define SH7750_RWKCNT_MON 1 /* Monday */ | |
432 | +#define SH7750_RWKCNT_TUE 2 /* Tuesday */ | |
433 | +#define SH7750_RWKCNT_WED 3 /* Wednesday */ | |
434 | +#define SH7750_RWKCNT_THU 4 /* Thursday */ | |
435 | +#define SH7750_RWKCNT_FRI 5 /* Friday */ | |
436 | +#define SH7750_RWKCNT_SAT 6 /* Saturday */ | |
437 | + | |
438 | +/* Day Counter Register (byte, BCD-coded) - RDAYCNT */ | |
439 | +#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */ | |
440 | +#define SH7750_RDAYCNT SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS) | |
441 | +#define SH7750_RDAYCNT_A7 SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS) | |
442 | + | |
443 | +/* Month Counter Register (byte, BCD-coded) - RMONCNT */ | |
444 | +#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */ | |
445 | +#define SH7750_RMONCNT SH7750_P4_REG32(SH7750_RMONCNT_REGOFS) | |
446 | +#define SH7750_RMONCNT_A7 SH7750_A7_REG32(SH7750_RMONCNT_REGOFS) | |
447 | + | |
448 | +/* Year Counter Register (half, BCD-coded) - RYRCNT */ | |
449 | +#define SH7750_RYRCNT_REGOFS 0xC8001C /* offset */ | |
450 | +#define SH7750_RYRCNT SH7750_P4_REG32(SH7750_RYRCNT_REGOFS) | |
451 | +#define SH7750_RYRCNT_A7 SH7750_A7_REG32(SH7750_RYRCNT_REGOFS) | |
452 | + | |
453 | +/* Second Alarm Register (byte, BCD-coded) - RSECAR */ | |
454 | +#define SH7750_RSECAR_REGOFS 0xC80020 /* offset */ | |
455 | +#define SH7750_RSECAR SH7750_P4_REG32(SH7750_RSECAR_REGOFS) | |
456 | +#define SH7750_RSECAR_A7 SH7750_A7_REG32(SH7750_RSECAR_REGOFS) | |
457 | +#define SH7750_RSECAR_ENB 0x80 /* Second Alarm Enable */ | |
458 | + | |
459 | +/* Minute Alarm Register (byte, BCD-coded) - RMINAR */ | |
460 | +#define SH7750_RMINAR_REGOFS 0xC80024 /* offset */ | |
461 | +#define SH7750_RMINAR SH7750_P4_REG32(SH7750_RMINAR_REGOFS) | |
462 | +#define SH7750_RMINAR_A7 SH7750_A7_REG32(SH7750_RMINAR_REGOFS) | |
463 | +#define SH7750_RMINAR_ENB 0x80 /* Minute Alarm Enable */ | |
464 | + | |
465 | +/* Hour Alarm Register (byte, BCD-coded) - RHRAR */ | |
466 | +#define SH7750_RHRAR_REGOFS 0xC80028 /* offset */ | |
467 | +#define SH7750_RHRAR SH7750_P4_REG32(SH7750_RHRAR_REGOFS) | |
468 | +#define SH7750_RHRAR_A7 SH7750_A7_REG32(SH7750_RHRAR_REGOFS) | |
469 | +#define SH7750_RHRAR_ENB 0x80 /* Hour Alarm Enable */ | |
470 | + | |
471 | +/* Day-of-Week Alarm Register (byte) - RWKAR */ | |
472 | +#define SH7750_RWKAR_REGOFS 0xC8002C /* offset */ | |
473 | +#define SH7750_RWKAR SH7750_P4_REG32(SH7750_RWKAR_REGOFS) | |
474 | +#define SH7750_RWKAR_A7 SH7750_A7_REG32(SH7750_RWKAR_REGOFS) | |
475 | +#define SH7750_RWKAR_ENB 0x80 /* Day-of-week Alarm Enable */ | |
476 | + | |
477 | +#define SH7750_RWKAR_SUN 0 /* Sunday */ | |
478 | +#define SH7750_RWKAR_MON 1 /* Monday */ | |
479 | +#define SH7750_RWKAR_TUE 2 /* Tuesday */ | |
480 | +#define SH7750_RWKAR_WED 3 /* Wednesday */ | |
481 | +#define SH7750_RWKAR_THU 4 /* Thursday */ | |
482 | +#define SH7750_RWKAR_FRI 5 /* Friday */ | |
483 | +#define SH7750_RWKAR_SAT 6 /* Saturday */ | |
484 | + | |
485 | +/* Day Alarm Register (byte, BCD-coded) - RDAYAR */ | |
486 | +#define SH7750_RDAYAR_REGOFS 0xC80030 /* offset */ | |
487 | +#define SH7750_RDAYAR SH7750_P4_REG32(SH7750_RDAYAR_REGOFS) | |
488 | +#define SH7750_RDAYAR_A7 SH7750_A7_REG32(SH7750_RDAYAR_REGOFS) | |
489 | +#define SH7750_RDAYAR_ENB 0x80 /* Day Alarm Enable */ | |
490 | + | |
491 | +/* Month Counter Register (byte, BCD-coded) - RMONAR */ | |
492 | +#define SH7750_RMONAR_REGOFS 0xC80034 /* offset */ | |
493 | +#define SH7750_RMONAR SH7750_P4_REG32(SH7750_RMONAR_REGOFS) | |
494 | +#define SH7750_RMONAR_A7 SH7750_A7_REG32(SH7750_RMONAR_REGOFS) | |
495 | +#define SH7750_RMONAR_ENB 0x80 /* Month Alarm Enable */ | |
496 | + | |
497 | +/* RTC Control Register 1 (byte) - RCR1 */ | |
498 | +#define SH7750_RCR1_REGOFS 0xC80038 /* offset */ | |
499 | +#define SH7750_RCR1 SH7750_P4_REG32(SH7750_RCR1_REGOFS) | |
500 | +#define SH7750_RCR1_A7 SH7750_A7_REG32(SH7750_RCR1_REGOFS) | |
501 | +#define SH7750_RCR1_CF 0x80 /* Carry Flag */ | |
502 | +#define SH7750_RCR1_CIE 0x10 /* Carry Interrupt Enable */ | |
503 | +#define SH7750_RCR1_AIE 0x08 /* Alarm Interrupt Enable */ | |
504 | +#define SH7750_RCR1_AF 0x01 /* Alarm Flag */ | |
505 | + | |
506 | +/* RTC Control Register 2 (byte) - RCR2 */ | |
507 | +#define SH7750_RCR2_REGOFS 0xC8003C /* offset */ | |
508 | +#define SH7750_RCR2 SH7750_P4_REG32(SH7750_RCR2_REGOFS) | |
509 | +#define SH7750_RCR2_A7 SH7750_A7_REG32(SH7750_RCR2_REGOFS) | |
510 | +#define SH7750_RCR2_PEF 0x80 /* Periodic Interrupt Flag */ | |
511 | +#define SH7750_RCR2_PES 0x70 /* Periodic Interrupt Enable: */ | |
512 | +#define SH7750_RCR2_PES_DIS 0x00 /* Periodic Interrupt Disabled */ | |
513 | +#define SH7750_RCR2_PES_DIV256 0x10 /* Generated at 1/256 sec interval */ | |
514 | +#define SH7750_RCR2_PES_DIV64 0x20 /* Generated at 1/64 sec interval */ | |
515 | +#define SH7750_RCR2_PES_DIV16 0x30 /* Generated at 1/16 sec interval */ | |
516 | +#define SH7750_RCR2_PES_DIV4 0x40 /* Generated at 1/4 sec interval */ | |
517 | +#define SH7750_RCR2_PES_DIV2 0x50 /* Generated at 1/2 sec interval */ | |
518 | +#define SH7750_RCR2_PES_x1 0x60 /* Generated at 1 sec interval */ | |
519 | +#define SH7750_RCR2_PES_x2 0x70 /* Generated at 2 sec interval */ | |
520 | +#define SH7750_RCR2_RTCEN 0x08 /* RTC Crystal Oscillator is Operated */ | |
521 | +#define SH7750_RCR2_ADJ 0x04 /* 30-Second Adjastment */ | |
522 | +#define SH7750_RCR2_RESET 0x02 /* Frequency divider circuits are reset */ | |
523 | +#define SH7750_RCR2_START 0x01 /* 0 - sec, min, hr, day-of-week, month, | |
524 | + year counters are stopped | |
525 | + 1 - sec, min, hr, day-of-week, month, | |
526 | + year counters operate normally */ | |
527 | +/* | |
528 | + * Bus State Controller - BSC | |
529 | + */ | |
530 | +/* Bus Control Register 1 - BCR1 */ | |
531 | +#define SH7750_BCR1_REGOFS 0x800000 /* offset */ | |
532 | +#define SH7750_BCR1 SH7750_P4_REG32(SH7750_BCR1_REGOFS) | |
533 | +#define SH7750_BCR1_A7 SH7750_A7_REG32(SH7750_BCR1_REGOFS) | |
534 | +#define SH7750_BCR1_ENDIAN 0x80000000 /* Endianness (1 - little endian) */ | |
535 | +#define SH7750_BCR1_MASTER 0x40000000 /* Master/Slave mode (1-master) */ | |
536 | +#define SH7750_BCR1_A0MPX 0x20000000 /* Area 0 Memory Type (0-SRAM,1-MPX) */ | |
537 | +#define SH7750_BCR1_IPUP 0x02000000 /* Input Pin Pull-up Control: | |
538 | + 0 - pull-up resistor is on for | |
539 | + control input pins | |
540 | + 1 - pull-up resistor is off */ | |
541 | +#define SH7750_BCR1_OPUP 0x01000000 /* Output Pin Pull-up Control: | |
542 | + 0 - pull-up resistor is on for | |
543 | + control output pins | |
544 | + 1 - pull-up resistor is off */ | |
545 | +#define SH7750_BCR1_A1MBC 0x00200000 /* Area 1 SRAM Byte Control Mode: | |
546 | + 0 - Area 1 SRAM is set to | |
547 | + normal mode | |
548 | + 1 - Area 1 SRAM is set to byte | |
549 | + control mode */ | |
550 | +#define SH7750_BCR1_A4MBC 0x00100000 /* Area 4 SRAM Byte Control Mode: | |
551 | + 0 - Area 4 SRAM is set to | |
552 | + normal mode | |
553 | + 1 - Area 4 SRAM is set to byte | |
554 | + control mode */ | |
555 | +#define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable: | |
556 | + 0 - External requests are not | |
557 | + accepted | |
558 | + 1 - External requests are | |
559 | + accepted */ | |
560 | +#define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit: | |
561 | + 0 - Master Mode | |
562 | + 1 - Partial-sharing Mode */ | |
563 | +#define SH7750_BCR1_MEMMPX 0x00020000 /* Area 1 to 6 MPX Interface: | |
564 | + 0 - SRAM/burst ROM interface | |
565 | + 1 - MPX interface */ | |
566 | +#define SH7750_BCR1_HIZMEM 0x00008000 /* High Impendance Control. Specifies | |
567 | + the state of A[25:0], BS\, CSn\, | |
568 | + RD/WR\, CE2A\, CE2B\ in standby | |
569 | + mode and when bus is released: | |
570 | + 0 - signals go to High-Z mode | |
571 | + 1 - signals driven */ | |
572 | +#define SH7750_BCR1_HIZCNT 0x00004000 /* High Impendance Control. Specifies | |
573 | + the state of the RAS\, RAS2\, WEn\, | |
574 | + CASn\, DQMn, RD\, CASS\, FRAME\, | |
575 | + RD2\ signals in standby mode and | |
576 | + when bus is released: | |
577 | + 0 - signals go to High-Z mode | |
578 | + 1 - signals driven */ | |
579 | +#define SH7750_BCR1_A0BST 0x00003800 /* Area 0 Burst ROM Control */ | |
580 | +#define SH7750_BCR1_A0BST_SRAM 0x0000 /* Area 0 accessed as SRAM i/f */ | |
581 | +#define SH7750_BCR1_A0BST_ROM4 0x0800 /* Area 0 accessed as burst ROM | |
582 | + interface, 4 cosequtive access */ | |
583 | +#define SH7750_BCR1_A0BST_ROM8 0x1000 /* Area 0 accessed as burst ROM | |
584 | + interface, 8 cosequtive access */ | |
585 | +#define SH7750_BCR1_A0BST_ROM16 0x1800 /* Area 0 accessed as burst ROM | |
586 | + interface, 16 cosequtive access */ | |
587 | +#define SH7750_BCR1_A0BST_ROM32 0x2000 /* Area 0 accessed as burst ROM | |
588 | + interface, 32 cosequtive access */ | |
589 | + | |
590 | +#define SH7750_BCR1_A5BST 0x00000700 /* Area 5 Burst ROM Control */ | |
591 | +#define SH7750_BCR1_A5BST_SRAM 0x0000 /* Area 5 accessed as SRAM i/f */ | |
592 | +#define SH7750_BCR1_A5BST_ROM4 0x0100 /* Area 5 accessed as burst ROM | |
593 | + interface, 4 cosequtive access */ | |
594 | +#define SH7750_BCR1_A5BST_ROM8 0x0200 /* Area 5 accessed as burst ROM | |
595 | + interface, 8 cosequtive access */ | |
596 | +#define SH7750_BCR1_A5BST_ROM16 0x0300 /* Area 5 accessed as burst ROM | |
597 | + interface, 16 cosequtive access */ | |
598 | +#define SH7750_BCR1_A5BST_ROM32 0x0400 /* Area 5 accessed as burst ROM | |
599 | + interface, 32 cosequtive access */ | |
600 | + | |
601 | +#define SH7750_BCR1_A6BST 0x000000E0 /* Area 6 Burst ROM Control */ | |
602 | +#define SH7750_BCR1_A6BST_SRAM 0x0000 /* Area 6 accessed as SRAM i/f */ | |
603 | +#define SH7750_BCR1_A6BST_ROM4 0x0020 /* Area 6 accessed as burst ROM | |
604 | + interface, 4 cosequtive access */ | |
605 | +#define SH7750_BCR1_A6BST_ROM8 0x0040 /* Area 6 accessed as burst ROM | |
606 | + interface, 8 cosequtive access */ | |
607 | +#define SH7750_BCR1_A6BST_ROM16 0x0060 /* Area 6 accessed as burst ROM | |
608 | + interface, 16 cosequtive access */ | |
609 | +#define SH7750_BCR1_A6BST_ROM32 0x0080 /* Area 6 accessed as burst ROM | |
610 | + interface, 32 cosequtive access */ | |
611 | + | |
612 | +#define SH7750_BCR1_DRAMTP 0x001C /* Area 2 and 3 Memory Type */ | |
613 | +#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM 0x0000 /* Area 2 and 3 are SRAM or MPX | |
614 | + interface. */ | |
615 | +#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM 0x0008 /* Area 2 - SRAM/MPX, Area 3 - | |
616 | + synchronous DRAM */ | |
617 | +#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C /* Area 2 and 3 are synchronous | |
618 | + DRAM interface */ | |
619 | +#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM 0x0010 /* Area 2 - SRAM/MPX, Area 3 - | |
620 | + DRAM interface */ | |
621 | +#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM 0x0014 /* Area 2 and 3 are DRAM | |
622 | + interface */ | |
623 | + | |
624 | +#define SH7750_BCR1_A56PCM 0x00000001 /* Area 5 and 6 Bus Type: | |
625 | + 0 - SRAM interface | |
626 | + 1 - PCMCIA interface */ | |
627 | + | |
628 | +/* Bus Control Register 2 (half) - BCR2 */ | |
629 | +#define SH7750_BCR2_REGOFS 0x800004 /* offset */ | |
630 | +#define SH7750_BCR2 SH7750_P4_REG32(SH7750_BCR2_REGOFS) | |
631 | +#define SH7750_BCR2_A7 SH7750_A7_REG32(SH7750_BCR2_REGOFS) | |
632 | + | |
633 | +#define SH7750_BCR2_A0SZ 0xC000 /* Area 0 Bus Width */ | |
634 | +#define SH7750_BCR2_A0SZ_S 14 | |
635 | +#define SH7750_BCR2_A6SZ 0x3000 /* Area 6 Bus Width */ | |
636 | +#define SH7750_BCR2_A6SZ_S 12 | |
637 | +#define SH7750_BCR2_A5SZ 0x0C00 /* Area 5 Bus Width */ | |
638 | +#define SH7750_BCR2_A5SZ_S 10 | |
639 | +#define SH7750_BCR2_A4SZ 0x0300 /* Area 4 Bus Width */ | |
640 | +#define SH7750_BCR2_A4SZ_S 8 | |
641 | +#define SH7750_BCR2_A3SZ 0x00C0 /* Area 3 Bus Width */ | |
642 | +#define SH7750_BCR2_A3SZ_S 6 | |
643 | +#define SH7750_BCR2_A2SZ 0x0030 /* Area 2 Bus Width */ | |
644 | +#define SH7750_BCR2_A2SZ_S 4 | |
645 | +#define SH7750_BCR2_A1SZ 0x000C /* Area 1 Bus Width */ | |
646 | +#define SH7750_BCR2_A1SZ_S 2 | |
647 | +#define SH7750_BCR2_SZ_64 0 /* 64 bits */ | |
648 | +#define SH7750_BCR2_SZ_8 1 /* 8 bits */ | |
649 | +#define SH7750_BCR2_SZ_16 2 /* 16 bits */ | |
650 | +#define SH7750_BCR2_SZ_32 3 /* 32 bits */ | |
651 | +#define SH7750_BCR2_PORTEN 0x0001 /* Port Function Enable : | |
652 | + 0 - D51-D32 are not used as a port | |
653 | + 1 - D51-D32 are used as a port */ | |
654 | + | |
655 | +/* Wait Control Register 1 - WCR1 */ | |
656 | +#define SH7750_WCR1_REGOFS 0x800008 /* offset */ | |
657 | +#define SH7750_WCR1 SH7750_P4_REG32(SH7750_WCR1_REGOFS) | |
658 | +#define SH7750_WCR1_A7 SH7750_A7_REG32(SH7750_WCR1_REGOFS) | |
659 | +#define SH7750_WCR1_DMAIW 0x70000000 /* DACK Device Inter-Cycle Idle | |
660 | + specification */ | |
661 | +#define SH7750_WCR1_DMAIW_S 28 | |
662 | +#define SH7750_WCR1_A6IW 0x07000000 /* Area 6 Inter-Cycle Idle spec. */ | |
663 | +#define SH7750_WCR1_A6IW_S 24 | |
664 | +#define SH7750_WCR1_A5IW 0x00700000 /* Area 5 Inter-Cycle Idle spec. */ | |
665 | +#define SH7750_WCR1_A5IW_S 20 | |
666 | +#define SH7750_WCR1_A4IW 0x00070000 /* Area 4 Inter-Cycle Idle spec. */ | |
667 | +#define SH7750_WCR1_A4IW_S 16 | |
668 | +#define SH7750_WCR1_A3IW 0x00007000 /* Area 3 Inter-Cycle Idle spec. */ | |
669 | +#define SH7750_WCR1_A3IW_S 12 | |
670 | +#define SH7750_WCR1_A2IW 0x00000700 /* Area 2 Inter-Cycle Idle spec. */ | |
671 | +#define SH7750_WCR1_A2IW_S 8 | |
672 | +#define SH7750_WCR1_A1IW 0x00000070 /* Area 1 Inter-Cycle Idle spec. */ | |
673 | +#define SH7750_WCR1_A1IW_S 4 | |
674 | +#define SH7750_WCR1_A0IW 0x00000007 /* Area 0 Inter-Cycle Idle spec. */ | |
675 | +#define SH7750_WCR1_A0IW_S 0 | |
676 | + | |
677 | +/* Wait Control Register 2 - WCR2 */ | |
678 | +#define SH7750_WCR2_REGOFS 0x80000C /* offset */ | |
679 | +#define SH7750_WCR2 SH7750_P4_REG32(SH7750_WCR2_REGOFS) | |
680 | +#define SH7750_WCR2_A7 SH7750_A7_REG32(SH7750_WCR2_REGOFS) | |
681 | + | |
682 | +#define SH7750_WCR2_A6W 0xE0000000 /* Area 6 Wait Control */ | |
683 | +#define SH7750_WCR2_A6W_S 29 | |
684 | +#define SH7750_WCR2_A6B 0x1C000000 /* Area 6 Burst Pitch */ | |
685 | +#define SH7750_WCR2_A6B_S 26 | |
686 | +#define SH7750_WCR2_A5W 0x03800000 /* Area 5 Wait Control */ | |
687 | +#define SH7750_WCR2_A5W_S 23 | |
688 | +#define SH7750_WCR2_A5B 0x00700000 /* Area 5 Burst Pitch */ | |
689 | +#define SH7750_WCR2_A5B_S 20 | |
690 | +#define SH7750_WCR2_A4W 0x000E0000 /* Area 4 Wait Control */ | |
691 | +#define SH7750_WCR2_A4W_S 17 | |
692 | +#define SH7750_WCR2_A3W 0x0000E000 /* Area 3 Wait Control */ | |
693 | +#define SH7750_WCR2_A3W_S 13 | |
694 | +#define SH7750_WCR2_A2W 0x00000E00 /* Area 2 Wait Control */ | |
695 | +#define SH7750_WCR2_A2W_S 9 | |
696 | +#define SH7750_WCR2_A1W 0x000001C0 /* Area 1 Wait Control */ | |
697 | +#define SH7750_WCR2_A1W_S 6 | |
698 | +#define SH7750_WCR2_A0W 0x00000038 /* Area 0 Wait Control */ | |
699 | +#define SH7750_WCR2_A0W_S 3 | |
700 | +#define SH7750_WCR2_A0B 0x00000007 /* Area 0 Burst Pitch */ | |
701 | +#define SH7750_WCR2_A0B_S 0 | |
702 | + | |
703 | +#define SH7750_WCR2_WS0 0 /* 0 wait states inserted */ | |
704 | +#define SH7750_WCR2_WS1 1 /* 1 wait states inserted */ | |
705 | +#define SH7750_WCR2_WS2 2 /* 2 wait states inserted */ | |
706 | +#define SH7750_WCR2_WS3 3 /* 3 wait states inserted */ | |
707 | +#define SH7750_WCR2_WS6 4 /* 6 wait states inserted */ | |
708 | +#define SH7750_WCR2_WS9 5 /* 9 wait states inserted */ | |
709 | +#define SH7750_WCR2_WS12 6 /* 12 wait states inserted */ | |
710 | +#define SH7750_WCR2_WS15 7 /* 15 wait states inserted */ | |
711 | + | |
712 | +#define SH7750_WCR2_BPWS0 0 /* 0 wait states inserted from 2nd access */ | |
713 | +#define SH7750_WCR2_BPWS1 1 /* 1 wait states inserted from 2nd access */ | |
714 | +#define SH7750_WCR2_BPWS2 2 /* 2 wait states inserted from 2nd access */ | |
715 | +#define SH7750_WCR2_BPWS3 3 /* 3 wait states inserted from 2nd access */ | |
716 | +#define SH7750_WCR2_BPWS4 4 /* 4 wait states inserted from 2nd access */ | |
717 | +#define SH7750_WCR2_BPWS5 5 /* 5 wait states inserted from 2nd access */ | |
718 | +#define SH7750_WCR2_BPWS6 6 /* 6 wait states inserted from 2nd access */ | |
719 | +#define SH7750_WCR2_BPWS7 7 /* 7 wait states inserted from 2nd access */ | |
720 | + | |
721 | +/* DRAM CAS\ Assertion Delay (area 3,2) */ | |
722 | +#define SH7750_WCR2_DRAM_CAS_ASW1 0 /* 1 cycle */ | |
723 | +#define SH7750_WCR2_DRAM_CAS_ASW2 1 /* 2 cycles */ | |
724 | +#define SH7750_WCR2_DRAM_CAS_ASW3 2 /* 3 cycles */ | |
725 | +#define SH7750_WCR2_DRAM_CAS_ASW4 3 /* 4 cycles */ | |
726 | +#define SH7750_WCR2_DRAM_CAS_ASW7 4 /* 7 cycles */ | |
727 | +#define SH7750_WCR2_DRAM_CAS_ASW10 5 /* 10 cycles */ | |
728 | +#define SH7750_WCR2_DRAM_CAS_ASW13 6 /* 13 cycles */ | |
729 | +#define SH7750_WCR2_DRAM_CAS_ASW16 7 /* 16 cycles */ | |
730 | + | |
731 | +/* SDRAM CAS\ Latency Cycles */ | |
732 | +#define SH7750_WCR2_SDRAM_CAS_LAT1 1 /* 1 cycle */ | |
733 | +#define SH7750_WCR2_SDRAM_CAS_LAT2 2 /* 2 cycles */ | |
734 | +#define SH7750_WCR2_SDRAM_CAS_LAT3 3 /* 3 cycles */ | |
735 | +#define SH7750_WCR2_SDRAM_CAS_LAT4 4 /* 4 cycles */ | |
736 | +#define SH7750_WCR2_SDRAM_CAS_LAT5 5 /* 5 cycles */ | |
737 | + | |
738 | +/* Wait Control Register 3 - WCR3 */ | |
739 | +#define SH7750_WCR3_REGOFS 0x800010 /* offset */ | |
740 | +#define SH7750_WCR3 SH7750_P4_REG32(SH7750_WCR3_REGOFS) | |
741 | +#define SH7750_WCR3_A7 SH7750_A7_REG32(SH7750_WCR3_REGOFS) | |
742 | + | |
743 | +#define SH7750_WCR3_A6S 0x04000000 /* Area 6 Write Strobe Setup time */ | |
744 | +#define SH7750_WCR3_A6H 0x03000000 /* Area 6 Data Hold Time */ | |
745 | +#define SH7750_WCR3_A6H_S 24 | |
746 | +#define SH7750_WCR3_A5S 0x00400000 /* Area 5 Write Strobe Setup time */ | |
747 | +#define SH7750_WCR3_A5H 0x00300000 /* Area 5 Data Hold Time */ | |
748 | +#define SH7750_WCR3_A5H_S 20 | |
749 | +#define SH7750_WCR3_A4S 0x00040000 /* Area 4 Write Strobe Setup time */ | |
750 | +#define SH7750_WCR3_A4H 0x00030000 /* Area 4 Data Hold Time */ | |
751 | +#define SH7750_WCR3_A4H_S 16 | |
752 | +#define SH7750_WCR3_A3S 0x00004000 /* Area 3 Write Strobe Setup time */ | |
753 | +#define SH7750_WCR3_A3H 0x00003000 /* Area 3 Data Hold Time */ | |
754 | +#define SH7750_WCR3_A3H_S 12 | |
755 | +#define SH7750_WCR3_A2S 0x00000400 /* Area 2 Write Strobe Setup time */ | |
756 | +#define SH7750_WCR3_A2H 0x00000300 /* Area 2 Data Hold Time */ | |
757 | +#define SH7750_WCR3_A2H_S 8 | |
758 | +#define SH7750_WCR3_A1S 0x00000040 /* Area 1 Write Strobe Setup time */ | |
759 | +#define SH7750_WCR3_A1H 0x00000030 /* Area 1 Data Hold Time */ | |
760 | +#define SH7750_WCR3_A1H_S 4 | |
761 | +#define SH7750_WCR3_A0S 0x00000004 /* Area 0 Write Strobe Setup time */ | |
762 | +#define SH7750_WCR3_A0H 0x00000003 /* Area 0 Data Hold Time */ | |
763 | +#define SH7750_WCR3_A0H_S 0 | |
764 | + | |
765 | +#define SH7750_WCR3_DHWS_0 0 /* 0 wait states data hold time */ | |
766 | +#define SH7750_WCR3_DHWS_1 1 /* 1 wait states data hold time */ | |
767 | +#define SH7750_WCR3_DHWS_2 2 /* 2 wait states data hold time */ | |
768 | +#define SH7750_WCR3_DHWS_3 3 /* 3 wait states data hold time */ | |
769 | + | |
770 | +#define SH7750_MCR_REGOFS 0x800014 /* offset */ | |
771 | +#define SH7750_MCR SH7750_P4_REG32(SH7750_MCR_REGOFS) | |
772 | +#define SH7750_MCR_A7 SH7750_A7_REG32(SH7750_MCR_REGOFS) | |
773 | + | |
774 | +#define SH7750_MCR_RASD 0x80000000 /* RAS Down mode */ | |
775 | +#define SH7750_MCR_MRSET 0x40000000 /* SDRAM Mode Register Set */ | |
776 | +#define SH7750_MCR_PALL 0x00000000 /* SDRAM Precharge All cmd. Mode */ | |
777 | +#define SH7750_MCR_TRC 0x38000000 /* RAS Precharge Time at End of | |
778 | + Refresh: */ | |
779 | +#define SH7750_MCR_TRC_0 0x00000000 /* 0 */ | |
780 | +#define SH7750_MCR_TRC_3 0x08000000 /* 3 */ | |
781 | +#define SH7750_MCR_TRC_6 0x10000000 /* 6 */ | |
782 | +#define SH7750_MCR_TRC_9 0x18000000 /* 9 */ | |
783 | +#define SH7750_MCR_TRC_12 0x20000000 /* 12 */ | |
784 | +#define SH7750_MCR_TRC_15 0x28000000 /* 15 */ | |
785 | +#define SH7750_MCR_TRC_18 0x30000000 /* 18 */ | |
786 | +#define SH7750_MCR_TRC_21 0x38000000 /* 21 */ | |
787 | + | |
788 | +#define SH7750_MCR_TCAS 0x00800000 /* CAS Negation Period */ | |
789 | +#define SH7750_MCR_TCAS_1 0x00000000 /* 1 */ | |
790 | +#define SH7750_MCR_TCAS_2 0x00800000 /* 2 */ | |
791 | + | |
792 | +#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period | |
793 | + SDRAM: minimum number of cycles | |
794 | + until the next bank active cmd | |
795 | + is output after precharging */ | |
796 | +#define SH7750_MCR_TPC_S 19 | |
797 | +#define SH7750_MCR_TPC_SDRAM_1 0x00000000 /* 1 cycle */ | |
798 | +#define SH7750_MCR_TPC_SDRAM_2 0x00080000 /* 2 cycles */ | |
799 | +#define SH7750_MCR_TPC_SDRAM_3 0x00100000 /* 3 cycles */ | |
800 | +#define SH7750_MCR_TPC_SDRAM_4 0x00180000 /* 4 cycles */ | |
801 | +#define SH7750_MCR_TPC_SDRAM_5 0x00200000 /* 5 cycles */ | |
802 | +#define SH7750_MCR_TPC_SDRAM_6 0x00280000 /* 6 cycles */ | |
803 | +#define SH7750_MCR_TPC_SDRAM_7 0x00300000 /* 7 cycles */ | |
804 | +#define SH7750_MCR_TPC_SDRAM_8 0x00380000 /* 8 cycles */ | |
805 | + | |
806 | +#define SH7750_MCR_RCD 0x00030000 /* DRAM: RAS-CAS Assertion Delay time | |
807 | + SDRAM: bank active-read/write cmd | |
808 | + delay time */ | |
809 | +#define SH7750_MCR_RCD_DRAM_2 0x00000000 /* DRAM delay 2 clocks */ | |
810 | +#define SH7750_MCR_RCD_DRAM_3 0x00010000 /* DRAM delay 3 clocks */ | |
811 | +#define SH7750_MCR_RCD_DRAM_4 0x00020000 /* DRAM delay 4 clocks */ | |
812 | +#define SH7750_MCR_RCD_DRAM_5 0x00030000 /* DRAM delay 5 clocks */ | |
813 | +#define SH7750_MCR_RCD_SDRAM_2 0x00010000 /* DRAM delay 2 clocks */ | |
814 | +#define SH7750_MCR_RCD_SDRAM_3 0x00020000 /* DRAM delay 3 clocks */ | |
815 | +#define SH7750_MCR_RCD_SDRAM_4 0x00030000 /* DRAM delay 4 clocks */ | |
816 | + | |
817 | +#define SH7750_MCR_TRWL 0x0000E000 /* SDRAM Write Precharge Delay */ | |
818 | +#define SH7750_MCR_TRWL_1 0x00000000 /* 1 */ | |
819 | +#define SH7750_MCR_TRWL_2 0x00002000 /* 2 */ | |
820 | +#define SH7750_MCR_TRWL_3 0x00004000 /* 3 */ | |
821 | +#define SH7750_MCR_TRWL_4 0x00006000 /* 4 */ | |
822 | +#define SH7750_MCR_TRWL_5 0x00008000 /* 5 */ | |
823 | + | |
824 | +#define SH7750_MCR_TRAS 0x00001C00 /* DRAM: CAS-Before-RAS Refresh RAS | |
825 | + asserting period | |
826 | + SDRAM: Command interval after | |
827 | + synchronous DRAM refresh */ | |
828 | +#define SH7750_MCR_TRAS_DRAM_2 0x00000000 /* 2 */ | |
829 | +#define SH7750_MCR_TRAS_DRAM_3 0x00000400 /* 3 */ | |
830 | +#define SH7750_MCR_TRAS_DRAM_4 0x00000800 /* 4 */ | |
831 | +#define SH7750_MCR_TRAS_DRAM_5 0x00000C00 /* 5 */ | |
832 | +#define SH7750_MCR_TRAS_DRAM_6 0x00001000 /* 6 */ | |
833 | +#define SH7750_MCR_TRAS_DRAM_7 0x00001400 /* 7 */ | |
834 | +#define SH7750_MCR_TRAS_DRAM_8 0x00001800 /* 8 */ | |
835 | +#define SH7750_MCR_TRAS_DRAM_9 0x00001C00 /* 9 */ | |
836 | + | |
837 | +#define SH7750_MCR_TRAS_SDRAM_TRC_4 0x00000000 /* 4 + TRC */ | |
838 | +#define SH7750_MCR_TRAS_SDRAM_TRC_5 0x00000400 /* 5 + TRC */ | |
839 | +#define SH7750_MCR_TRAS_SDRAM_TRC_6 0x00000800 /* 6 + TRC */ | |
840 | +#define SH7750_MCR_TRAS_SDRAM_TRC_7 0x00000C00 /* 7 + TRC */ | |
841 | +#define SH7750_MCR_TRAS_SDRAM_TRC_8 0x00001000 /* 8 + TRC */ | |
842 | +#define SH7750_MCR_TRAS_SDRAM_TRC_9 0x00001400 /* 9 + TRC */ | |
843 | +#define SH7750_MCR_TRAS_SDRAM_TRC_10 0x00001800 /* 10 + TRC */ | |
844 | +#define SH7750_MCR_TRAS_SDRAM_TRC_11 0x00001C00 /* 11 + TRC */ | |
845 | + | |
846 | +#define SH7750_MCR_BE 0x00000200 /* Burst Enable */ | |
847 | +#define SH7750_MCR_SZ 0x00000180 /* Memory Data Size */ | |
848 | +#define SH7750_MCR_SZ_64 0x00000000 /* 64 bits */ | |
849 | +#define SH7750_MCR_SZ_16 0x00000100 /* 16 bits */ | |
850 | +#define SH7750_MCR_SZ_32 0x00000180 /* 32 bits */ | |
851 | + | |
852 | +#define SH7750_MCR_AMX 0x00000078 /* Address Multiplexing */ | |
853 | +#define SH7750_MCR_AMX_S 3 | |
854 | +#define SH7750_MCR_AMX_DRAM_8BIT_COL 0x00000000 /* 8-bit column addr */ | |
855 | +#define SH7750_MCR_AMX_DRAM_9BIT_COL 0x00000008 /* 9-bit column addr */ | |
856 | +#define SH7750_MCR_AMX_DRAM_10BIT_COL 0x00000010 /* 10-bit column addr */ | |
857 | +#define SH7750_MCR_AMX_DRAM_11BIT_COL 0x00000018 /* 11-bit column addr */ | |
858 | +#define SH7750_MCR_AMX_DRAM_12BIT_COL 0x00000020 /* 12-bit column addr */ | |
859 | +/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */ | |
860 | + | |
861 | +#define SH7750_MCR_RFSH 0x00000004 /* Refresh Control */ | |
862 | +#define SH7750_MCR_RMODE 0x00000002 /* Refresh Mode: */ | |
863 | +#define SH7750_MCR_RMODE_NORMAL 0x00000000 /* Normal Refresh Mode */ | |
864 | +#define SH7750_MCR_RMODE_SELF 0x00000002 /* Self-Refresh Mode */ | |
865 | +#define SH7750_MCR_RMODE_EDO 0x00000001 /* EDO Mode */ | |
866 | + | |
867 | +/* SDRAM Mode Set address */ | |
868 | +#define SH7750_SDRAM_MODE_A2_BASE 0xFF900000 | |
869 | +#define SH7750_SDRAM_MODE_A3_BASE 0xFF940000 | |
870 | +#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2)) | |
871 | +#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2)) | |
872 | +#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3)) | |
873 | +#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3)) | |
874 | + | |
875 | + | |
876 | +/* PCMCIA Control Register (half) - PCR */ | |
877 | +#define SH7750_PCR_REGOFS 0x800018 /* offset */ | |
878 | +#define SH7750_PCR SH7750_P4_REG32(SH7750_PCR_REGOFS) | |
879 | +#define SH7750_PCR_A7 SH7750_A7_REG32(SH7750_PCR_REGOFS) | |
880 | + | |
881 | +#define SH7750_PCR_A5PCW 0xC000 /* Area 5 PCMCIA Wait - Number of wait | |
882 | + states to be added to the number of | |
883 | + waits specified by WCR2 in a low-speed | |
884 | + PCMCIA wait cycle */ | |
885 | +#define SH7750_PCR_A5PCW_0 0x0000 /* 0 waits inserted */ | |
886 | +#define SH7750_PCR_A5PCW_15 0x4000 /* 15 waits inserted */ | |
887 | +#define SH7750_PCR_A5PCW_30 0x8000 /* 30 waits inserted */ | |
888 | +#define SH7750_PCR_A5PCW_50 0xC000 /* 50 waits inserted */ | |
889 | + | |
890 | +#define SH7750_PCR_A6PCW 0x3000 /* Area 6 PCMCIA Wait - Number of wait | |
891 | + states to be added to the number of | |
892 | + waits specified by WCR2 in a low-speed | |
893 | + PCMCIA wait cycle */ | |
894 | +#define SH7750_PCR_A6PCW_0 0x0000 /* 0 waits inserted */ | |
895 | +#define SH7750_PCR_A6PCW_15 0x1000 /* 15 waits inserted */ | |
896 | +#define SH7750_PCR_A6PCW_30 0x2000 /* 30 waits inserted */ | |
897 | +#define SH7750_PCR_A6PCW_50 0x3000 /* 50 waits inserted */ | |
898 | + | |
899 | +#define SH7750_PCR_A5TED 0x0E00 /* Area 5 Address-OE\/WE\ Assertion Delay, | |
900 | + delay time from address output to | |
901 | + OE\/WE\ assertion on the connected | |
902 | + PCMCIA interface */ | |
903 | +#define SH7750_PCR_A5TED_S 9 | |
904 | +#define SH7750_PCR_A6TED 0x01C0 /* Area 6 Address-OE\/WE\ Assertion Delay */ | |
905 | +#define SH7750_PCR_A6TED_S 6 | |
906 | + | |
907 | +#define SH7750_PCR_TED_0WS 0 /* 0 Waits inserted */ | |
908 | +#define SH7750_PCR_TED_1WS 1 /* 1 Waits inserted */ | |
909 | +#define SH7750_PCR_TED_2WS 2 /* 2 Waits inserted */ | |
910 | +#define SH7750_PCR_TED_3WS 3 /* 3 Waits inserted */ | |
911 | +#define SH7750_PCR_TED_6WS 4 /* 6 Waits inserted */ | |
912 | +#define SH7750_PCR_TED_9WS 5 /* 9 Waits inserted */ | |
913 | +#define SH7750_PCR_TED_12WS 6 /* 12 Waits inserted */ | |
914 | +#define SH7750_PCR_TED_15WS 7 /* 15 Waits inserted */ | |
915 | + | |
916 | +#define SH7750_PCR_A5TEH 0x0038 /* Area 5 OE\/WE\ Negation Address delay, | |
917 | + address hold delay time from OE\/WE\ | |
918 | + negation in a write on the connected | |
919 | + PCMCIA interface */ | |
920 | +#define SH7750_PCR_A5TEH_S 3 | |
921 | + | |
922 | +#define SH7750_PCR_A6TEH 0x0007 /* Area 6 OE\/WE\ Negation Address delay */ | |
923 | +#define SH7750_PCR_A6TEH_S 0 | |
924 | + | |
925 | +#define SH7750_PCR_TEH_0WS 0 /* 0 Waits inserted */ | |
926 | +#define SH7750_PCR_TEH_1WS 1 /* 1 Waits inserted */ | |
927 | +#define SH7750_PCR_TEH_2WS 2 /* 2 Waits inserted */ | |
928 | +#define SH7750_PCR_TEH_3WS 3 /* 3 Waits inserted */ | |
929 | +#define SH7750_PCR_TEH_6WS 4 /* 6 Waits inserted */ | |
930 | +#define SH7750_PCR_TEH_9WS 5 /* 9 Waits inserted */ | |
931 | +#define SH7750_PCR_TEH_12WS 6 /* 12 Waits inserted */ | |
932 | +#define SH7750_PCR_TEH_15WS 7 /* 15 Waits inserted */ | |
933 | + | |
934 | +/* Refresh Timer Control/Status Register (half) - RTSCR */ | |
935 | +#define SH7750_RTCSR_REGOFS 0x80001C /* offset */ | |
936 | +#define SH7750_RTCSR SH7750_P4_REG32(SH7750_RTCSR_REGOFS) | |
937 | +#define SH7750_RTCSR_A7 SH7750_A7_REG32(SH7750_RTCSR_REGOFS) | |
938 | + | |
939 | +#define SH7750_RTCSR_KEY 0xA500 /* RTCSR write key */ | |
940 | +#define SH7750_RTCSR_CMF 0x0080 /* Compare-Match Flag (indicates a | |
941 | + match between the refresh timer | |
942 | + counter and refresh time constant) */ | |
943 | +#define SH7750_RTCSR_CMIE 0x0040 /* Compare-Match Interrupt Enable */ | |
944 | +#define SH7750_RTCSR_CKS 0x0038 /* Refresh Counter Clock Selects */ | |
945 | +#define SH7750_RTCSR_CKS_DIS 0x0000 /* Clock Input Disabled */ | |
946 | +#define SH7750_RTCSR_CKS_CKIO_DIV4 0x0008 /* Bus Clock / 4 */ | |
947 | +#define SH7750_RTCSR_CKS_CKIO_DIV16 0x0010 /* Bus Clock / 16 */ | |
948 | +#define SH7750_RTCSR_CKS_CKIO_DIV64 0x0018 /* Bus Clock / 64 */ | |
949 | +#define SH7750_RTCSR_CKS_CKIO_DIV256 0x0020 /* Bus Clock / 256 */ | |
950 | +#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028 /* Bus Clock / 1024 */ | |
951 | +#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030 /* Bus Clock / 2048 */ | |
952 | +#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038 /* Bus Clock / 4096 */ | |
953 | + | |
954 | +#define SH7750_RTCSR_OVF 0x0004 /* Refresh Count Overflow Flag */ | |
955 | +#define SH7750_RTCSR_OVIE 0x0002 /* Refresh Count Overflow Interrupt | |
956 | + Enable */ | |
957 | +#define SH7750_RTCSR_LMTS 0x0001 /* Refresh Count Overflow Limit Select */ | |
958 | +#define SH7750_RTCSR_LMTS_1024 0x0000 /* Count Limit is 1024 */ | |
959 | +#define SH7750_RTCSR_LMTS_512 0x0001 /* Count Limit is 512 */ | |
960 | + | |
961 | +/* Refresh Timer Counter (half) - RTCNT */ | |
962 | +#define SH7750_RTCNT_REGOFS 0x800020 /* offset */ | |
963 | +#define SH7750_RTCNT SH7750_P4_REG32(SH7750_RTCNT_REGOFS) | |
964 | +#define SH7750_RTCNT_A7 SH7750_A7_REG32(SH7750_RTCNT_REGOFS) | |
965 | + | |
966 | +#define SH7750_RTCNT_KEY 0xA500 /* RTCNT write key */ | |
967 | + | |
968 | +/* Refresh Time Constant Register (half) - RTCOR */ | |
969 | +#define SH7750_RTCOR_REGOFS 0x800024 /* offset */ | |
970 | +#define SH7750_RTCOR SH7750_P4_REG32(SH7750_RTCOR_REGOFS) | |
971 | +#define SH7750_RTCOR_A7 SH7750_A7_REG32(SH7750_RTCOR_REGOFS) | |
972 | + | |
973 | +#define SH7750_RTCOR_KEY 0xA500 /* RTCOR write key */ | |
974 | + | |
975 | +/* Refresh Count Register (half) - RFCR */ | |
976 | +#define SH7750_RFCR_REGOFS 0x800028 /* offset */ | |
977 | +#define SH7750_RFCR SH7750_P4_REG32(SH7750_RFCR_REGOFS) | |
978 | +#define SH7750_RFCR_A7 SH7750_A7_REG32(SH7750_RFCR_REGOFS) | |
979 | + | |
980 | +#define SH7750_RFCR_KEY 0xA400 /* RFCR write key */ | |
981 | + | |
982 | +/* Synchronous DRAM mode registers - SDMR */ | |
983 | +#define SH7750_SDMR2_REGOFS 0x900000 /* base offset */ | |
984 | +#define SH7750_SDMR2_REGNB 0x0FFC /* nb of register */ | |
985 | +#define SH7750_SDMR2 SH7750_P4_REG32(SH7750_SDMR2_REGOFS) | |
986 | +#define SH7750_SDMR2_A7 SH7750_A7_REG32(SH7750_SDMR2_REGOFS) | |
987 | + | |
988 | +#define SH7750_SDMR3_REGOFS 0x940000 /* offset */ | |
989 | +#define SH7750_SDMR3_REGNB 0x0FFC /* nb of register */ | |
990 | +#define SH7750_SDMR3 SH7750_P4_REG32(SH7750_SDMR3_REGOFS) | |
991 | +#define SH7750_SDMR3_A7 SH7750_A7_REG32(SH7750_SDMR3_REGOFS) | |
992 | + | |
993 | +/* | |
994 | + * Direct Memory Access Controller (DMAC) | |
995 | + */ | |
996 | + | |
997 | +/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */ | |
998 | +#define SH7750_SAR_REGOFS(n) (0xA00000 + ((n)*16)) /* offset */ | |
999 | +#define SH7750_SAR(n) SH7750_P4_REG32(SH7750_SAR_REGOFS(n)) | |
1000 | +#define SH7750_SAR_A7(n) SH7750_A7_REG32(SH7750_SAR_REGOFS(n)) | |
1001 | +#define SH7750_SAR0 SH7750_SAR(0) | |
1002 | +#define SH7750_SAR1 SH7750_SAR(1) | |
1003 | +#define SH7750_SAR2 SH7750_SAR(2) | |
1004 | +#define SH7750_SAR3 SH7750_SAR(3) | |
1005 | +#define SH7750_SAR0_A7 SH7750_SAR_A7(0) | |
1006 | +#define SH7750_SAR1_A7 SH7750_SAR_A7(1) | |
1007 | +#define SH7750_SAR2_A7 SH7750_SAR_A7(2) | |
1008 | +#define SH7750_SAR3_A7 SH7750_SAR_A7(3) | |
1009 | + | |
1010 | +/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */ | |
1011 | +#define SH7750_DAR_REGOFS(n) (0xA00004 + ((n)*16)) /* offset */ | |
1012 | +#define SH7750_DAR(n) SH7750_P4_REG32(SH7750_DAR_REGOFS(n)) | |
1013 | +#define SH7750_DAR_A7(n) SH7750_A7_REG32(SH7750_DAR_REGOFS(n)) | |
1014 | +#define SH7750_DAR0 SH7750_DAR(0) | |
1015 | +#define SH7750_DAR1 SH7750_DAR(1) | |
1016 | +#define SH7750_DAR2 SH7750_DAR(2) | |
1017 | +#define SH7750_DAR3 SH7750_DAR(3) | |
1018 | +#define SH7750_DAR0_A7 SH7750_DAR_A7(0) | |
1019 | +#define SH7750_DAR1_A7 SH7750_DAR_A7(1) | |
1020 | +#define SH7750_DAR2_A7 SH7750_DAR_A7(2) | |
1021 | +#define SH7750_DAR3_A7 SH7750_DAR_A7(3) | |
1022 | + | |
1023 | +/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */ | |
1024 | +#define SH7750_DMATCR_REGOFS(n) (0xA00008 + ((n)*16)) /* offset */ | |
1025 | +#define SH7750_DMATCR(n) SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n)) | |
1026 | +#define SH7750_DMATCR_A7(n) SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n)) | |
1027 | +#define SH7750_DMATCR0_P4 SH7750_DMATCR(0) | |
1028 | +#define SH7750_DMATCR1_P4 SH7750_DMATCR(1) | |
1029 | +#define SH7750_DMATCR2_P4 SH7750_DMATCR(2) | |
1030 | +#define SH7750_DMATCR3_P4 SH7750_DMATCR(3) | |
1031 | +#define SH7750_DMATCR0_A7 SH7750_DMATCR_A7(0) | |
1032 | +#define SH7750_DMATCR1_A7 SH7750_DMATCR_A7(1) | |
1033 | +#define SH7750_DMATCR2_A7 SH7750_DMATCR_A7(2) | |
1034 | +#define SH7750_DMATCR3_A7 SH7750_DMATCR_A7(3) | |
1035 | + | |
1036 | +/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */ | |
1037 | +#define SH7750_CHCR_REGOFS(n) (0xA0000C + ((n)*16)) /* offset */ | |
1038 | +#define SH7750_CHCR(n) SH7750_P4_REG32(SH7750_CHCR_REGOFS(n)) | |
1039 | +#define SH7750_CHCR_A7(n) SH7750_A7_REG32(SH7750_CHCR_REGOFS(n)) | |
1040 | +#define SH7750_CHCR0 SH7750_CHCR(0) | |
1041 | +#define SH7750_CHCR1 SH7750_CHCR(1) | |
1042 | +#define SH7750_CHCR2 SH7750_CHCR(2) | |
1043 | +#define SH7750_CHCR3 SH7750_CHCR(3) | |
1044 | +#define SH7750_CHCR0_A7 SH7750_CHCR_A7(0) | |
1045 | +#define SH7750_CHCR1_A7 SH7750_CHCR_A7(1) | |
1046 | +#define SH7750_CHCR2_A7 SH7750_CHCR_A7(2) | |
1047 | +#define SH7750_CHCR3_A7 SH7750_CHCR_A7(3) | |
1048 | + | |
1049 | +#define SH7750_CHCR_SSA 0xE0000000 /* Source Address Space Attribute */ | |
1050 | +#define SH7750_CHCR_SSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ | |
1051 | +#define SH7750_CHCR_SSA_DYNBSZ 0x20000000 /* Dynamic Bus Sizing I/O space */ | |
1052 | +#define SH7750_CHCR_SSA_IO8 0x40000000 /* 8-bit I/O space */ | |
1053 | +#define SH7750_CHCR_SSA_IO16 0x60000000 /* 16-bit I/O space */ | |
1054 | +#define SH7750_CHCR_SSA_CMEM8 0x80000000 /* 8-bit common memory space */ | |
1055 | +#define SH7750_CHCR_SSA_CMEM16 0xA0000000 /* 16-bit common memory space */ | |
1056 | +#define SH7750_CHCR_SSA_AMEM8 0xC0000000 /* 8-bit attribute memory space */ | |
1057 | +#define SH7750_CHCR_SSA_AMEM16 0xE0000000 /* 16-bit attribute memory space */ | |
1058 | + | |
1059 | +#define SH7750_CHCR_STC 0x10000000 /* Source Address Wait Control Select, | |
1060 | + specifies CS5 or CS6 space wait | |
1061 | + control for PCMCIA access */ | |
1062 | + | |
1063 | +#define SH7750_CHCR_DSA 0x0E000000 /* Source Address Space Attribute */ | |
1064 | +#define SH7750_CHCR_DSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ | |
1065 | +#define SH7750_CHCR_DSA_DYNBSZ 0x02000000 /* Dynamic Bus Sizing I/O space */ | |
1066 | +#define SH7750_CHCR_DSA_IO8 0x04000000 /* 8-bit I/O space */ | |
1067 | +#define SH7750_CHCR_DSA_IO16 0x06000000 /* 16-bit I/O space */ | |
1068 | +#define SH7750_CHCR_DSA_CMEM8 0x08000000 /* 8-bit common memory space */ | |
1069 | +#define SH7750_CHCR_DSA_CMEM16 0x0A000000 /* 16-bit common memory space */ | |
1070 | +#define SH7750_CHCR_DSA_AMEM8 0x0C000000 /* 8-bit attribute memory space */ | |
1071 | +#define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */ | |
1072 | + | |
1073 | +#define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control | |
1074 | + Select, specifies CS5 or CS6 | |
1075 | + space wait control for PCMCIA | |
1076 | + access */ | |
1077 | + | |
1078 | +#define SH7750_CHCR_DS 0x00080000 /* DREQ\ Select : */ | |
1079 | +#define SH7750_CHCR_DS_LOWLVL 0x00000000 /* Low Level Detection */ | |
1080 | +#define SH7750_CHCR_DS_FALL 0x00080000 /* Falling Edge Detection */ | |
1081 | + | |
1082 | +#define SH7750_CHCR_RL 0x00040000 /* Request Check Level: */ | |
1083 | +#define SH7750_CHCR_RL_ACTH 0x00000000 /* DRAK is an active high out */ | |
1084 | +#define SH7750_CHCR_RL_ACTL 0x00040000 /* DRAK is an active low out */ | |
1085 | + | |
1086 | +#define SH7750_CHCR_AM 0x00020000 /* Acknowledge Mode: */ | |
1087 | +#define SH7750_CHCR_AM_RD 0x00000000 /* DACK is output in read cycle */ | |
1088 | +#define SH7750_CHCR_AM_WR 0x00020000 /* DACK is output in write cycle */ | |
1089 | + | |
1090 | +#define SH7750_CHCR_AL 0x00010000 /* Acknowledge Level: */ | |
1091 | +#define SH7750_CHCR_AL_ACTH 0x00000000 /* DACK is an active high out */ | |
1092 | +#define SH7750_CHCR_AL_ACTL 0x00010000 /* DACK is an active low out */ | |
1093 | + | |
1094 | +#define SH7750_CHCR_DM 0x0000C000 /* Destination Address Mode: */ | |
1095 | +#define SH7750_CHCR_DM_FIX 0x00000000 /* Destination Addr Fixed */ | |
1096 | +#define SH7750_CHCR_DM_INC 0x00004000 /* Destination Addr Incremented */ | |
1097 | +#define SH7750_CHCR_DM_DEC 0x00008000 /* Destination Addr Decremented */ | |
1098 | + | |
1099 | +#define SH7750_CHCR_SM 0x00003000 /* Source Address Mode: */ | |
1100 | +#define SH7750_CHCR_SM_FIX 0x00000000 /* Source Addr Fixed */ | |
1101 | +#define SH7750_CHCR_SM_INC 0x00001000 /* Source Addr Incremented */ | |
1102 | +#define SH7750_CHCR_SM_DEC 0x00002000 /* Source Addr Decremented */ | |
1103 | + | |
1104 | +#define SH7750_CHCR_RS 0x00000F00 /* Request Source Select: */ | |
1105 | +#define SH7750_CHCR_RS_ER_DA_EA_TO_EA 0x000 /* External Request, Dual Address | |
1106 | + Mode (External Addr Space-> | |
1107 | + External Addr Space) */ | |
1108 | +#define SH7750_CHCR_RS_ER_SA_EA_TO_ED 0x200 /* External Request, Single | |
1109 | + Address Mode (External Addr | |
1110 | + Space -> External Device) */ | |
1111 | +#define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single | |
1112 | + Address Mode, (External | |
1113 | + Device -> External Addr | |
1114 | + Space) */ | |
1115 | +#define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr | |
1116 | + Space -> External Addr Space) */ | |
1117 | + | |
1118 | +#define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr | |
1119 | + Space -> On-chip Peripheral | |
1120 | + Module) */ | |
1121 | +#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip | |
1122 | + Peripheral Module -> | |
1123 | + External Addr Space */ | |
1124 | +#define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr | |
1125 | + transfer request (external | |
1126 | + address space -> SCTDR1) */ | |
1127 | +#define SH7750_CHCR_RS_SCIRX_SC_TO_EA 0x900 /* SCI Receive-Data-Full intr | |
1128 | + transfer request (SCRDR1 -> | |
1129 | + External Addr Space) */ | |
1130 | +#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC 0xA00 /* SCIF Transmit-Data-Empty intr | |
1131 | + transfer request (external | |
1132 | + address space -> SCFTDR1) */ | |
1133 | +#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA 0xB00 /* SCIF Receive-Data-Full intr | |
1134 | + transfer request (SCFRDR2 -> | |
1135 | + External Addr Space) */ | |
1136 | +#define SH7750_CHCR_RS_TMU2_EA_TO_EA 0xC00 /* TMU Channel 2 (input capture | |
1137 | + interrupt), (external address | |
1138 | + space -> external address | |
1139 | + space) */ | |
1140 | +#define SH7750_CHCR_RS_TMU2_EA_TO_OCP 0xD00 /* TMU Channel 2 (input capture | |
1141 | + interrupt), (external address | |
1142 | + space -> on-chip peripheral | |
1143 | + module) */ | |
1144 | +#define SH7750_CHCR_RS_TMU2_OCP_TO_EA 0xE00 /* TMU Channel 2 (input capture | |
1145 | + interrupt), (on-chip | |
1146 | + peripheral module -> external | |
1147 | + address space) */ | |
1148 | + | |
1149 | +#define SH7750_CHCR_TM 0x00000080 /* Transmit mode: */ | |
1150 | +#define SH7750_CHCR_TM_CSTEAL 0x00000000 /* Cycle Steal Mode */ | |
1151 | +#define SH7750_CHCR_TM_BURST 0x00000080 /* Burst Mode */ | |
1152 | + | |
1153 | +#define SH7750_CHCR_TS 0x00000070 /* Transmit Size: */ | |
1154 | +#define SH7750_CHCR_TS_QUAD 0x00000000 /* Quadword Size (64 bits) */ | |
1155 | +#define SH7750_CHCR_TS_BYTE 0x00000010 /* Byte Size (8 bit) */ | |
1156 | +#define SH7750_CHCR_TS_WORD 0x00000020 /* Word Size (16 bit) */ | |
1157 | +#define SH7750_CHCR_TS_LONG 0x00000030 /* Longword Size (32 bit) */ | |
1158 | +#define SH7750_CHCR_TS_BLOCK 0x00000040 /* 32-byte block transfer */ | |
1159 | + | |
1160 | +#define SH7750_CHCR_IE 0x00000004 /* Interrupt Enable */ | |
1161 | +#define SH7750_CHCR_TE 0x00000002 /* Transfer End */ | |
1162 | +#define SH7750_CHCR_DE 0x00000001 /* DMAC Enable */ | |
1163 | + | |
1164 | +/* DMA Operation Register - DMAOR */ | |
1165 | +#define SH7750_DMAOR_REGOFS 0xA00040 /* offset */ | |
1166 | +#define SH7750_DMAOR SH7750_P4_REG32(SH7750_DMAOR_REGOFS) | |
1167 | +#define SH7750_DMAOR_A7 SH7750_A7_REG32(SH7750_DMAOR_REGOFS) | |
1168 | + | |
1169 | +#define SH7750_DMAOR_DDT 0x00008000 /* On-Demand Data Transfer Mode */ | |
1170 | + | |
1171 | +#define SH7750_DMAOR_PR 0x00000300 /* Priority Mode: */ | |
1172 | +#define SH7750_DMAOR_PR_0123 0x00000000 /* CH0 > CH1 > CH2 > CH3 */ | |
1173 | +#define SH7750_DMAOR_PR_0231 0x00000100 /* CH0 > CH2 > CH3 > CH1 */ | |
1174 | +#define SH7750_DMAOR_PR_2013 0x00000200 /* CH2 > CH0 > CH1 > CH3 */ | |
1175 | +#define SH7750_DMAOR_PR_RR 0x00000300 /* Round-robin mode */ | |
1176 | + | |
1177 | +#define SH7750_DMAOR_COD 0x00000010 /* Check Overrun for DREQ\ */ | |
1178 | +#define SH7750_DMAOR_AE 0x00000004 /* Address Error flag */ | |
1179 | +#define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */ | |
1180 | +#define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */ | |
1181 | + | |
1182 | +/* | |
1183 | + * I/O Ports | |
1184 | + */ | |
1185 | +/* Port Control Register A - PCTRA */ | |
1186 | +#define SH7750_PCTRA_REGOFS 0x80002C /* offset */ | |
1187 | +#define SH7750_PCTRA SH7750_P4_REG32(SH7750_PCTRA_REGOFS) | |
1188 | +#define SH7750_PCTRA_A7 SH7750_A7_REG32(SH7750_PCTRA_REGOFS) | |
1189 | + | |
1190 | +#define SH7750_PCTRA_PBPUP(n) 0 /* Bit n is pulled up */ | |
1191 | +#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1)) /* Bit n is not pulled up */ | |
1192 | +#define SH7750_PCTRA_PBINP(n) 0 /* Bit n is an input */ | |
1193 | +#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2)) /* Bit n is an output */ | |
1194 | + | |
1195 | +/* Port Data Register A - PDTRA(half) */ | |
1196 | +#define SH7750_PDTRA_REGOFS 0x800030 /* offset */ | |
1197 | +#define SH7750_PDTRA SH7750_P4_REG32(SH7750_PDTRA_REGOFS) | |
1198 | +#define SH7750_PDTRA_A7 SH7750_A7_REG32(SH7750_PDTRA_REGOFS) | |
1199 | + | |
1200 | +#define SH7750_PDTRA_BIT(n) (1 << (n)) | |
1201 | + | |
1202 | +/* Port Control Register B - PCTRB */ | |
1203 | +#define SH7750_PCTRB_REGOFS 0x800040 /* offset */ | |
1204 | +#define SH7750_PCTRB SH7750_P4_REG32(SH7750_PCTRB_REGOFS) | |
1205 | +#define SH7750_PCTRB_A7 SH7750_A7_REG32(SH7750_PCTRB_REGOFS) | |
1206 | + | |
1207 | +#define SH7750_PCTRB_PBPUP(n) 0 /* Bit n is pulled up */ | |
1208 | +#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1)) /* Bit n is not pulled up */ | |
1209 | +#define SH7750_PCTRB_PBINP(n) 0 /* Bit n is an input */ | |
1210 | +#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2)) /* Bit n is an output */ | |
1211 | + | |
1212 | +/* Port Data Register B - PDTRB(half) */ | |
1213 | +#define SH7750_PDTRB_REGOFS 0x800044 /* offset */ | |
1214 | +#define SH7750_PDTRB SH7750_P4_REG32(SH7750_PDTRB_REGOFS) | |
1215 | +#define SH7750_PDTRB_A7 SH7750_A7_REG32(SH7750_PDTRB_REGOFS) | |
1216 | + | |
1217 | +#define SH7750_PDTRB_BIT(n) (1 << ((n)-16)) | |
1218 | + | |
1219 | +/* GPIO Interrupt Control Register - GPIOIC(half) */ | |
1220 | +#define SH7750_GPIOIC_REGOFS 0x800048 /* offset */ | |
1221 | +#define SH7750_GPIOIC SH7750_P4_REG32(SH7750_GPIOIC_REGOFS) | |
1222 | +#define SH7750_GPIOIC_A7 SH7750_A7_REG32(SH7750_GPIOIC_REGOFS) | |
1223 | + | |
1224 | +#define SH7750_GPIOIC_PTIREN(n) (1 << (n)) /* Port n is used as a GPIO int */ | |
1225 | + | |
1226 | +/* | |
1227 | + * Interrupt Controller - INTC | |
1228 | + */ | |
1229 | +/* Interrupt Control Register - ICR (half) */ | |
1230 | +#define SH7750_ICR_REGOFS 0xD00000 /* offset */ | |
1231 | +#define SH7750_ICR SH7750_P4_REG32(SH7750_ICR_REGOFS) | |
1232 | +#define SH7750_ICR_A7 SH7750_A7_REG32(SH7750_ICR_REGOFS) | |
1233 | + | |
1234 | +#define SH7750_ICR_NMIL 0x8000 /* NMI Input Level */ | |
1235 | +#define SH7750_ICR_MAI 0x4000 /* NMI Interrupt Mask */ | |
1236 | + | |
1237 | +#define SH7750_ICR_NMIB 0x0200 /* NMI Block Mode: */ | |
1238 | +#define SH7750_ICR_NMIB_BLK 0x0000 /* NMI requests held pending while | |
1239 | + SR.BL bit is set to 1 */ | |
1240 | +#define SH7750_ICR_NMIB_NBLK 0x0200 /* NMI requests detected when SR.BL bit | |
1241 | + set to 1 */ | |
1242 | + | |
1243 | +#define SH7750_ICR_NMIE 0x0100 /* NMI Edge Select: */ | |
1244 | +#define SH7750_ICR_NMIE_FALL 0x0000 /* Interrupt request detected on falling | |
1245 | + edge of NMI input */ | |
1246 | +#define SH7750_ICR_NMIE_RISE 0x0100 /* Interrupt request detected on rising | |
1247 | + edge of NMI input */ | |
1248 | + | |
1249 | +#define SH7750_ICR_IRLM 0x0080 /* IRL Pin Mode: */ | |
1250 | +#define SH7750_ICR_IRLM_ENC 0x0000 /* IRL\ pins used as a level-encoded | |
1251 | + interrupt requests */ | |
1252 | +#define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent | |
1253 | + interrupt requests */ | |
1254 | + | |
1255 | +/* | |
1256 | + * User Break Controller registers | |
1257 | + */ | |
1258 | +#define SH7750_BARA 0x200000 /* Break address regiser A */ | |
1259 | +#define SH7750_BAMRA 0x200004 /* Break address mask regiser A */ | |
1260 | +#define SH7750_BBRA 0x200008 /* Break bus cycle regiser A */ | |
1261 | +#define SH7750_BARB 0x20000c /* Break address regiser B */ | |
1262 | +#define SH7750_BAMRB 0x200010 /* Break address mask regiser B */ | |
1263 | +#define SH7750_BBRB 0x200014 /* Break bus cycle regiser B */ | |
1264 | +#define SH7750_BASRB 0x000018 /* Break ASID regiser B */ | |
1265 | +#define SH7750_BDRB 0x200018 /* Break data regiser B */ | |
1266 | +#define SH7750_BDMRB 0x20001c /* Break data mask regiser B */ | |
1267 | +#define SH7750_BRCR 0x200020 /* Break control register */ | |
1268 | + | |
1269 | +#define SH7750_BRCR_UDBE 0x0001 /* User break debug enable bit */ | |
1270 | + | |
1271 | +/* | |
1272 | + * Missing in RTEMS, added for QEMU | |
1273 | + */ | |
1274 | +#define SH7750_BCR3_A7 0x1f800050 | |
1275 | +#define SH7750_BCR4_A7 0x1e0a00f0 | |
1276 | + | |
1277 | +#endif |
@@ -0,0 +1,208 @@ | ||
1 | +/* | |
2 | + * SuperH on-chip PCIC emulation. | |
3 | + * | |
4 | + * Copyright (c) 2008 Takashi YOSHII | |
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 "hw/sysbus.h" | |
27 | +#include "hw/sh4/sh.h" | |
28 | +#include "hw/pci/pci.h" | |
29 | +#include "hw/pci/pci_host.h" | |
30 | +#include "qemu/bswap.h" | |
31 | +#include "qemu/module.h" | |
32 | +#include "exec/address-spaces.h" | |
33 | + | |
34 | +#define TYPE_SH_PCI_HOST_BRIDGE "sh_pci" | |
35 | + | |
36 | +#define SH_PCI_HOST_BRIDGE(obj) \ | |
37 | + OBJECT_CHECK(SHPCIState, (obj), TYPE_SH_PCI_HOST_BRIDGE) | |
38 | + | |
39 | +typedef struct SHPCIState { | |
40 | + PCIHostState parent_obj; | |
41 | + | |
42 | + PCIDevice *dev; | |
43 | + qemu_irq irq[4]; | |
44 | + MemoryRegion memconfig_p4; | |
45 | + MemoryRegion memconfig_a7; | |
46 | + MemoryRegion isa; | |
47 | + uint32_t par; | |
48 | + uint32_t mbr; | |
49 | + uint32_t iobr; | |
50 | +} SHPCIState; | |
51 | + | |
52 | +static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val, | |
53 | + unsigned size) | |
54 | +{ | |
55 | + SHPCIState *pcic = p; | |
56 | + PCIHostState *phb = PCI_HOST_BRIDGE(pcic); | |
57 | + | |
58 | + switch(addr) { | |
59 | + case 0 ... 0xfc: | |
60 | + stl_le_p(pcic->dev->config + addr, val); | |
61 | + break; | |
62 | + case 0x1c0: | |
63 | + pcic->par = val; | |
64 | + break; | |
65 | + case 0x1c4: | |
66 | + pcic->mbr = val & 0xff000001; | |
67 | + break; | |
68 | + case 0x1c8: | |
69 | + if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) { | |
70 | + memory_region_del_subregion(get_system_memory(), &pcic->isa); | |
71 | + pcic->iobr = val & 0xfffc0001; | |
72 | + memory_region_add_subregion(get_system_memory(), | |
73 | + pcic->iobr & 0xfffc0000, &pcic->isa); | |
74 | + } | |
75 | + break; | |
76 | + case 0x220: | |
77 | + pci_data_write(phb->bus, pcic->par, val, 4); | |
78 | + break; | |
79 | + } | |
80 | +} | |
81 | + | |
82 | +static uint64_t sh_pci_reg_read (void *p, hwaddr addr, | |
83 | + unsigned size) | |
84 | +{ | |
85 | + SHPCIState *pcic = p; | |
86 | + PCIHostState *phb = PCI_HOST_BRIDGE(pcic); | |
87 | + | |
88 | + switch(addr) { | |
89 | + case 0 ... 0xfc: | |
90 | + return ldl_le_p(pcic->dev->config + addr); | |
91 | + case 0x1c0: | |
92 | + return pcic->par; | |
93 | + case 0x1c4: | |
94 | + return pcic->mbr; | |
95 | + case 0x1c8: | |
96 | + return pcic->iobr; | |
97 | + case 0x220: | |
98 | + return pci_data_read(phb->bus, pcic->par, 4); | |
99 | + } | |
100 | + return 0; | |
101 | +} | |
102 | + | |
103 | +static const MemoryRegionOps sh_pci_reg_ops = { | |
104 | + .read = sh_pci_reg_read, | |
105 | + .write = sh_pci_reg_write, | |
106 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
107 | + .valid = { | |
108 | + .min_access_size = 4, | |
109 | + .max_access_size = 4, | |
110 | + }, | |
111 | +}; | |
112 | + | |
113 | +static int sh_pci_map_irq(PCIDevice *d, int irq_num) | |
114 | +{ | |
115 | + return (d->devfn >> 3); | |
116 | +} | |
117 | + | |
118 | +static void sh_pci_set_irq(void *opaque, int irq_num, int level) | |
119 | +{ | |
120 | + qemu_irq *pic = opaque; | |
121 | + | |
122 | + qemu_set_irq(pic[irq_num], level); | |
123 | +} | |
124 | + | |
125 | +static void sh_pci_device_realize(DeviceState *dev, Error **errp) | |
126 | +{ | |
127 | + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | |
128 | + SHPCIState *s = SH_PCI_HOST_BRIDGE(dev); | |
129 | + PCIHostState *phb = PCI_HOST_BRIDGE(s); | |
130 | + int i; | |
131 | + | |
132 | + for (i = 0; i < 4; i++) { | |
133 | + sysbus_init_irq(sbd, &s->irq[i]); | |
134 | + } | |
135 | + phb->bus = pci_register_root_bus(DEVICE(dev), "pci", | |
136 | + sh_pci_set_irq, sh_pci_map_irq, | |
137 | + s->irq, | |
138 | + get_system_memory(), | |
139 | + get_system_io(), | |
140 | + PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); | |
141 | + memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s, | |
142 | + "sh_pci", 0x224); | |
143 | + memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2", | |
144 | + &s->memconfig_p4, 0, 0x224); | |
145 | + memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa", | |
146 | + get_system_io(), 0, 0x40000); | |
147 | + sysbus_init_mmio(sbd, &s->memconfig_p4); | |
148 | + sysbus_init_mmio(sbd, &s->memconfig_a7); | |
149 | + s->iobr = 0xfe240000; | |
150 | + memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa); | |
151 | + | |
152 | + s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host"); | |
153 | +} | |
154 | + | |
155 | +static void sh_pci_host_realize(PCIDevice *d, Error **errp) | |
156 | +{ | |
157 | + pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT); | |
158 | + pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST | | |
159 | + PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); | |
160 | +} | |
161 | + | |
162 | +static void sh_pci_host_class_init(ObjectClass *klass, void *data) | |
163 | +{ | |
164 | + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
165 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
166 | + | |
167 | + k->realize = sh_pci_host_realize; | |
168 | + k->vendor_id = PCI_VENDOR_ID_HITACHI; | |
169 | + k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R; | |
170 | + /* | |
171 | + * PCI-facing part of the host bridge, not usable without the | |
172 | + * host-facing part, which can't be device_add'ed, yet. | |
173 | + */ | |
174 | + dc->user_creatable = false; | |
175 | +} | |
176 | + | |
177 | +static const TypeInfo sh_pci_host_info = { | |
178 | + .name = "sh_pci_host", | |
179 | + .parent = TYPE_PCI_DEVICE, | |
180 | + .instance_size = sizeof(PCIDevice), | |
181 | + .class_init = sh_pci_host_class_init, | |
182 | + .interfaces = (InterfaceInfo[]) { | |
183 | + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, | |
184 | + { }, | |
185 | + }, | |
186 | +}; | |
187 | + | |
188 | +static void sh_pci_device_class_init(ObjectClass *klass, void *data) | |
189 | +{ | |
190 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
191 | + | |
192 | + dc->realize = sh_pci_device_realize; | |
193 | +} | |
194 | + | |
195 | +static const TypeInfo sh_pci_device_info = { | |
196 | + .name = TYPE_SH_PCI_HOST_BRIDGE, | |
197 | + .parent = TYPE_PCI_HOST_BRIDGE, | |
198 | + .instance_size = sizeof(SHPCIState), | |
199 | + .class_init = sh_pci_device_class_init, | |
200 | +}; | |
201 | + | |
202 | +static void sh_pci_register_types(void) | |
203 | +{ | |
204 | + type_register_static(&sh_pci_device_info); | |
205 | + type_register_static(&sh_pci_host_info); | |
206 | +} | |
207 | + | |
208 | +type_init(sh_pci_register_types) |
@@ -0,0 +1,90 @@ | ||
1 | +/* | |
2 | + * SHIX 2.0 board description | |
3 | + * | |
4 | + * Copyright (c) 2005 Samuel Tardieu | |
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 | + Shix 2.0 board by Alexis Polti, described at | |
26 | + https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20 | |
27 | + | |
28 | + More information in target/sh4/README.sh4 | |
29 | +*/ | |
30 | +#include "qemu/osdep.h" | |
31 | +#include "qapi/error.h" | |
32 | +#include "cpu.h" | |
33 | +#include "hw/hw.h" | |
34 | +#include "hw/sh4/sh.h" | |
35 | +#include "sysemu/sysemu.h" | |
36 | +#include "sysemu/qtest.h" | |
37 | +#include "hw/boards.h" | |
38 | +#include "hw/loader.h" | |
39 | +#include "exec/address-spaces.h" | |
40 | +#include "qemu/error-report.h" | |
41 | + | |
42 | +#define BIOS_FILENAME "shix_bios.bin" | |
43 | +#define BIOS_ADDRESS 0xA0000000 | |
44 | + | |
45 | +static void shix_init(MachineState *machine) | |
46 | +{ | |
47 | + int ret; | |
48 | + SuperHCPU *cpu; | |
49 | + struct SH7750State *s; | |
50 | + MemoryRegion *sysmem = get_system_memory(); | |
51 | + MemoryRegion *rom = g_new(MemoryRegion, 1); | |
52 | + MemoryRegion *sdram = g_new(MemoryRegion, 2); | |
53 | + | |
54 | + cpu = SUPERH_CPU(cpu_create(machine->cpu_type)); | |
55 | + | |
56 | + /* Allocate memory space */ | |
57 | + memory_region_init_ram(rom, NULL, "shix.rom", 0x4000, &error_fatal); | |
58 | + memory_region_set_readonly(rom, true); | |
59 | + memory_region_add_subregion(sysmem, 0x00000000, rom); | |
60 | + memory_region_init_ram(&sdram[0], NULL, "shix.sdram1", 0x01000000, | |
61 | + &error_fatal); | |
62 | + memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]); | |
63 | + memory_region_init_ram(&sdram[1], NULL, "shix.sdram2", 0x01000000, | |
64 | + &error_fatal); | |
65 | + memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]); | |
66 | + | |
67 | + /* Load BIOS in 0 (and access it through P2, 0xA0000000) */ | |
68 | + if (bios_name == NULL) | |
69 | + bios_name = BIOS_FILENAME; | |
70 | + ret = load_image_targphys(bios_name, 0, 0x4000); | |
71 | + if (ret < 0 && !qtest_enabled()) { | |
72 | + error_report("Could not load SHIX bios '%s'", bios_name); | |
73 | + exit(1); | |
74 | + } | |
75 | + | |
76 | + /* Register peripherals */ | |
77 | + s = sh7750_init(cpu, sysmem); | |
78 | + /* XXXXX Check success */ | |
79 | + tc58128_init(s, "shix_linux_nand.bin", NULL); | |
80 | +} | |
81 | + | |
82 | +static void shix_machine_init(MachineClass *mc) | |
83 | +{ | |
84 | + mc->desc = "shix card"; | |
85 | + mc->init = shix_init; | |
86 | + mc->is_default = 1; | |
87 | + mc->default_cpu_type = TYPE_SH7750R_CPU; | |
88 | +} | |
89 | + | |
90 | +DEFINE_MACHINE("shix", shix_machine_init) |
@@ -15,7 +15,7 @@ enum { | ||
15 | 15 | QEMU_ARCH_MIPS = (1 << 7), |
16 | 16 | QEMU_ARCH_PPC = (1 << 8), |
17 | 17 | QEMU_ARCH_S390X = (1 << 9), |
18 | - QEMU_ARCH_SH4 = (1 << 10), | |
18 | + QEMU_ARCH_SH = (1 << 10), | |
19 | 19 | QEMU_ARCH_SPARC = (1 << 11), |
20 | 20 | QEMU_ARCH_XTENSA = (1 << 12), |
21 | 21 | QEMU_ARCH_OPENRISC = (1 << 13), |
@@ -0,0 +1,10 @@ | ||
1 | +obj-y += translate.o op_helper.o helper.o cpu.o gdbstub.o | |
2 | + | |
3 | +DECODETREE = $(SRC_PATH)/scripts/decodetree.py | |
4 | + | |
5 | +target/sh/decode.inc.c: \ | |
6 | + $(SRC_PATH)/target/sh/insns.decode $(DECODETREE) | |
7 | + $(call quiet-command, \ | |
8 | + $(PYTHON) $(DECODETREE) -w 16 -o $@ $<, "GEN", $(TARGET_DIR)$@) | |
9 | + | |
10 | +target/sh/translate.o: target/sh/decode.inc.c |
@@ -0,0 +1,21 @@ | ||
1 | +/* | |
2 | + * SH4 cpu parameters for qemu. | |
3 | + * | |
4 | + * Copyright (c) 2005 Samuel Tardieu | |
5 | + * SPDX-License-Identifier: LGPL-2.0+ | |
6 | + */ | |
7 | + | |
8 | +#ifndef SH4_CPU_PARAM_H | |
9 | +#define SH4_CPU_PARAM_H 1 | |
10 | + | |
11 | +#define TARGET_LONG_BITS 32 | |
12 | +#define TARGET_PAGE_BITS 12 /* 4k */ | |
13 | +#define TARGET_PHYS_ADDR_SPACE_BITS 32 | |
14 | +#ifdef CONFIG_USER_ONLY | |
15 | +# define TARGET_VIRT_ADDR_SPACE_BITS 31 | |
16 | +#else | |
17 | +# define TARGET_VIRT_ADDR_SPACE_BITS 32 | |
18 | +#endif | |
19 | +#define NB_MMU_MODES 2 | |
20 | + | |
21 | +#endif |
@@ -0,0 +1,62 @@ | ||
1 | +/* | |
2 | + * QEMU SuperH CPU | |
3 | + * | |
4 | + * Copyright (c) 2012 SUSE LINUX Products GmbH | |
5 | + * | |
6 | + * This library is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU Lesser General Public | |
8 | + * License as published by the Free Software Foundation; either | |
9 | + * version 2.1 of the License, or (at your option) any later version. | |
10 | + * | |
11 | + * This library is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | + * Lesser General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU Lesser General Public | |
17 | + * License along with this library; if not, see | |
18 | + * <http://www.gnu.org/licenses/lgpl-2.1.html> | |
19 | + */ | |
20 | +#ifndef QEMU_SUPERH_CPU_QOM_H | |
21 | +#define QEMU_SUPERH_CPU_QOM_H | |
22 | + | |
23 | +#include "qom/cpu.h" | |
24 | + | |
25 | +#define TYPE_SUPERH_CPU "superh-cpu" | |
26 | + | |
27 | +#define TYPE_SH2_CPU SUPERH_CPU_TYPE_NAME("sh2") | |
28 | +#define TYPE_SH4_CPU SUPERH_CPU_TYPE_NAME("sh4") | |
29 | + | |
30 | +#define SUPERH_CPU_CLASS(klass) \ | |
31 | + OBJECT_CLASS_CHECK(SuperHCPUClass, (klass), TYPE_SUPERH_CPU) | |
32 | +#define SUPERH_CPU(obj) \ | |
33 | + OBJECT_CHECK(SuperHCPU, (obj), TYPE_SUPERH_CPU) | |
34 | +#define SUPERH_CPU_GET_CLASS(obj) \ | |
35 | + OBJECT_GET_CLASS(SuperHCPUClass, (obj), TYPE_SUPERH_CPU) | |
36 | + | |
37 | +/** | |
38 | + * SuperHCPUClass: | |
39 | + * @parent_realize: The parent class' realize handler. | |
40 | + * @parent_reset: The parent class' reset handler. | |
41 | + * @pvr: Processor Version Register | |
42 | + * @prr: Processor Revision Register | |
43 | + * @cvr: Cache Version Register | |
44 | + * | |
45 | + * A SuperH CPU model. | |
46 | + */ | |
47 | +typedef struct SuperHCPUClass { | |
48 | + /*< private >*/ | |
49 | + CPUClass parent_class; | |
50 | + /*< public >*/ | |
51 | + | |
52 | + DeviceRealize parent_realize; | |
53 | + void (*parent_reset)(CPUState *cpu); | |
54 | + | |
55 | + uint32_t pvr; | |
56 | + uint32_t prr; | |
57 | + uint32_t cvr; | |
58 | +} SuperHCPUClass; | |
59 | + | |
60 | +#define CPUArchState struct CPUSHState | |
61 | + | |
62 | +#endif |
@@ -0,0 +1,211 @@ | ||
1 | +/* | |
2 | + * QEMU SuperH CPU | |
3 | + * | |
4 | + * Copyright (c) 2005 Samuel Tardieu | |
5 | + * Copyright (c) 2012 SUSE LINUX Products GmbH | |
6 | + * Copyright (c) 2019 Yoshinori Sato | |
7 | + * | |
8 | + * This library is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU Lesser General Public | |
10 | + * License as published by the Free Software Foundation; either | |
11 | + * version 2.1 of the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This library is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | + * Lesser General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU Lesser General Public | |
19 | + * License along with this library; if not, see | |
20 | + * <http://www.gnu.org/licenses/lgpl-2.1.html> | |
21 | + */ | |
22 | + | |
23 | +#include "qemu/osdep.h" | |
24 | +#include "qapi/error.h" | |
25 | +#include "qemu/qemu-print.h" | |
26 | +#include "cpu.h" | |
27 | +#include "migration/vmstate.h" | |
28 | +#include "exec/exec-all.h" | |
29 | +#include "hw/loader.h" | |
30 | + | |
31 | +static void superh_cpu_set_pc(CPUState *cs, vaddr value) | |
32 | +{ | |
33 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
34 | + | |
35 | + cpu->env.pc = value; | |
36 | +} | |
37 | + | |
38 | +static void superh_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) | |
39 | +{ | |
40 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
41 | + | |
42 | + cpu->env.pc = tb->pc; | |
43 | + cpu->env.flags = tb->flags & TB_FLAG_ENVFLAGS_MASK; | |
44 | +} | |
45 | + | |
46 | +static bool superh_cpu_has_work(CPUState *cs) | |
47 | +{ | |
48 | + return cs->interrupt_request & CPU_INTERRUPT_HARD; | |
49 | +} | |
50 | + | |
51 | +/* CPUClass::reset() */ | |
52 | +static void superh_cpu_reset(CPUState *s) | |
53 | +{ | |
54 | + SuperHCPU *cpu = SUPERH_CPU(s); | |
55 | + SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(cpu); | |
56 | + CPUSHState *env = &cpu->env; | |
57 | + | |
58 | + scc->parent_reset(s); | |
59 | + | |
60 | + memset(env, 0, offsetof(CPUSHState, end_reset_fields)); | |
61 | + | |
62 | + if ((env->features & FEATURE_ISA) > 2) { | |
63 | + env->pc = 0xA0000000; | |
64 | + env->sr = FIELD_DP32(0, SR, MD, 1); | |
65 | + env->sr = FIELD_DP32(env->sr, SR, BL, 1); | |
66 | + env->sr = FIELD_DP32(env->sr, SR, RB, 1); | |
67 | + env->sr = FIELD_DP32(env->sr, SR, FD, 0); | |
68 | + env->sr = FIELD_DP32(env->sr, SR, I, 0x0f); | |
69 | + if ((env->features & FEATURE_ISA) == 4) { | |
70 | +#if 0 | |
71 | + env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */ | |
72 | + set_float_rounding_mode(float_round_to_zero, &env->fp_status); | |
73 | + set_flush_to_zero(1, &env->fp_status); | |
74 | + set_default_nan_mode(1, &env->fp_status); | |
75 | +#endif | |
76 | + } | |
77 | + } else { | |
78 | + uint32_t *resetvec; | |
79 | + env->sr = FIELD_DP32(env->sr, SR, I, 0x0f); | |
80 | + resetvec = rom_ptr(0x00000000, 4); | |
81 | + if (resetvec) { | |
82 | + env->pc = ldl_p(resetvec); | |
83 | + resetvec = rom_ptr(0x00000004, 4); | |
84 | + env->regs[15] = ldl_p(resetvec); | |
85 | + } | |
86 | + } | |
87 | + | |
88 | +} | |
89 | + | |
90 | +static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) | |
91 | +{ | |
92 | + info->mach = bfd_mach_sh; | |
93 | + info->print_insn = print_insn_sh; | |
94 | +} | |
95 | + | |
96 | +static void superh_cpu_list_entry(gpointer data, gpointer user_data) | |
97 | +{ | |
98 | + const char *typename = object_class_get_name(OBJECT_CLASS(data)); | |
99 | + | |
100 | + qemu_printf("%s\n", typename); | |
101 | +} | |
102 | + | |
103 | +void sh_cpu_list(void) | |
104 | +{ | |
105 | + GSList *list; | |
106 | + | |
107 | + list = object_class_get_list_sorted(TYPE_SUPERH_CPU, false); | |
108 | + g_slist_foreach(list, superh_cpu_list_entry, NULL); | |
109 | + g_slist_free(list); | |
110 | +} | |
111 | + | |
112 | +static ObjectClass *superh_cpu_class_by_name(const char *cpu_model) | |
113 | +{ | |
114 | + ObjectClass *oc; | |
115 | + | |
116 | + oc = object_class_by_name(cpu_model); | |
117 | + | |
118 | + if (object_class_dynamic_cast(oc, TYPE_SUPERH_CPU) == NULL || | |
119 | + object_class_is_abstract(oc)) { | |
120 | + oc = NULL; | |
121 | + } | |
122 | + | |
123 | + return oc; | |
124 | +} | |
125 | + | |
126 | +static void superh_cpu_realizefn(DeviceState *dev, Error **errp) | |
127 | +{ | |
128 | + CPUState *cs = CPU(dev); | |
129 | + SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev); | |
130 | + Error *local_err = NULL; | |
131 | + | |
132 | + cpu_exec_realizefn(cs, &local_err); | |
133 | + if (local_err != NULL) { | |
134 | + error_propagate(errp, local_err); | |
135 | + return; | |
136 | + } | |
137 | + | |
138 | + cpu_reset(cs); | |
139 | + qemu_init_vcpu(cs); | |
140 | + | |
141 | + scc->parent_realize(dev, errp); | |
142 | +} | |
143 | + | |
144 | +static void superh_cpu_initfn(Object *obj) | |
145 | +{ | |
146 | + SuperHCPU *cpu = SUPERH_CPU(obj); | |
147 | + | |
148 | + cpu_set_cpustate_pointers(cpu); | |
149 | +} | |
150 | + | |
151 | +static const VMStateDescription vmstate_sh_cpu = { | |
152 | + .name = "cpu", | |
153 | + .unmigratable = 1, | |
154 | +}; | |
155 | + | |
156 | +static void superh_cpu_class_init(ObjectClass *oc, void *data) | |
157 | +{ | |
158 | + DeviceClass *dc = DEVICE_CLASS(oc); | |
159 | + CPUClass *cc = CPU_CLASS(oc); | |
160 | + SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); | |
161 | + | |
162 | + device_class_set_parent_realize(dc, superh_cpu_realizefn, | |
163 | + &scc->parent_realize); | |
164 | + | |
165 | + scc->parent_reset = cc->reset; | |
166 | + cc->reset = superh_cpu_reset; | |
167 | + | |
168 | + cc->class_by_name = superh_cpu_class_by_name; | |
169 | + cc->has_work = superh_cpu_has_work; | |
170 | + cc->do_interrupt = superh_cpu_do_interrupt; | |
171 | + cc->cpu_exec_interrupt = superh_cpu_exec_interrupt; | |
172 | + cc->dump_state = superh_cpu_dump_state; | |
173 | + cc->set_pc = superh_cpu_set_pc; | |
174 | + cc->synchronize_from_tb = superh_cpu_synchronize_from_tb; | |
175 | + cc->gdb_read_register = superh_cpu_gdb_read_register; | |
176 | + cc->gdb_write_register = superh_cpu_gdb_write_register; | |
177 | + cc->tlb_fill = superh_cpu_tlb_fill; | |
178 | +#ifndef CONFIG_USER_ONLY | |
179 | + cc->do_unaligned_access = superh_cpu_do_unaligned_access; | |
180 | + cc->get_phys_page_debug = superh_cpu_get_phys_page_debug; | |
181 | +#endif | |
182 | + cc->disas_set_info = superh_cpu_disas_set_info; | |
183 | + cc->tcg_initialize = sh_translate_init; | |
184 | + | |
185 | + cc->gdb_num_core_regs = 23; | |
186 | + cc->gdb_core_xml_file = "sh-core.xml"; | |
187 | + dc->vmsd = &vmstate_sh_cpu; | |
188 | +} | |
189 | + | |
190 | +static const TypeInfo superh_cpu_type_info = { | |
191 | + .name = TYPE_SUPERH_CPU, | |
192 | + .parent = TYPE_CPU, | |
193 | + .instance_size = sizeof(SuperHCPU), | |
194 | + .instance_init = superh_cpu_initfn, | |
195 | + .abstract = true, | |
196 | + .class_size = sizeof(SuperHCPUClass), | |
197 | + .class_init = superh_cpu_class_init, | |
198 | +}; | |
199 | + | |
200 | +static const TypeInfo sh2_cpu_type_info = { | |
201 | + .name = TYPE_SH2_CPU, | |
202 | + .parent = TYPE_SUPERH_CPU, | |
203 | +}; | |
204 | + | |
205 | +static void sh_cpu_register_types(void) | |
206 | +{ | |
207 | + type_register_static(&superh_cpu_type_info); | |
208 | + type_register_static(&sh2_cpu_type_info); | |
209 | +} | |
210 | + | |
211 | +type_init(sh_cpu_register_types) |
@@ -0,0 +1,338 @@ | ||
1 | +/* | |
2 | + * Renesas SH emulation | |
3 | + * | |
4 | + * Copyright (c) 2005 Samuel Tardieu | |
5 | + * Copyright (c) 2019 Yoshinori Sato | |
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 | |
10 | + * version 2.1 of the License, or (at your option) any later version. | |
11 | + * | |
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 | |
15 | + * Lesser General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU Lesser General Public | |
18 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | + */ | |
20 | + | |
21 | +#ifndef SH_CPU_H | |
22 | +#define SH_CPU_H | |
23 | + | |
24 | +#include "cpu-qom.h" | |
25 | +#include "exec/cpu-defs.h" | |
26 | +#include "hw/registerfields.h" | |
27 | + | |
28 | +#define ALIGNED_ONLY | |
29 | + | |
30 | +/* SR */ | |
31 | +REG32(SR, 0) | |
32 | +FIELD(SR, MD, 30, 1) | |
33 | +FIELD(SR, RB, 29, 1) | |
34 | +FIELD(SR, BL, 28, 1) | |
35 | +FIELD(SR, FD, 15, 1) | |
36 | +FIELD(SR, M, 9, 1) | |
37 | +FIELD(SR, Q, 8, 1) | |
38 | +FIELD(SR, I, 4, 4) | |
39 | +FIELD(SR, S, 1, 1) | |
40 | +FIELD(SR, T, 0, 1) | |
41 | + | |
42 | +#define DELAY_SLOT_MASK 0x7 | |
43 | +#define DELAY_SLOT (1 << 0) | |
44 | +#define DELAY_SLOT_CONDITIONAL (1 << 1) | |
45 | +#define DELAY_SLOT_RTE (1 << 2) | |
46 | + | |
47 | +#define TB_FLAG_ENVFLAGS_MASK DELAY_SLOT_MASK | |
48 | +#define FEATURE_ISA (15) | |
49 | +#define FEATURE_A (1 << 4) | |
50 | +#define FEATURE_R (1 << 5) | |
51 | + | |
52 | +#define SH_FEATURE_SH2 (2) | |
53 | +#define SH_FEATURE_SH2A (2 | FEATURE_A) | |
54 | +#define SH_FEATURE_SH3 (3) | |
55 | +#define SH_FEATURE_SH4 (4) | |
56 | +#define SH_FEATURE_SH4A (4 | FEATURE_A) | |
57 | + | |
58 | +typedef struct tlb_t { | |
59 | + uint32_t vpn; /* virtual page number */ | |
60 | + uint32_t ppn; /* physical page number */ | |
61 | + uint32_t size; /* mapped page size in bytes */ | |
62 | + uint8_t asid; /* address space identifier */ | |
63 | + uint8_t v:1; /* validity */ | |
64 | + uint8_t sz:2; /* page size */ | |
65 | + uint8_t sh:1; /* share status */ | |
66 | + uint8_t c:1; /* cacheability */ | |
67 | + uint8_t pr:2; /* protection key */ | |
68 | + uint8_t d:1; /* dirty */ | |
69 | + uint8_t wt:1; /* write through */ | |
70 | + uint8_t sa:3; /* space attribute (PCMCIA) */ | |
71 | + uint8_t tc:1; /* timing control */ | |
72 | +} tlb_t; | |
73 | + | |
74 | +#define UTLB_SIZE 64 | |
75 | +#define ITLB_SIZE 4 | |
76 | + | |
77 | +#define TARGET_INSN_START_EXTRA_WORDS 1 | |
78 | + | |
79 | +typedef struct CPUSHState { | |
80 | + uint32_t regs[32]; | |
81 | + uint32_t sr; | |
82 | + uint32_t sr_m; /* M bit of status register */ | |
83 | + uint32_t sr_q; /* Q bit of status register */ | |
84 | + uint32_t sr_t; /* T bit of status register */ | |
85 | + | |
86 | + uint32_t ssr; /* saved status register */ | |
87 | + uint32_t spc; /* saved program counter */ | |
88 | + uint32_t gbr; /* global base register */ | |
89 | + uint32_t vbr; /* vector base register */ | |
90 | + uint32_t sgr; /* saved global register 15 */ | |
91 | + uint32_t dbr; /* debug base register */ | |
92 | + uint32_t pc; /* program counter */ | |
93 | + uint32_t delayed_pc; /* target of delayed branch */ | |
94 | + uint32_t delayed_cond; /* condition of delayed branch */ | |
95 | + uint64_t mac; /* multiply and accumulate high */ | |
96 | + uint32_t pr; /* procedure register */ | |
97 | + | |
98 | + /* Those belong to the specific unit (SH7750) but are handled here */ | |
99 | + uint32_t mmucr; /* MMU control register */ | |
100 | + uint32_t pteh; /* page table entry high register */ | |
101 | + uint32_t ptel; /* page table entry low register */ | |
102 | + uint32_t ptea; /* page table entry assistance register */ | |
103 | + uint32_t ttb; /* tranlation table base register */ | |
104 | + uint32_t tea; /* TLB exception address register */ | |
105 | + uint32_t tra; /* TRAPA exception register */ | |
106 | + uint32_t expevt; /* exception event register */ | |
107 | + uint32_t intevt; /* interrupt event register */ | |
108 | + | |
109 | + tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ | |
110 | + tlb_t utlb[UTLB_SIZE]; /* unified translation table */ | |
111 | + /* Fields up to this point are cleared by a CPU reset */ | |
112 | + struct {} end_reset_fields; | |
113 | + | |
114 | + /* The features that we should emulate. See sh_features above. */ | |
115 | + uint32_t features; | |
116 | + uint32_t flags; /* general execution flags */ | |
117 | + int req_irq; | |
118 | + int req_ipl; | |
119 | + qemu_irq ack; | |
120 | + | |
121 | + int in_sleep; /* SR_BL ignored during sleep */ | |
122 | +} CPUSHState; | |
123 | + | |
124 | + | |
125 | + | |
126 | +/** | |
127 | + * SuperHCPU: | |
128 | + * @env: #CPUSHState | |
129 | + * | |
130 | + * A SuperH CPU. | |
131 | + */ | |
132 | +struct SuperHCPU { | |
133 | + /*< private >*/ | |
134 | + CPUState parent_obj; | |
135 | + /*< public >*/ | |
136 | + | |
137 | + CPUNegativeOffsetState neg; | |
138 | + CPUSHState env; | |
139 | +}; | |
140 | + | |
141 | + | |
142 | +void superh_cpu_do_interrupt(CPUState *cpu); | |
143 | +bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req); | |
144 | +void superh_cpu_dump_state(CPUState *cpu, FILE *f, int flags); | |
145 | +hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); | |
146 | +int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); | |
147 | +int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); | |
148 | +void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, | |
149 | + MMUAccessType access_type, | |
150 | + int mmu_idx, uintptr_t retaddr); | |
151 | + | |
152 | +void sh_translate_init(void); | |
153 | +int cpu_sh4_signal_handler(int host_signum, void *pinfo, | |
154 | + void *puc); | |
155 | +bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size, | |
156 | + MMUAccessType access_type, int mmu_idx, | |
157 | + bool probe, uintptr_t retaddr); | |
158 | + | |
159 | +void sh_cpu_list(void); | |
160 | +#if !defined(CONFIG_USER_ONLY) | |
161 | +void cpu_sh4_invalidate_tlb(CPUSHState *s); | |
162 | +uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSHState *s, | |
163 | + hwaddr addr); | |
164 | +void cpu_sh4_write_mmaped_itlb_addr(CPUSHState *s, hwaddr addr, | |
165 | + uint32_t mem_value); | |
166 | +uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSHState *s, | |
167 | + hwaddr addr); | |
168 | +void cpu_sh4_write_mmaped_itlb_data(CPUSHState *s, hwaddr addr, | |
169 | + uint32_t mem_value); | |
170 | +uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSHState *s, | |
171 | + hwaddr addr); | |
172 | +void cpu_sh4_write_mmaped_utlb_addr(CPUSHState *s, hwaddr addr, | |
173 | + uint32_t mem_value); | |
174 | +uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSHState *s, | |
175 | + hwaddr addr); | |
176 | +void cpu_sh4_write_mmaped_utlb_data(CPUSHState *s, hwaddr addr, | |
177 | + uint32_t mem_value); | |
178 | +#endif | |
179 | + | |
180 | +int cpu_sh4_is_cached(CPUSHState * env, target_ulong addr); | |
181 | + | |
182 | +void cpu_load_tlb(CPUSHState * env); | |
183 | + | |
184 | +#define SUPERH_CPU_TYPE_SUFFIX "-" TYPE_SUPERH_CPU | |
185 | +#define SUPERH_CPU_TYPE_NAME(model) model SUPERH_CPU_TYPE_SUFFIX | |
186 | +#define CPU_RESOLVING_TYPE TYPE_SUPERH_CPU | |
187 | + | |
188 | +#define cpu_signal_handler cpu_sh_signal_handler | |
189 | +#define cpu_list sh_cpu_list | |
190 | + | |
191 | +/* MMU modes definitions */ | |
192 | +#define MMU_MODE0_SUFFIX _kernel | |
193 | +#define MMU_MODE1_SUFFIX _user | |
194 | +#define MMU_USER_IDX 1 | |
195 | +static inline int cpu_mmu_index (CPUSHState *env, bool ifetch) | |
196 | +{ | |
197 | + /* The instruction in a RTE delay slot is fetched in privileged | |
198 | + mode, but executed in user mode. */ | |
199 | + if (ifetch && (env->flags & DELAY_SLOT_RTE)) { | |
200 | + return 0; | |
201 | + } else { | |
202 | + if ((env->features & FEATURE_ISA) > 2) { | |
203 | + return (FIELD_EX32(env->sr, SR, MD )) == 0 ? 1 : 0; | |
204 | + } else { | |
205 | + return 0; | |
206 | + } | |
207 | + } | |
208 | +} | |
209 | + | |
210 | +typedef struct SuperHCPU SuperHCPU; | |
211 | +typedef SuperHCPU ArchCPU; | |
212 | + | |
213 | +#include "exec/cpu-all.h" | |
214 | + | |
215 | +/* Memory access type */ | |
216 | +enum { | |
217 | + /* Privilege */ | |
218 | + ACCESS_PRIV = 0x01, | |
219 | + /* Direction */ | |
220 | + ACCESS_WRITE = 0x02, | |
221 | + /* Type of instruction */ | |
222 | + ACCESS_CODE = 0x10, | |
223 | + ACCESS_INT = 0x20 | |
224 | +}; | |
225 | + | |
226 | +/* MMU control register */ | |
227 | +#define MMUCR 0x1F000010 | |
228 | +#define MMUCR_AT (1<<0) | |
229 | +#define MMUCR_TI (1<<2) | |
230 | +#define MMUCR_SV (1<<8) | |
231 | +#define MMUCR_URC_BITS (6) | |
232 | +#define MMUCR_URC_OFFSET (10) | |
233 | +#define MMUCR_URC_SIZE (1 << MMUCR_URC_BITS) | |
234 | +#define MMUCR_URC_MASK (((MMUCR_URC_SIZE) - 1) << MMUCR_URC_OFFSET) | |
235 | +static inline int cpu_mmucr_urc (uint32_t mmucr) | |
236 | +{ | |
237 | + return ((mmucr & MMUCR_URC_MASK) >> MMUCR_URC_OFFSET); | |
238 | +} | |
239 | + | |
240 | +/* PTEH : Page Translation Entry High register */ | |
241 | +#define PTEH_ASID_BITS (8) | |
242 | +#define PTEH_ASID_SIZE (1 << PTEH_ASID_BITS) | |
243 | +#define PTEH_ASID_MASK (PTEH_ASID_SIZE - 1) | |
244 | +#define cpu_pteh_asid(pteh) ((pteh) & PTEH_ASID_MASK) | |
245 | +#define PTEH_VPN_BITS (22) | |
246 | +#define PTEH_VPN_OFFSET (10) | |
247 | +#define PTEH_VPN_SIZE (1 << PTEH_VPN_BITS) | |
248 | +#define PTEH_VPN_MASK (((PTEH_VPN_SIZE) - 1) << PTEH_VPN_OFFSET) | |
249 | +static inline int cpu_pteh_vpn (uint32_t pteh) | |
250 | +{ | |
251 | + return ((pteh & PTEH_VPN_MASK) >> PTEH_VPN_OFFSET); | |
252 | +} | |
253 | + | |
254 | +/* PTEL : Page Translation Entry Low register */ | |
255 | +#define PTEL_V (1 << 8) | |
256 | +#define cpu_ptel_v(ptel) (((ptel) & PTEL_V) >> 8) | |
257 | +#define PTEL_C (1 << 3) | |
258 | +#define cpu_ptel_c(ptel) (((ptel) & PTEL_C) >> 3) | |
259 | +#define PTEL_D (1 << 2) | |
260 | +#define cpu_ptel_d(ptel) (((ptel) & PTEL_D) >> 2) | |
261 | +#define PTEL_SH (1 << 1) | |
262 | +#define cpu_ptel_sh(ptel)(((ptel) & PTEL_SH) >> 1) | |
263 | +#define PTEL_WT (1 << 0) | |
264 | +#define cpu_ptel_wt(ptel) ((ptel) & PTEL_WT) | |
265 | + | |
266 | +#define PTEL_SZ_HIGH_OFFSET (7) | |
267 | +#define PTEL_SZ_HIGH (1 << PTEL_SZ_HIGH_OFFSET) | |
268 | +#define PTEL_SZ_LOW_OFFSET (4) | |
269 | +#define PTEL_SZ_LOW (1 << PTEL_SZ_LOW_OFFSET) | |
270 | +static inline int cpu_ptel_sz (uint32_t ptel) | |
271 | +{ | |
272 | + int sz; | |
273 | + sz = (ptel & PTEL_SZ_HIGH) >> PTEL_SZ_HIGH_OFFSET; | |
274 | + sz <<= 1; | |
275 | + sz |= (ptel & PTEL_SZ_LOW) >> PTEL_SZ_LOW_OFFSET; | |
276 | + return sz; | |
277 | +} | |
278 | + | |
279 | +#define PTEL_PPN_BITS (19) | |
280 | +#define PTEL_PPN_OFFSET (10) | |
281 | +#define PTEL_PPN_SIZE (1 << PTEL_PPN_BITS) | |
282 | +#define PTEL_PPN_MASK (((PTEL_PPN_SIZE) - 1) << PTEL_PPN_OFFSET) | |
283 | +static inline int cpu_ptel_ppn (uint32_t ptel) | |
284 | +{ | |
285 | + return ((ptel & PTEL_PPN_MASK) >> PTEL_PPN_OFFSET); | |
286 | +} | |
287 | + | |
288 | +#define PTEL_PR_BITS (2) | |
289 | +#define PTEL_PR_OFFSET (5) | |
290 | +#define PTEL_PR_SIZE (1 << PTEL_PR_BITS) | |
291 | +#define PTEL_PR_MASK (((PTEL_PR_SIZE) - 1) << PTEL_PR_OFFSET) | |
292 | +static inline int cpu_ptel_pr (uint32_t ptel) | |
293 | +{ | |
294 | + return ((ptel & PTEL_PR_MASK) >> PTEL_PR_OFFSET); | |
295 | +} | |
296 | + | |
297 | +/* PTEA : Page Translation Entry Assistance register */ | |
298 | +#define PTEA_SA_BITS (3) | |
299 | +#define PTEA_SA_SIZE (1 << PTEA_SA_BITS) | |
300 | +#define PTEA_SA_MASK (PTEA_SA_SIZE - 1) | |
301 | +#define cpu_ptea_sa(ptea) ((ptea) & PTEA_SA_MASK) | |
302 | +#define PTEA_TC (1 << 3) | |
303 | +#define cpu_ptea_tc(ptea) (((ptea) & PTEA_TC) >> 3) | |
304 | + | |
305 | +static inline target_ulong cpu_read_sr(CPUSHState *env) | |
306 | +{ | |
307 | + uint32_t sr = env->sr; | |
308 | + sr = FIELD_DP32(sr, SR, M, env->sr_m); | |
309 | + sr = FIELD_DP32(sr, SR, Q, env->sr_q); | |
310 | + sr = FIELD_DP32(sr, SR, T, env->sr_t); | |
311 | + return sr; | |
312 | +} | |
313 | + | |
314 | +static inline void cpu_write_sr(CPUSHState *env, target_ulong sr) | |
315 | +{ | |
316 | + env->sr = FIELD_DP32(env->sr, SR, MD, FIELD_EX32(sr, SR, MD)); | |
317 | + env->sr = FIELD_DP32(env->sr, SR, BL, FIELD_EX32(sr, SR, BL)); | |
318 | + env->sr = FIELD_DP32(env->sr, SR, RB, FIELD_EX32(sr, SR, RB)); | |
319 | + env->sr = FIELD_DP32(env->sr, SR, FD, FIELD_EX32(sr, SR, FD)); | |
320 | + env->sr = FIELD_DP32(env->sr, SR, I, FIELD_EX32(sr, SR, I)); | |
321 | + env->sr = FIELD_DP32(env->sr, SR, S, FIELD_EX32(sr, SR, S)); | |
322 | + env->sr_m = FIELD_EX32(sr, SR, M); | |
323 | + env->sr_q = FIELD_EX32(sr, SR, Q); | |
324 | + env->sr_t = FIELD_EX32(sr, SR, T); | |
325 | +} | |
326 | + | |
327 | +static inline void cpu_get_tb_cpu_state(CPUSHState *env, target_ulong *pc, | |
328 | + target_ulong *cs_base, uint32_t *flags) | |
329 | +{ | |
330 | + *pc = env->pc; | |
331 | + *flags = env->flags; /* TB_FLAG_ENVFLAGS_MASK: bits 0-2, 4-12 */ | |
332 | + *flags = FIELD_DP32(*flags, SR, MD, FIELD_EX32(env->sr, SR, MD)); | |
333 | + *flags = FIELD_DP32(*flags, SR, RB, FIELD_EX32(env->sr, SR, RB)); | |
334 | + *flags = FIELD_DP32(*flags, SR, FD, FIELD_EX32(env->sr, SR, FD)); | |
335 | + | |
336 | +} | |
337 | + | |
338 | +#endif /* CPU_H */ |
@@ -0,0 +1,154 @@ | ||
1 | +/* | |
2 | + * SuperH gdb server stub | |
3 | + * | |
4 | + * Copyright (c) 2003-2005 Fabrice Bellard | |
5 | + * Copyright (c) 2013 SUSE LINUX Products GmbH | |
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 | |
10 | + * version 2.1 of the License, or (at your option) any later version. | |
11 | + * | |
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 | |
15 | + * Lesser General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU Lesser General Public | |
18 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | + */ | |
20 | +#include "qemu/osdep.h" | |
21 | +#include "cpu.h" | |
22 | +#include "exec/gdbstub.h" | |
23 | + | |
24 | +/* Hint: Use "set architecture sh4" in GDB to see fpu registers */ | |
25 | +/* FIXME: We should use XML for this. */ | |
26 | + | |
27 | +static inline int regbank(CPUSHState *env) | |
28 | +{ | |
29 | + if ((env->features & FEATURE_ISA) >= 3) { | |
30 | + return FIELD_EX32(env->sr, SR, MD) && FIELD_EX32(env->sr, SR, RB) ? | |
31 | + 16 : 0; | |
32 | + } else { | |
33 | + return 0; | |
34 | + } | |
35 | +} | |
36 | + | |
37 | +int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) | |
38 | +{ | |
39 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
40 | + CPUSHState *env = &cpu->env; | |
41 | + | |
42 | + switch (n) { | |
43 | + case 0 ... 7: | |
44 | + return gdb_get_regl(mem_buf, env->regs[n + regbank(env)]); | |
45 | + case 8 ... 15: | |
46 | + return gdb_get_regl(mem_buf, env->regs[n]); | |
47 | + case 16: | |
48 | + return gdb_get_regl(mem_buf, env->pc); | |
49 | + case 17: | |
50 | + return gdb_get_regl(mem_buf, env->pr); | |
51 | + case 18: | |
52 | + return gdb_get_regl(mem_buf, env->gbr); | |
53 | + case 19: | |
54 | + return gdb_get_regl(mem_buf, env->vbr); | |
55 | + case 20: | |
56 | + return gdb_get_regl(mem_buf, env->mac >> 32); | |
57 | + case 21: | |
58 | + return gdb_get_regl(mem_buf, env->mac & 0xffffffff); | |
59 | + case 22: | |
60 | + return gdb_get_regl(mem_buf, cpu_read_sr(env)); | |
61 | +#if 0 | |
62 | + case 23: | |
63 | + return gdb_get_regl(mem_buf, env->fpul); | |
64 | + case 24: | |
65 | + return gdb_get_regl(mem_buf, env->fpscr); | |
66 | + case 25 ... 40: | |
67 | + if (env->fpscr & FPSCR_FR) { | |
68 | + stfl_p(mem_buf, env->fregs[n - 9]); | |
69 | + } else { | |
70 | + stfl_p(mem_buf, env->fregs[n - 25]); | |
71 | + } | |
72 | + return 4; | |
73 | +#endif | |
74 | + case 41: | |
75 | + return gdb_get_regl(mem_buf, env->ssr); | |
76 | + case 42: | |
77 | + return gdb_get_regl(mem_buf, env->spc); | |
78 | + case 43 ... 50: | |
79 | + return gdb_get_regl(mem_buf, env->regs[n - 43]); | |
80 | + case 51 ... 58: | |
81 | + return gdb_get_regl(mem_buf, env->regs[n - (51 - 16)]); | |
82 | + } | |
83 | + | |
84 | + return 0; | |
85 | +} | |
86 | + | |
87 | +int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) | |
88 | +{ | |
89 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
90 | + CPUSHState *env = &cpu->env; | |
91 | + | |
92 | + switch (n) { | |
93 | + case 0 ... 7: | |
94 | + env->regs[n + regbank(env)] = ldl_p(mem_buf); | |
95 | + break; | |
96 | + case 8 ... 15: | |
97 | + env->regs[n] = ldl_p(mem_buf); | |
98 | + break; | |
99 | + case 16: | |
100 | + env->pc = ldl_p(mem_buf); | |
101 | + break; | |
102 | + case 17: | |
103 | + env->pr = ldl_p(mem_buf); | |
104 | + break; | |
105 | + case 18: | |
106 | + env->gbr = ldl_p(mem_buf); | |
107 | + break; | |
108 | + case 19: | |
109 | + env->vbr = ldl_p(mem_buf); | |
110 | + break; | |
111 | + case 20: | |
112 | + env->mac &= 0xffffffff; | |
113 | + env->mac |= (uint64_t)ldl_p(mem_buf) << 32; | |
114 | + break; | |
115 | + case 21: | |
116 | + env->mac &= 0xffffffff00000000; | |
117 | + env->mac |= ldl_p(mem_buf); | |
118 | + break; | |
119 | + case 22: | |
120 | + cpu_write_sr(env, ldl_p(mem_buf)); | |
121 | + break; | |
122 | +#if 0 | |
123 | + case 23: | |
124 | + env->fpul = ldl_p(mem_buf); | |
125 | + break; | |
126 | + case 24: | |
127 | + env->fpscr = ldl_p(mem_buf); | |
128 | + break; | |
129 | + case 25 ... 40: | |
130 | + if (env->fpscr & FPSCR_FR) { | |
131 | + env->fregs[n - 9] = ldfl_p(mem_buf); | |
132 | + } else { | |
133 | + env->fregs[n - 25] = ldfl_p(mem_buf); | |
134 | + } | |
135 | + break; | |
136 | +#endif | |
137 | + case 41: | |
138 | + env->ssr = ldl_p(mem_buf); | |
139 | + break; | |
140 | + case 42: | |
141 | + env->spc = ldl_p(mem_buf); | |
142 | + break; | |
143 | + case 43 ... 50: | |
144 | + env->regs[n - 43] = ldl_p(mem_buf); | |
145 | + break; | |
146 | + case 51 ... 58: | |
147 | + env->regs[n - (51 - 16)] = ldl_p(mem_buf); | |
148 | + break; | |
149 | + default: | |
150 | + return 0; | |
151 | + } | |
152 | + | |
153 | + return 4; | |
154 | +} |
@@ -0,0 +1,1006 @@ | ||
1 | +/* | |
2 | + * SH emulation | |
3 | + * | |
4 | + * Copyright (c) 2005 Samuel Tardieu | |
5 | + * Copyright (c) 2019 Yoshinori Sato | |
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 | |
10 | + * version 2.1 of the License, or (at your option) any later version. | |
11 | + * | |
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 | |
15 | + * Lesser General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU Lesser General Public | |
18 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | + */ | |
20 | +#include "qemu/osdep.h" | |
21 | + | |
22 | +#include "cpu.h" | |
23 | +#include "exec/exec-all.h" | |
24 | +#include "exec/log.h" | |
25 | +#include "exec/cpu_ldst.h" | |
26 | +#include "sysemu/sysemu.h" | |
27 | + | |
28 | +#define MMU_OK 0 | |
29 | +#define MMU_ITLB_MISS (-1) | |
30 | +#define MMU_ITLB_MULTIPLE (-2) | |
31 | +#define MMU_ITLB_VIOLATION (-3) | |
32 | +#define MMU_DTLB_MISS_READ (-4) | |
33 | +#define MMU_DTLB_MISS_WRITE (-5) | |
34 | +#define MMU_DTLB_INITIAL_WRITE (-6) | |
35 | +#define MMU_DTLB_VIOLATION_READ (-7) | |
36 | +#define MMU_DTLB_VIOLATION_WRITE (-8) | |
37 | +#define MMU_DTLB_MULTIPLE (-9) | |
38 | +#define MMU_DTLB_MISS (-10) | |
39 | +#define MMU_IADDR_ERROR (-11) | |
40 | +#define MMU_DADDR_ERROR_READ (-12) | |
41 | +#define MMU_DADDR_ERROR_WRITE (-13) | |
42 | + | |
43 | +#if defined(CONFIG_USER_ONLY) | |
44 | + | |
45 | +void superh_cpu_do_interrupt(CPUState *cs) | |
46 | +{ | |
47 | + cs->exception_index = -1; | |
48 | +} | |
49 | + | |
50 | +int cpu_sh4_is_cached(CPUSHState *env, target_ulong addr) | |
51 | +{ | |
52 | + /* For user mode, only U0 area is cacheable. */ | |
53 | + return !(addr & 0x80000000); | |
54 | +} | |
55 | + | |
56 | +#else /* !CONFIG_USER_ONLY */ | |
57 | + | |
58 | +static void superh_cpu_do_interrupt_evt(CPUState *cs) | |
59 | +{ | |
60 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
61 | + CPUSHState *env = &cpu->env; | |
62 | + int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD; | |
63 | + int do_exp, irq_vector = cs->exception_index; | |
64 | + | |
65 | + /* prioritize exceptions over interrupts */ | |
66 | + | |
67 | + do_exp = cs->exception_index != -1; | |
68 | + do_irq = do_irq && (cs->exception_index == -1); | |
69 | + | |
70 | + if (FIELD_EX32(env->sr, SR, BL)) { | |
71 | + if (do_exp && cs->exception_index != 0x1e0) { | |
72 | + /* In theory a masked exception generates a reset exception, | |
73 | + which in turn jumps to the reset vector. However this only | |
74 | + works when using a bootloader. When using a kernel and an | |
75 | + initrd, they need to be reloaded and the program counter | |
76 | + should be loaded with the kernel entry point. | |
77 | + qemu_system_reset_request takes care of that. */ | |
78 | + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); | |
79 | + return; | |
80 | + } | |
81 | + if (do_irq && !env->in_sleep) { | |
82 | + return; /* masked */ | |
83 | + } | |
84 | + } | |
85 | + env->in_sleep = 0; | |
86 | + | |
87 | + if (do_irq) { | |
88 | + if (env->req_ipl >= FIELD_EX32(env->sr, SR, I)) { | |
89 | + irq_vector = env->req_irq; | |
90 | + qemu_set_irq(env->ack, irq_vector); | |
91 | + } else { | |
92 | + return; | |
93 | + } | |
94 | + } | |
95 | + | |
96 | + if (qemu_loglevel_mask(CPU_LOG_INT)) { | |
97 | + const char *expname; | |
98 | + switch (cs->exception_index) { | |
99 | + case 0x0e0: | |
100 | + expname = "addr_error"; | |
101 | + break; | |
102 | + case 0x040: | |
103 | + expname = "tlb_miss"; | |
104 | + break; | |
105 | + case 0x0a0: | |
106 | + expname = "tlb_violation"; | |
107 | + break; | |
108 | + case 0x180: | |
109 | + expname = "illegal_instruction"; | |
110 | + break; | |
111 | + case 0x1a0: | |
112 | + expname = "slot_illegal_instruction"; | |
113 | + break; | |
114 | + case 0x800: | |
115 | + expname = "fpu_disable"; | |
116 | + break; | |
117 | + case 0x820: | |
118 | + expname = "slot_fpu"; | |
119 | + break; | |
120 | + case 0x100: | |
121 | + expname = "data_write"; | |
122 | + break; | |
123 | + case 0x060: | |
124 | + expname = "dtlb_miss_write"; | |
125 | + break; | |
126 | + case 0x0c0: | |
127 | + expname = "dtlb_violation_write"; | |
128 | + break; | |
129 | + case 0x120: | |
130 | + expname = "fpu_exception"; | |
131 | + break; | |
132 | + case 0x080: | |
133 | + expname = "initial_page_write"; | |
134 | + break; | |
135 | + case 0x160: | |
136 | + expname = "trapa"; | |
137 | + break; | |
138 | + default: | |
139 | + expname = do_irq ? "interrupt" : "???"; | |
140 | + break; | |
141 | + } | |
142 | + qemu_log("exception 0x%03x [%s] raised\n", | |
143 | + irq_vector, expname); | |
144 | + log_cpu_state(cs, 0); | |
145 | + } | |
146 | + | |
147 | + env->ssr = cpu_read_sr(env); | |
148 | + env->spc = env->pc; | |
149 | + env->sgr = env->regs[15]; | |
150 | + env->sr = FIELD_DP32(env->sr, SR, BL, 1); | |
151 | + env->sr = FIELD_DP32(env->sr, SR, MD, 1); | |
152 | + env->sr = FIELD_DP32(env->sr, SR, RB, 1); | |
153 | + | |
154 | + if (env->flags & DELAY_SLOT_MASK) { | |
155 | + /* Branch instruction should be executed again before delay slot. */ | |
156 | + env->spc -= 2; | |
157 | + /* Clear flags for exception/interrupt routine. */ | |
158 | + env->flags &= ~DELAY_SLOT_MASK; | |
159 | + } | |
160 | + | |
161 | + if (do_exp) { | |
162 | + env->expevt = cs->exception_index; | |
163 | + switch (cs->exception_index) { | |
164 | + case 0x000: | |
165 | + case 0x020: | |
166 | + case 0x140: | |
167 | + env->sr = FIELD_DP32(env->sr, SR, FD, 0); | |
168 | + env->sr = FIELD_DP32(env->sr, SR, I, 0x0f); | |
169 | + env->pc = 0xa0000000; | |
170 | + break; | |
171 | + case 0x040: | |
172 | + case 0x060: | |
173 | + env->pc = env->vbr + 0x400; | |
174 | + break; | |
175 | + case 0x160: | |
176 | + env->spc += 2; /* special case for TRAPA */ | |
177 | + /* fall through */ | |
178 | + default: | |
179 | + env->pc = env->vbr + 0x100; | |
180 | + break; | |
181 | + } | |
182 | + return; | |
183 | + } | |
184 | + | |
185 | + if (do_irq) { | |
186 | + env->intevt = irq_vector; | |
187 | + env->pc = env->vbr + 0x600; | |
188 | + return; | |
189 | + } | |
190 | +} | |
191 | + | |
192 | +static void superh_cpu_do_interrupt_vec(CPUState *cs) | |
193 | +{ | |
194 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
195 | + CPUSHState *env = &cpu->env; | |
196 | + int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD; | |
197 | + int do_exp, irq_vector = cs->exception_index; | |
198 | + uint32_t sr; | |
199 | + | |
200 | + /* prioritize exceptions over interrupts */ | |
201 | + | |
202 | + do_exp = cs->exception_index != -1; | |
203 | + do_irq = do_irq && (cs->exception_index == -1); | |
204 | + | |
205 | + env->in_sleep = 0; | |
206 | + | |
207 | + if (do_irq) { | |
208 | + if (env->req_ipl >= FIELD_EX32(env->sr, SR, I)) { | |
209 | + irq_vector = env->req_irq; | |
210 | + qemu_set_irq(env->ack, irq_vector); | |
211 | + } else { | |
212 | + return; | |
213 | + } | |
214 | + } | |
215 | + | |
216 | + if (qemu_loglevel_mask(CPU_LOG_INT)) { | |
217 | + const char *expname; | |
218 | + switch (cs->exception_index) { | |
219 | + case 0x0e0: | |
220 | + expname = "addr_error"; | |
221 | + break; | |
222 | + case 0x180: | |
223 | + expname = "illegal_instruction"; | |
224 | + break; | |
225 | + case 0x1a0: | |
226 | + expname = "slot_illegal_instruction"; | |
227 | + break; | |
228 | + case 0x160: | |
229 | + expname = "trapa"; | |
230 | + irq_vector = env->tra >> 2; | |
231 | + break; | |
232 | + default: | |
233 | + expname = do_irq ? "interrupt" : "???"; | |
234 | + break; | |
235 | + } | |
236 | + qemu_log("exception 0x%03x [%s] raised\n", | |
237 | + irq_vector, expname); | |
238 | + log_cpu_state(cs, 0); | |
239 | + } | |
240 | + | |
241 | + if (env->flags & DELAY_SLOT_MASK) { | |
242 | + /* Branch instruction should be executed again before delay slot. */ | |
243 | + env->pc -= 2; | |
244 | + /* Clear flags for exception/interrupt routine. */ | |
245 | + env->flags &= ~DELAY_SLOT_MASK; | |
246 | + } | |
247 | + | |
248 | + sr = cpu_read_sr(env); | |
249 | + cpu_stl_kernel(env, env->regs[15], sr); | |
250 | + env->regs[15] -= 4; | |
251 | + cpu_stl_kernel(env, env->regs[15], env->pc); | |
252 | + env->regs[15] -= 4; | |
253 | + if (do_irq) { | |
254 | + env->sr = FIELD_DP32(env->sr, SR, I, env->req_ipl); | |
255 | + } | |
256 | + if (do_exp) { | |
257 | + switch (cs->exception_index) { | |
258 | + case 0x0e0: | |
259 | + irq_vector = 9; | |
260 | + break; | |
261 | + case 0x180: | |
262 | + irq_vector = 4; | |
263 | + break; | |
264 | + case 0x1a0: | |
265 | + irq_vector = 6; | |
266 | + break; | |
267 | + } | |
268 | + } | |
269 | + env->pc = cpu_ldl_kernel(env, env->vbr + irq_vector * 4); | |
270 | +} | |
271 | + | |
272 | +void superh_cpu_do_interrupt(CPUState *cs) | |
273 | +{ | |
274 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
275 | + CPUSHState *env = &cpu->env; | |
276 | + | |
277 | + if ((env->features & FEATURE_ISA) < 3) { | |
278 | + superh_cpu_do_interrupt_vec(cs); | |
279 | + } else { | |
280 | + superh_cpu_do_interrupt_evt(cs); | |
281 | + } | |
282 | +} | |
283 | + | |
284 | +static void update_itlb_use(CPUSHState * env, int itlbnb) | |
285 | +{ | |
286 | + uint8_t or_mask = 0, and_mask = (uint8_t) - 1; | |
287 | + | |
288 | + switch (itlbnb) { | |
289 | + case 0: | |
290 | + and_mask = 0x1f; | |
291 | + break; | |
292 | + case 1: | |
293 | + and_mask = 0xe7; | |
294 | + or_mask = 0x80; | |
295 | + break; | |
296 | + case 2: | |
297 | + and_mask = 0xfb; | |
298 | + or_mask = 0x50; | |
299 | + break; | |
300 | + case 3: | |
301 | + or_mask = 0x2c; | |
302 | + break; | |
303 | + } | |
304 | + | |
305 | + env->mmucr &= (and_mask << 24) | 0x00ffffff; | |
306 | + env->mmucr |= (or_mask << 24); | |
307 | +} | |
308 | + | |
309 | +static int itlb_replacement(CPUSHState * env) | |
310 | +{ | |
311 | + if ((env->mmucr & 0xe0000000) == 0xe0000000) { | |
312 | + return 0; | |
313 | + } | |
314 | + if ((env->mmucr & 0x98000000) == 0x18000000) { | |
315 | + return 1; | |
316 | + } | |
317 | + if ((env->mmucr & 0x54000000) == 0x04000000) { | |
318 | + return 2; | |
319 | + } | |
320 | + if ((env->mmucr & 0x2c000000) == 0x00000000) { | |
321 | + return 3; | |
322 | + } | |
323 | + cpu_abort(env_cpu(env), "Unhandled itlb_replacement"); | |
324 | +} | |
325 | + | |
326 | +/* Find the corresponding entry in the right TLB | |
327 | + Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE | |
328 | +*/ | |
329 | +static int find_tlb_entry(CPUSHState * env, target_ulong address, | |
330 | + tlb_t * entries, uint8_t nbtlb, int use_asid) | |
331 | +{ | |
332 | + int match = MMU_DTLB_MISS; | |
333 | + uint32_t start, end; | |
334 | + uint8_t asid; | |
335 | + int i; | |
336 | + | |
337 | + asid = env->pteh & 0xff; | |
338 | + | |
339 | + for (i = 0; i < nbtlb; i++) { | |
340 | + if (!entries[i].v) | |
341 | + continue; /* Invalid entry */ | |
342 | + if (!entries[i].sh && use_asid && entries[i].asid != asid) | |
343 | + continue; /* Bad ASID */ | |
344 | + start = (entries[i].vpn << 10) & ~(entries[i].size - 1); | |
345 | + end = start + entries[i].size - 1; | |
346 | + if (address >= start && address <= end) { /* Match */ | |
347 | + if (match != MMU_DTLB_MISS) | |
348 | + return MMU_DTLB_MULTIPLE; /* Multiple match */ | |
349 | + match = i; | |
350 | + } | |
351 | + } | |
352 | + return match; | |
353 | +} | |
354 | + | |
355 | +static void increment_urc(CPUSHState * env) | |
356 | +{ | |
357 | + uint8_t urb, urc; | |
358 | + | |
359 | + /* Increment URC */ | |
360 | + urb = ((env->mmucr) >> 18) & 0x3f; | |
361 | + urc = ((env->mmucr) >> 10) & 0x3f; | |
362 | + urc++; | |
363 | + if ((urb > 0 && urc > urb) || urc > (UTLB_SIZE - 1)) | |
364 | + urc = 0; | |
365 | + env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); | |
366 | +} | |
367 | + | |
368 | +/* Copy and utlb entry into itlb | |
369 | + Return entry | |
370 | +*/ | |
371 | +static int copy_utlb_entry_itlb(CPUSHState *env, int utlb) | |
372 | +{ | |
373 | + int itlb; | |
374 | + | |
375 | + tlb_t * ientry; | |
376 | + itlb = itlb_replacement(env); | |
377 | + ientry = &env->itlb[itlb]; | |
378 | + if (ientry->v) { | |
379 | + tlb_flush_page(env_cpu(env), ientry->vpn << 10); | |
380 | + } | |
381 | + *ientry = env->utlb[utlb]; | |
382 | + update_itlb_use(env, itlb); | |
383 | + return itlb; | |
384 | +} | |
385 | + | |
386 | +/* Find itlb entry | |
387 | + Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE | |
388 | +*/ | |
389 | +static int find_itlb_entry(CPUSHState * env, target_ulong address, | |
390 | + int use_asid) | |
391 | +{ | |
392 | + int e; | |
393 | + | |
394 | + e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid); | |
395 | + if (e == MMU_DTLB_MULTIPLE) { | |
396 | + e = MMU_ITLB_MULTIPLE; | |
397 | + } else if (e == MMU_DTLB_MISS) { | |
398 | + e = MMU_ITLB_MISS; | |
399 | + } else if (e >= 0) { | |
400 | + update_itlb_use(env, e); | |
401 | + } | |
402 | + return e; | |
403 | +} | |
404 | + | |
405 | +/* Find utlb entry | |
406 | + Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */ | |
407 | +static int find_utlb_entry(CPUSHState * env, target_ulong address, int use_asid) | |
408 | +{ | |
409 | + /* per utlb access */ | |
410 | + increment_urc(env); | |
411 | + | |
412 | + /* Return entry */ | |
413 | + return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); | |
414 | +} | |
415 | + | |
416 | +/* Match address against MMU | |
417 | + Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE, | |
418 | + MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ, | |
419 | + MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS, | |
420 | + MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION, | |
421 | + MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE. | |
422 | +*/ | |
423 | +static int get_mmu_address(CPUSHState * env, target_ulong * physical, | |
424 | + int *prot, target_ulong address, | |
425 | + int rw, int access_type) | |
426 | +{ | |
427 | + int use_asid, n; | |
428 | + tlb_t *matching = NULL; | |
429 | + | |
430 | + use_asid = !(env->mmucr & MMUCR_SV) || !FIELD_EX32(env->sr, SR, MD); | |
431 | + | |
432 | + if (rw == 2) { | |
433 | + n = find_itlb_entry(env, address, use_asid); | |
434 | + if (n >= 0) { | |
435 | + matching = &env->itlb[n]; | |
436 | + if (!FIELD_EX32(env->sr, SR, MD) && !(matching->pr & 2)) { | |
437 | + n = MMU_ITLB_VIOLATION; | |
438 | + } else { | |
439 | + *prot = PAGE_EXEC; | |
440 | + } | |
441 | + } else { | |
442 | + n = find_utlb_entry(env, address, use_asid); | |
443 | + if (n >= 0) { | |
444 | + n = copy_utlb_entry_itlb(env, n); | |
445 | + matching = &env->itlb[n]; | |
446 | + if (!FIELD_EX32(env->sr, SR, MD) && !(matching->pr & 2)) { | |
447 | + n = MMU_ITLB_VIOLATION; | |
448 | + } else { | |
449 | + *prot = PAGE_READ | PAGE_EXEC; | |
450 | + if ((matching->pr & 1) && matching->d) { | |
451 | + *prot |= PAGE_WRITE; | |
452 | + } | |
453 | + } | |
454 | + } else if (n == MMU_DTLB_MULTIPLE) { | |
455 | + n = MMU_ITLB_MULTIPLE; | |
456 | + } else if (n == MMU_DTLB_MISS) { | |
457 | + n = MMU_ITLB_MISS; | |
458 | + } | |
459 | + } | |
460 | + } else { | |
461 | + n = find_utlb_entry(env, address, use_asid); | |
462 | + if (n >= 0) { | |
463 | + matching = &env->utlb[n]; | |
464 | + if (!FIELD_EX32(env->sr, SR, MD) && !(matching->pr & 2)) { | |
465 | + n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE : | |
466 | + MMU_DTLB_VIOLATION_READ; | |
467 | + } else if ((rw == 1) && !(matching->pr & 1)) { | |
468 | + n = MMU_DTLB_VIOLATION_WRITE; | |
469 | + } else if ((rw == 1) && !matching->d) { | |
470 | + n = MMU_DTLB_INITIAL_WRITE; | |
471 | + } else { | |
472 | + *prot = PAGE_READ; | |
473 | + if ((matching->pr & 1) && matching->d) { | |
474 | + *prot |= PAGE_WRITE; | |
475 | + } | |
476 | + } | |
477 | + } else if (n == MMU_DTLB_MISS) { | |
478 | + n = (rw == 1) ? MMU_DTLB_MISS_WRITE : | |
479 | + MMU_DTLB_MISS_READ; | |
480 | + } | |
481 | + } | |
482 | + if (n >= 0) { | |
483 | + n = MMU_OK; | |
484 | + *physical = ((matching->ppn << 10) & ~(matching->size - 1)) | | |
485 | + (address & (matching->size - 1)); | |
486 | + } | |
487 | + return n; | |
488 | +} | |
489 | + | |
490 | +static int get_physical_address_sh4(CPUSHState * env, target_ulong * physical, | |
491 | + int *prot, target_ulong address, | |
492 | + int rw, int access_type) | |
493 | +{ | |
494 | + /* P1, P2 and P4 areas do not use translation */ | |
495 | + if ((address >= 0x80000000 && address < 0xc0000000) || | |
496 | + address >= 0xe0000000) { | |
497 | + if (!FIELD_EX32(env->sr, SR, MD) | |
498 | + && (address < 0xe0000000 || address >= 0xe4000000)) { | |
499 | + /* Unauthorized access in user mode (only store queues are available) */ | |
500 | + qemu_log_mask(LOG_GUEST_ERROR, "Unauthorized access\n"); | |
501 | + if (rw == 0) | |
502 | + return MMU_DADDR_ERROR_READ; | |
503 | + else if (rw == 1) | |
504 | + return MMU_DADDR_ERROR_WRITE; | |
505 | + else | |
506 | + return MMU_IADDR_ERROR; | |
507 | + } | |
508 | + if (address >= 0x80000000 && address < 0xc0000000) { | |
509 | + /* Mask upper 3 bits for P1 and P2 areas */ | |
510 | + *physical = address & 0x1fffffff; | |
511 | + } else { | |
512 | + *physical = address; | |
513 | + } | |
514 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
515 | + return MMU_OK; | |
516 | + } | |
517 | + | |
518 | + /* If MMU is disabled, return the corresponding physical page */ | |
519 | + if (!(env->mmucr & MMUCR_AT)) { | |
520 | + *physical = address & 0x1FFFFFFF; | |
521 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
522 | + return MMU_OK; | |
523 | + } | |
524 | + | |
525 | + /* We need to resort to the MMU */ | |
526 | + return get_mmu_address(env, physical, prot, address, rw, access_type); | |
527 | +} | |
528 | + | |
529 | +static int get_physical_address_sh2(CPUSHState * env, target_ulong * physical, | |
530 | + int *prot, target_ulong address) | |
531 | +{ | |
532 | + /* P1, P2 and P4 areas do not use translation */ | |
533 | + if ((address >= 0x80000000 && address < 0xc0000000) || | |
534 | + address >= 0xe0000000) { | |
535 | + if (address >= 0x80000000 && address < 0xc0000000) { | |
536 | + /* Mask upper 3 bits for P1 and P2 areas */ | |
537 | + *physical = address & 0x1fffffff; | |
538 | + } else { | |
539 | + *physical = address; | |
540 | + } | |
541 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
542 | + return MMU_OK; | |
543 | + } | |
544 | + | |
545 | + if (address < 0x80000000) { | |
546 | + /* P0 */ | |
547 | + *physical = address & 0x7FFFFFFF; | |
548 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
549 | + } else { | |
550 | + /* P3 */ | |
551 | + *physical = address & 0x1FFFFFFF; | |
552 | + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | |
553 | + } | |
554 | + return MMU_OK; | |
555 | +} | |
556 | + | |
557 | +hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | |
558 | +{ | |
559 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
560 | + CPUSHState *env = &cpu->env; | |
561 | + target_ulong physical; | |
562 | + int prot; | |
563 | + | |
564 | + switch(env->features & FEATURE_ISA) { | |
565 | + case 2: | |
566 | + get_physical_address_sh2(env, &physical, &prot, addr); | |
567 | + break; | |
568 | + case 4: | |
569 | + get_physical_address_sh4(env, &physical, &prot, addr, 0, 0); | |
570 | + break; | |
571 | + } | |
572 | + return physical; | |
573 | +} | |
574 | + | |
575 | +void cpu_load_tlb(CPUSHState * env) | |
576 | +{ | |
577 | + CPUState *cs = env_cpu(env); | |
578 | + int n = cpu_mmucr_urc(env->mmucr); | |
579 | + tlb_t * entry = &env->utlb[n]; | |
580 | + | |
581 | + if (entry->v) { | |
582 | + /* Overwriting valid entry in utlb. */ | |
583 | + target_ulong address = entry->vpn << 10; | |
584 | + tlb_flush_page(cs, address); | |
585 | + } | |
586 | + | |
587 | + /* Take values into cpu status from registers. */ | |
588 | + entry->asid = (uint8_t)cpu_pteh_asid(env->pteh); | |
589 | + entry->vpn = cpu_pteh_vpn(env->pteh); | |
590 | + entry->v = (uint8_t)cpu_ptel_v(env->ptel); | |
591 | + entry->ppn = cpu_ptel_ppn(env->ptel); | |
592 | + entry->sz = (uint8_t)cpu_ptel_sz(env->ptel); | |
593 | + switch (entry->sz) { | |
594 | + case 0: /* 00 */ | |
595 | + entry->size = 1024; /* 1K */ | |
596 | + break; | |
597 | + case 1: /* 01 */ | |
598 | + entry->size = 1024 * 4; /* 4K */ | |
599 | + break; | |
600 | + case 2: /* 10 */ | |
601 | + entry->size = 1024 * 64; /* 64K */ | |
602 | + break; | |
603 | + case 3: /* 11 */ | |
604 | + entry->size = 1024 * 1024; /* 1M */ | |
605 | + break; | |
606 | + default: | |
607 | + cpu_abort(cs, "Unhandled load_tlb"); | |
608 | + break; | |
609 | + } | |
610 | + entry->sh = (uint8_t)cpu_ptel_sh(env->ptel); | |
611 | + entry->c = (uint8_t)cpu_ptel_c(env->ptel); | |
612 | + entry->pr = (uint8_t)cpu_ptel_pr(env->ptel); | |
613 | + entry->d = (uint8_t)cpu_ptel_d(env->ptel); | |
614 | + entry->wt = (uint8_t)cpu_ptel_wt(env->ptel); | |
615 | + entry->sa = (uint8_t)cpu_ptea_sa(env->ptea); | |
616 | + entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); | |
617 | +} | |
618 | + | |
619 | + void cpu_sh4_invalidate_tlb(CPUSHState *s) | |
620 | +{ | |
621 | + int i; | |
622 | + | |
623 | + /* UTLB */ | |
624 | + for (i = 0; i < UTLB_SIZE; i++) { | |
625 | + tlb_t * entry = &s->utlb[i]; | |
626 | + entry->v = 0; | |
627 | + } | |
628 | + /* ITLB */ | |
629 | + for (i = 0; i < ITLB_SIZE; i++) { | |
630 | + tlb_t * entry = &s->itlb[i]; | |
631 | + entry->v = 0; | |
632 | + } | |
633 | + | |
634 | + tlb_flush(env_cpu(s)); | |
635 | +} | |
636 | + | |
637 | +uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSHState *s, | |
638 | + hwaddr addr) | |
639 | +{ | |
640 | + int index = (addr & 0x00000300) >> 8; | |
641 | + tlb_t * entry = &s->itlb[index]; | |
642 | + | |
643 | + return (entry->vpn << 10) | | |
644 | + (entry->v << 8) | | |
645 | + (entry->asid); | |
646 | +} | |
647 | + | |
648 | +void cpu_sh4_write_mmaped_itlb_addr(CPUSHState *s, hwaddr addr, | |
649 | + uint32_t mem_value) | |
650 | +{ | |
651 | + uint32_t vpn = (mem_value & 0xfffffc00) >> 10; | |
652 | + uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); | |
653 | + uint8_t asid = (uint8_t)(mem_value & 0x000000ff); | |
654 | + | |
655 | + int index = (addr & 0x00000300) >> 8; | |
656 | + tlb_t * entry = &s->itlb[index]; | |
657 | + if (entry->v) { | |
658 | + /* Overwriting valid entry in itlb. */ | |
659 | + target_ulong address = entry->vpn << 10; | |
660 | + tlb_flush_page(env_cpu(s), address); | |
661 | + } | |
662 | + entry->asid = asid; | |
663 | + entry->vpn = vpn; | |
664 | + entry->v = v; | |
665 | +} | |
666 | + | |
667 | +uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSHState *s, | |
668 | + hwaddr addr) | |
669 | +{ | |
670 | + int array = (addr & 0x00800000) >> 23; | |
671 | + int index = (addr & 0x00000300) >> 8; | |
672 | + tlb_t * entry = &s->itlb[index]; | |
673 | + | |
674 | + if (array == 0) { | |
675 | + /* ITLB Data Array 1 */ | |
676 | + return (entry->ppn << 10) | | |
677 | + (entry->v << 8) | | |
678 | + (entry->pr << 5) | | |
679 | + ((entry->sz & 1) << 6) | | |
680 | + ((entry->sz & 2) << 4) | | |
681 | + (entry->c << 3) | | |
682 | + (entry->sh << 1); | |
683 | + } else { | |
684 | + /* ITLB Data Array 2 */ | |
685 | + return (entry->tc << 1) | | |
686 | + (entry->sa); | |
687 | + } | |
688 | +} | |
689 | + | |
690 | +void cpu_sh4_write_mmaped_itlb_data(CPUSHState *s, hwaddr addr, | |
691 | + uint32_t mem_value) | |
692 | +{ | |
693 | + int array = (addr & 0x00800000) >> 23; | |
694 | + int index = (addr & 0x00000300) >> 8; | |
695 | + tlb_t * entry = &s->itlb[index]; | |
696 | + | |
697 | + if (array == 0) { | |
698 | + /* ITLB Data Array 1 */ | |
699 | + if (entry->v) { | |
700 | + /* Overwriting valid entry in utlb. */ | |
701 | + target_ulong address = entry->vpn << 10; | |
702 | + tlb_flush_page(env_cpu(s), address); | |
703 | + } | |
704 | + entry->ppn = (mem_value & 0x1ffffc00) >> 10; | |
705 | + entry->v = (mem_value & 0x00000100) >> 8; | |
706 | + entry->sz = (mem_value & 0x00000080) >> 6 | | |
707 | + (mem_value & 0x00000010) >> 4; | |
708 | + entry->pr = (mem_value & 0x00000040) >> 5; | |
709 | + entry->c = (mem_value & 0x00000008) >> 3; | |
710 | + entry->sh = (mem_value & 0x00000002) >> 1; | |
711 | + } else { | |
712 | + /* ITLB Data Array 2 */ | |
713 | + entry->tc = (mem_value & 0x00000008) >> 3; | |
714 | + entry->sa = (mem_value & 0x00000007); | |
715 | + } | |
716 | +} | |
717 | + | |
718 | +uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSHState *s, | |
719 | + hwaddr addr) | |
720 | +{ | |
721 | + int index = (addr & 0x00003f00) >> 8; | |
722 | + tlb_t * entry = &s->utlb[index]; | |
723 | + | |
724 | + increment_urc(s); /* per utlb access */ | |
725 | + | |
726 | + return (entry->vpn << 10) | | |
727 | + (entry->v << 8) | | |
728 | + (entry->asid); | |
729 | +} | |
730 | + | |
731 | +void cpu_sh4_write_mmaped_utlb_addr(CPUSHState *s, hwaddr addr, | |
732 | + uint32_t mem_value) | |
733 | +{ | |
734 | + int associate = addr & 0x0000080; | |
735 | + uint32_t vpn = (mem_value & 0xfffffc00) >> 10; | |
736 | + uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9); | |
737 | + uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); | |
738 | + uint8_t asid = (uint8_t)(mem_value & 0x000000ff); | |
739 | + int use_asid = !(s->mmucr & MMUCR_SV) || !FIELD_EX32(s->sr, SR, MD); | |
740 | + | |
741 | + if (associate) { | |
742 | + int i; | |
743 | + tlb_t * utlb_match_entry = NULL; | |
744 | + int needs_tlb_flush = 0; | |
745 | + | |
746 | + /* search UTLB */ | |
747 | + for (i = 0; i < UTLB_SIZE; i++) { | |
748 | + tlb_t * entry = &s->utlb[i]; | |
749 | + if (!entry->v) | |
750 | + continue; | |
751 | + | |
752 | + if (entry->vpn == vpn | |
753 | + && (!use_asid || entry->asid == asid || entry->sh)) { | |
754 | + if (utlb_match_entry) { | |
755 | + CPUState *cs = env_cpu(s); | |
756 | + | |
757 | + /* Multiple TLB Exception */ | |
758 | + cs->exception_index = 0x140; | |
759 | + s->tea = addr; | |
760 | + break; | |
761 | + } | |
762 | + if (entry->v && !v) | |
763 | + needs_tlb_flush = 1; | |
764 | + entry->v = v; | |
765 | + entry->d = d; | |
766 | + utlb_match_entry = entry; | |
767 | + } | |
768 | + increment_urc(s); /* per utlb access */ | |
769 | + } | |
770 | + | |
771 | + /* search ITLB */ | |
772 | + for (i = 0; i < ITLB_SIZE; i++) { | |
773 | + tlb_t * entry = &s->itlb[i]; | |
774 | + if (entry->vpn == vpn | |
775 | + && (!use_asid || entry->asid == asid || entry->sh)) { | |
776 | + if (entry->v && !v) | |
777 | + needs_tlb_flush = 1; | |
778 | + if (utlb_match_entry) | |
779 | + *entry = *utlb_match_entry; | |
780 | + else | |
781 | + entry->v = v; | |
782 | + break; | |
783 | + } | |
784 | + } | |
785 | + | |
786 | + if (needs_tlb_flush) { | |
787 | + tlb_flush_page(env_cpu(s), vpn << 10); | |
788 | + } | |
789 | + } else { | |
790 | + int index = (addr & 0x00003f00) >> 8; | |
791 | + tlb_t * entry = &s->utlb[index]; | |
792 | + if (entry->v) { | |
793 | + CPUState *cs = env_cpu(s); | |
794 | + | |
795 | + /* Overwriting valid entry in utlb. */ | |
796 | + target_ulong address = entry->vpn << 10; | |
797 | + tlb_flush_page(cs, address); | |
798 | + } | |
799 | + entry->asid = asid; | |
800 | + entry->vpn = vpn; | |
801 | + entry->d = d; | |
802 | + entry->v = v; | |
803 | + increment_urc(s); | |
804 | + } | |
805 | +} | |
806 | + | |
807 | +uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSHState *s, | |
808 | + hwaddr addr) | |
809 | +{ | |
810 | + int array = (addr & 0x00800000) >> 23; | |
811 | + int index = (addr & 0x00003f00) >> 8; | |
812 | + tlb_t * entry = &s->utlb[index]; | |
813 | + | |
814 | + increment_urc(s); /* per utlb access */ | |
815 | + | |
816 | + if (array == 0) { | |
817 | + /* ITLB Data Array 1 */ | |
818 | + return (entry->ppn << 10) | | |
819 | + (entry->v << 8) | | |
820 | + (entry->pr << 5) | | |
821 | + ((entry->sz & 1) << 6) | | |
822 | + ((entry->sz & 2) << 4) | | |
823 | + (entry->c << 3) | | |
824 | + (entry->d << 2) | | |
825 | + (entry->sh << 1) | | |
826 | + (entry->wt); | |
827 | + } else { | |
828 | + /* ITLB Data Array 2 */ | |
829 | + return (entry->tc << 1) | | |
830 | + (entry->sa); | |
831 | + } | |
832 | +} | |
833 | + | |
834 | +void cpu_sh4_write_mmaped_utlb_data(CPUSHState *s, hwaddr addr, | |
835 | + uint32_t mem_value) | |
836 | +{ | |
837 | + int array = (addr & 0x00800000) >> 23; | |
838 | + int index = (addr & 0x00003f00) >> 8; | |
839 | + tlb_t * entry = &s->utlb[index]; | |
840 | + | |
841 | + increment_urc(s); /* per utlb access */ | |
842 | + | |
843 | + if (array == 0) { | |
844 | + /* UTLB Data Array 1 */ | |
845 | + if (entry->v) { | |
846 | + /* Overwriting valid entry in utlb. */ | |
847 | + target_ulong address = entry->vpn << 10; | |
848 | + tlb_flush_page(env_cpu(s), address); | |
849 | + } | |
850 | + entry->ppn = (mem_value & 0x1ffffc00) >> 10; | |
851 | + entry->v = (mem_value & 0x00000100) >> 8; | |
852 | + entry->sz = (mem_value & 0x00000080) >> 6 | | |
853 | + (mem_value & 0x00000010) >> 4; | |
854 | + entry->pr = (mem_value & 0x00000060) >> 5; | |
855 | + entry->c = (mem_value & 0x00000008) >> 3; | |
856 | + entry->d = (mem_value & 0x00000004) >> 2; | |
857 | + entry->sh = (mem_value & 0x00000002) >> 1; | |
858 | + entry->wt = (mem_value & 0x00000001); | |
859 | + } else { | |
860 | + /* UTLB Data Array 2 */ | |
861 | + entry->tc = (mem_value & 0x00000008) >> 3; | |
862 | + entry->sa = (mem_value & 0x00000007); | |
863 | + } | |
864 | +} | |
865 | + | |
866 | +int cpu_sh4_is_cached(CPUSHState * env, target_ulong addr) | |
867 | +{ | |
868 | + int n; | |
869 | + int use_asid = !(env->mmucr & MMUCR_SV) || !FIELD_EX32(env->sr, SR, MD); | |
870 | + | |
871 | + /* check area */ | |
872 | + if (FIELD_EX32(env->sr, SR, MD)) { | |
873 | + /* For privileged mode, P2 and P4 area is not cacheable. */ | |
874 | + if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr) | |
875 | + return 0; | |
876 | + } else { | |
877 | + /* For user mode, only U0 area is cacheable. */ | |
878 | + if (0x80000000 <= addr) | |
879 | + return 0; | |
880 | + } | |
881 | + | |
882 | + /* | |
883 | + * TODO : Evaluate CCR and check if the cache is on or off. | |
884 | + * Now CCR is not in CPUSHState, but in SH7750State. | |
885 | + * When you move the ccr into CPUSHState, the code will be | |
886 | + * as follows. | |
887 | + */ | |
888 | +#if 0 | |
889 | + /* check if operand cache is enabled or not. */ | |
890 | + if (!(env->ccr & 1)) | |
891 | + return 0; | |
892 | +#endif | |
893 | + | |
894 | + /* if MMU is off, no check for TLB. */ | |
895 | + if (env->mmucr & MMUCR_AT) | |
896 | + return 1; | |
897 | + | |
898 | + /* check TLB */ | |
899 | + n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid); | |
900 | + if (n >= 0) | |
901 | + return env->itlb[n].c; | |
902 | + | |
903 | + n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid); | |
904 | + if (n >= 0) | |
905 | + return env->utlb[n].c; | |
906 | + | |
907 | + return 0; | |
908 | +} | |
909 | + | |
910 | +#endif | |
911 | + | |
912 | +bool superh_cpu_exec_interrupt(CPUState *cs, int interrupt_request) | |
913 | +{ | |
914 | + if (interrupt_request & CPU_INTERRUPT_HARD) { | |
915 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
916 | + CPUSHState *env = &cpu->env; | |
917 | + | |
918 | + /* Delay slots are indivisible, ignore interrupts */ | |
919 | + if (env->flags & DELAY_SLOT_MASK) { | |
920 | + return false; | |
921 | + } else { | |
922 | + superh_cpu_do_interrupt(cs); | |
923 | + return true; | |
924 | + } | |
925 | + } | |
926 | + return false; | |
927 | +} | |
928 | + | |
929 | +bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size, | |
930 | + MMUAccessType access_type, int mmu_idx, | |
931 | + bool probe, uintptr_t retaddr) | |
932 | +{ | |
933 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
934 | + CPUSHState *env = &cpu->env; | |
935 | + int ret; | |
936 | + | |
937 | +#ifdef CONFIG_USER_ONLY | |
938 | + ret = (access_type == MMU_DATA_STORE ? MMU_DTLB_VIOLATION_WRITE : | |
939 | + access_type == MMU_INST_FETCH ? MMU_ITLB_VIOLATION : | |
940 | + MMU_DTLB_VIOLATION_READ); | |
941 | +#else | |
942 | + target_ulong physical; | |
943 | + int prot, sh_access_type; | |
944 | + | |
945 | + sh_access_type = ACCESS_INT; | |
946 | + switch(env->features & FEATURE_ISA) { | |
947 | + case 2: | |
948 | + ret = get_physical_address_sh2(env, &physical, &prot, address); | |
949 | + break; | |
950 | + case 4: | |
951 | + ret = get_physical_address_sh4(env, &physical, &prot, address, | |
952 | + access_type, sh_access_type); | |
953 | + break; | |
954 | + } | |
955 | + if (ret == MMU_OK) { | |
956 | + address &= TARGET_PAGE_MASK; | |
957 | + physical &= TARGET_PAGE_MASK; | |
958 | + tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE); | |
959 | + return true; | |
960 | + } | |
961 | + if (probe) { | |
962 | + return false; | |
963 | + } | |
964 | + | |
965 | + if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) { | |
966 | + env->pteh = (env->pteh & PTEH_ASID_MASK) | (address & PTEH_VPN_MASK); | |
967 | + } | |
968 | +#endif | |
969 | + | |
970 | + env->tea = address; | |
971 | + switch (ret) { | |
972 | + case MMU_ITLB_MISS: | |
973 | + case MMU_DTLB_MISS_READ: | |
974 | + cs->exception_index = 0x040; | |
975 | + break; | |
976 | + case MMU_DTLB_MULTIPLE: | |
977 | + case MMU_ITLB_MULTIPLE: | |
978 | + cs->exception_index = 0x140; | |
979 | + break; | |
980 | + case MMU_ITLB_VIOLATION: | |
981 | + cs->exception_index = 0x0a0; | |
982 | + break; | |
983 | + case MMU_DTLB_MISS_WRITE: | |
984 | + cs->exception_index = 0x060; | |
985 | + break; | |
986 | + case MMU_DTLB_INITIAL_WRITE: | |
987 | + cs->exception_index = 0x080; | |
988 | + break; | |
989 | + case MMU_DTLB_VIOLATION_READ: | |
990 | + cs->exception_index = 0x0a0; | |
991 | + break; | |
992 | + case MMU_DTLB_VIOLATION_WRITE: | |
993 | + cs->exception_index = 0x0c0; | |
994 | + break; | |
995 | + case MMU_IADDR_ERROR: | |
996 | + case MMU_DADDR_ERROR_READ: | |
997 | + cs->exception_index = 0x0e0; | |
998 | + break; | |
999 | + case MMU_DADDR_ERROR_WRITE: | |
1000 | + cs->exception_index = 0x100; | |
1001 | + break; | |
1002 | + default: | |
1003 | + cpu_abort(cs, "Unhandled MMU fault"); | |
1004 | + } | |
1005 | + cpu_loop_exit_restore(cs, retaddr); | |
1006 | +} |
@@ -0,0 +1,13 @@ | ||
1 | +DEF_HELPER_1(ldtlb, void, env) | |
2 | +DEF_HELPER_1(raise_illegal_instruction, noreturn, env) | |
3 | +DEF_HELPER_1(raise_slot_illegal_instruction, noreturn, env) | |
4 | +DEF_HELPER_1(raise_fpu_disable, noreturn, env) | |
5 | +DEF_HELPER_1(raise_slot_fpu_disable, noreturn, env) | |
6 | +DEF_HELPER_1(debug, noreturn, env) | |
7 | +DEF_HELPER_1(sleep, noreturn, env) | |
8 | +DEF_HELPER_2(trapa, noreturn, env, i32) | |
9 | +DEF_HELPER_1(exclusive, noreturn, env) | |
10 | + | |
11 | +DEF_HELPER_3(macl, void, env, i32, i32) | |
12 | +DEF_HELPER_3(macw, void, env, i32, i32) | |
13 | + |
@@ -0,0 +1,236 @@ | ||
1 | +&rn_imm rn imm | |
2 | +&rn_dsp rn dsp sz | |
3 | +&rn_mem rn rm sz | |
4 | +&rn_rm_dsp rn rm dsp sz | |
5 | +&rn_rm rn rm | |
6 | +&rn rn | |
7 | +&rm rm | |
8 | +&imm imm | |
9 | +&rn_rm_cd rn rm cd | |
10 | + | |
11 | +@rn_imm .... rn:4 imm:s8 &rn_imm | |
12 | +@rn_pc .... rn:4 dsp:8 &rn_dsp | |
13 | +@rnm .... rn:4 rm:4 .. sz:2 &rn_mem | |
14 | +@rnd .... .. sz:2 rn:4 dsp:4 &rn_rm_dsp | |
15 | +@rmd .... .. sz:2 rm:4 dsp:4 &rn_rm_dsp | |
16 | +@rnrm .... rn:4 rm:4 .... &rn_rm | |
17 | +@cmp .... rn:4 rm:4 cd:4 | |
18 | +@cmp_pl .... rn:4 .... .... &rn_rm_cd rm=0 cd=5 | |
19 | +@cmp_pz .... rn:4 .... .... &rn_rm_cd rm=0 cd=1 | |
20 | +@cmp_s .... rn:4 rm:4 .... &rn_rm_cd cd=12 | |
21 | +@rn .... rn:4 .... .... &rn | |
22 | +@rm .... rm:4 .... .... &rm | |
23 | +@imm .... .... imm:8 &imm | |
24 | +# MOV #imm,Rn | |
25 | +MOV_ir 1110 .... .... .... @rn_imm | |
26 | +# MOV.W @(disp,PC),Rn | |
27 | +MOV_pc_r 1001 .... .... .... @rn_pc sz=1 | |
28 | +# MOV.L @(disp,PC),Rn | |
29 | +MOV_pc_r 1101 .... .... .... @rn_pc sz=2 | |
30 | +# MOV Rm,Rn | |
31 | +# MOV.<BWL> @Rm,Rn | |
32 | +{ | |
33 | + MOV_rr 0110 .... .... 0011 @rnrm | |
34 | + MOV_mr 0110 .... .... 00 .. @rnm | |
35 | +} | |
36 | +# MOV.<BWL> Rm,@Rn | |
37 | +MOV_rm 0010 .... .... 00 .. @rnm | |
38 | +# MOV.<BWL> Rm,@-Rn | |
39 | +# DIV0S Rm,Rn | |
40 | +{ | |
41 | + DIV0S 0010 .... .... 0111 @rnrm | |
42 | + MOV_rmd 0010 .... .... 01 .. @rnm | |
43 | +} | |
44 | +# MOV.<BWL> @Rm+,Rn | |
45 | +# NOT Rm,Rn | |
46 | +{ | |
47 | + NOT 0110 .... .... 0111 @rnrm | |
48 | + MOV_mir 0110 .... .... 01 .. @rnm | |
49 | +} | |
50 | +# MOV.<BW> R0,@(disp,Rn) | |
51 | +MOV_rm_rn_dsp 1000 00 .. .... .... @rnd rm=0 | |
52 | +# MOV.L Rm,@(disp,Rn) | |
53 | +MOV_rm_rn_dsp 0001 rn:4 rm:4 dsp:4 &rn_rm_dsp sz=2 | |
54 | +# MOV.<BW> @(disp,Rm),R0 | |
55 | +MOV_rm_dsp_rn 1000 01 .. .... .... @rmd rn=0 | |
56 | +# MOV.L @(disp,Rm),Rn | |
57 | +MOV_rm_dsp_rn 0101 rn:4 rm:4 dsp:4 &rn_rm_dsp sz=2 | |
58 | +# MOV.<BWL> Rm,@(R0,Rn) | |
59 | +# MUL.L Rm,Rn | |
60 | +{ | |
61 | + MUL 0000 .... .... 0111 @rnrm | |
62 | + MOV_rm_r0_rn 0000 .... .... 01 .. @rnm | |
63 | +} | |
64 | +# MOV.<BWL> @(R0,Rm),Rn | |
65 | +# MAC.L @Rm+,@Rn+ | |
66 | +{ | |
67 | + MACL 0000 .... .... 1111 @rnrm | |
68 | + MOV_r0_rm_rn 0000 .... .... 11 .. @rnm | |
69 | +} | |
70 | +# MOV.<BWL> R0,@(disp,GBR) | |
71 | +# TRAPA #imm | |
72 | +{ | |
73 | + TRAPA 11000011 imm:8 | |
74 | + MOV_r0_dsp_gbr 1100 00 sz:2 dsp:8 | |
75 | +} | |
76 | +# MOV.B @(disp,GBR),R0 | |
77 | +# MOVA @(disp,PC),R0 | |
78 | +{ | |
79 | + MOVA 1100 0111 dsp:8 | |
80 | + MOV_dsp_gbr_r0 1100 01 sz:2 dsp:8 | |
81 | +} | |
82 | +# MOVT Rn | |
83 | +MOVT 0000 .... 0010 1001 @rn | |
84 | +# SWAP.<BW> Rm,Rn | |
85 | +# NEG Rm,Rn | |
86 | +# NEGC Rm,Rn | |
87 | +{ | |
88 | + NEG 0110 .... .... 1011 @rnrm | |
89 | + NEGC 0110 .... .... 1010 @rnrm | |
90 | + SWAP 0110 .... .... 10 .. @rnm | |
91 | +} | |
92 | +# XTRCT Rm,Rn | |
93 | +XTRACT 0010 .... .... 1101 @rnrm | |
94 | +# ADD Rm,Rn | |
95 | +# ADDC Rm,Rn | |
96 | +# ADDV Rm,Rn | |
97 | +# DIV1 Rm,Rn | |
98 | +# DMULS.L Rm,Rn | |
99 | +# DMULU.L Rm,Rn | |
100 | +# CMP/EQ Rm,Rn | |
101 | +# CMP/HS Rm,Rn | |
102 | +# CMP/GE Rm,Rn | |
103 | +# CMP/HI Rm,Rn | |
104 | +# CMP/GT Rm,Rn | |
105 | +# SUB Rm,Rn | |
106 | +# SUBC Rm,Rn | |
107 | +# SUBV Rm,Rn | |
108 | +{ | |
109 | + ADD_rr 0011 .... .... 1100 @rnrm | |
110 | + ADDC 0011 .... .... 1110 @rnrm | |
111 | + ADDV 0011 .... .... 1111 @rnrm | |
112 | + DIV1 0011 .... .... 0100 @rnrm | |
113 | + DMULS 0011 .... .... 1101 @rnrm | |
114 | + DMULU 0011 .... .... 0101 @rnrm | |
115 | + SUB 0011 .... .... 1000 @rnrm | |
116 | + SUBC 0011 .... .... 1010 @rnrm | |
117 | + SUBV 0011 .... .... 1011 @rnrm | |
118 | + CMP_cd 0011 .... .... .... @cmp | |
119 | +} | |
120 | +# ADD #imm,Rn | |
121 | +ADD_ir 0111 .... .... .... @rn_imm | |
122 | +# CMP/EQ #imm,R0 | |
123 | +CMP_eq 1000 1000 imm:s8 | |
124 | +# CMP/PL Rn | |
125 | +CMP_cd 0100 .... 0001 0101 @cmp_pl | |
126 | +# CMP/PZ Rn | |
127 | +CMP_cd 0100 .... 0001 0001 @cmp_pz | |
128 | +# CMP/STR Rm,Rn | |
129 | +CMP_cd 0010 .... .... 1100 @cmp_s | |
130 | +# DIV0U | |
131 | +DIV0U 0000 0000 0001 1001 | |
132 | +# DT Rn | |
133 | +DT 0100 .... 0001 0000 @rn | |
134 | +# EXTS.<BW> Rm,Rn | |
135 | +EXTS 0110 rn:4 rm:4 111 sz:1 | |
136 | +# EXTU.<BW> Rm,Rn | |
137 | +EXTU 0110 rn:4 rm:4 110 sz:1 | |
138 | +# MAC.W @Rm+,@Rn+ | |
139 | +MACW 0100 .... .... 1111 @rnrm | |
140 | +# MULS.W Rm,Rn | |
141 | +MULS 0010 .... .... 1111 @rnrm | |
142 | +# MULU.W Rm,Rn | |
143 | +MULU 0010 .... .... 1110 @rnrm | |
144 | +# AND Rm,Rn | |
145 | +AND_rr 0010 .... .... 1001 @rnrm | |
146 | +# AND #imm,R0 | |
147 | +AND_ir 1100 1001 .... .... @imm | |
148 | +# AND.B #imm,@(R0,GBR) | |
149 | +AND_im 1100 1101 .... .... @imm | |
150 | +# OR Rm,Rn | |
151 | +OR_rr 0010 .... .... 1011 @rnrm | |
152 | +# OR #imm,R0 | |
153 | +OR_ir 1100 1011 .... .... @imm | |
154 | +# OR.B #imm,@(R0,GBR) | |
155 | +OR_im 1100 1111 .... .... @imm | |
156 | +# TAS.B @Rn | |
157 | +TAS 0100 .... 0001 1011 @rn | |
158 | +# TST Rm,Rn | |
159 | +TST_rr 0010 .... .... 1000 @rnrm | |
160 | +# TST #imm,R0 | |
161 | +TST_ir 1100 1000 .... .... @imm | |
162 | +# TST.B #imm,@(R0,GBR) | |
163 | +TST_im 1100 1100 .... .... @imm | |
164 | +# XOR Rm,Rn | |
165 | +XOR_rr 0010 .... .... 1010 @rnrm | |
166 | +# XOR #imm,R0 | |
167 | +XOR_ir 1100 1010 .... .... @imm | |
168 | +# XOR.B #imm,@(R0,GBR) | |
169 | +XOR_im 1100 1110 .... .... @imm | |
170 | +# ROTL Rn | |
171 | +ROTL 0100 .... 0000 0100 @rn | |
172 | +# ROTR Rn | |
173 | +ROTR 0100 .... 0000 0101 @rn | |
174 | +# ROTCL Rn | |
175 | +ROTCL 0100 .... 0010 0100 @rn | |
176 | +# ROTCR Rn | |
177 | +ROTCR 0100 .... 0010 0101 @rn | |
178 | +# SHAL Rn | |
179 | +SHAL 0100 .... 0010 0000 @rn | |
180 | +# SHAR Rn | |
181 | +SHAR 0100 .... 0010 0001 @rn | |
182 | +# SHLL Rn | |
183 | +SHLL 0100 .... 0000 0000 @rn | |
184 | +# SHLR Rn | |
185 | +SHLR 0100 .... 0000 0001 @rn | |
186 | +# SHLL<2,8,16> Rn | |
187 | +SHLL2 0100 rn:4 00 n:2 1000 | |
188 | +# SHLR<2,8,16> Rn | |
189 | +SHLR2 0100 rn:4 00 n:2 1001 | |
190 | +# BF label | |
191 | +# BF/S label | |
192 | +# BT label | |
193 | +# BT/S label | |
194 | +BRANCH_T 1000 1 d:1 nt:1 1 dsp:s8 | |
195 | +# BRA label | |
196 | +BRA 1010 dsp:s12 | |
197 | +# BRAF Rm | |
198 | +BRAF 0000 .... 0010 0011 @rm | |
199 | +# BSR label | |
200 | +BSR 1011 dsp:s12 | |
201 | +# BSRF Rm | |
202 | +BSRF 0000 .... 0000 0011 @rm | |
203 | +# JMP @Rm | |
204 | +JMP 0100 .... 0010 1011 @rm | |
205 | +# JSR @Rm | |
206 | +JSR 0100 .... 0000 1011 @rm | |
207 | +# RTS | |
208 | +RTS 0000 0000 0000 1011 | |
209 | +# CLRMAC | |
210 | +CLRMAC 0000 0000 0010 1000 | |
211 | +# CLRT | |
212 | +CLRT 0000 0000 0000 1000 | |
213 | +# LDC Rm,<SR,GBR,VBR> | |
214 | +LDC_r 0100 rm:4 dst:4 1110 | |
215 | +# LDC.L @Rm+,<SR,GBR,VBR> | |
216 | +LDC_m 0100 rm:4 dst:4 0111 | |
217 | +# LDS Rm,<MACH,MACL,PR> | |
218 | +LDS_r 0100 rm:4 dst:4 1010 | |
219 | +# LDS.L @Rm+,MACH | |
220 | +LDS_m 0100 rm:4 dst:4 0110 | |
221 | +# NOP | |
222 | +NOP 0000 0000 0000 1001 | |
223 | +# RTE | |
224 | +RTE 0000 0000 0010 1011 | |
225 | +# SETT | |
226 | +SETT 0000 0000 0001 1000 | |
227 | +# SLEEP | |
228 | +SLEEP 0000 0000 0001 1011 | |
229 | +# STC <SR,GBR,VBR>,Rn | |
230 | +STC_r 0000 rn:4 src:4 0010 | |
231 | +# STC.L <SR,GBR,VBR>,@-Rn | |
232 | +STC_m 0100 rn:4 src:4 0011 | |
233 | +# STS <MACH,MACL,PR>,Rn | |
234 | +STS_r 0000 rn:4 src:4 1010 | |
235 | +# STS.L <MACH,MACL,PR>,@-Rn | |
236 | +STS_m 0100 rn:4 src:4 0010 |
@@ -0,0 +1,133 @@ | ||
1 | +/* | |
2 | + * SH4 emulation | |
3 | + * | |
4 | + * Copyright (c) 2005 Samuel Tardieu | |
5 | + * | |
6 | + * This library is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU Lesser General Public | |
8 | + * License as published by the Free Software Foundation; either | |
9 | + * version 2.1 of the License, or (at your option) any later version. | |
10 | + * | |
11 | + * This library is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | + * Lesser General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU Lesser General Public | |
17 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | + */ | |
19 | +#include "qemu/osdep.h" | |
20 | +#include "cpu.h" | |
21 | +#include "exec/helper-proto.h" | |
22 | +#include "exec/exec-all.h" | |
23 | +#include "exec/cpu_ldst.h" | |
24 | +#include "fpu/softfloat.h" | |
25 | + | |
26 | +#ifndef CONFIG_USER_ONLY | |
27 | + | |
28 | +void superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr, | |
29 | + MMUAccessType access_type, | |
30 | + int mmu_idx, uintptr_t retaddr) | |
31 | +{ | |
32 | + switch (access_type) { | |
33 | + case MMU_INST_FETCH: | |
34 | + case MMU_DATA_LOAD: | |
35 | + cs->exception_index = 0x0e0; | |
36 | + break; | |
37 | + case MMU_DATA_STORE: | |
38 | + cs->exception_index = 0x100; | |
39 | + break; | |
40 | + } | |
41 | + cpu_loop_exit_restore(cs, retaddr); | |
42 | +} | |
43 | + | |
44 | +#endif | |
45 | + | |
46 | +void helper_ldtlb(CPUSHState *env) | |
47 | +{ | |
48 | +#ifdef CONFIG_USER_ONLY | |
49 | + cpu_abort(env_cpu(env), "Unhandled ldtlb"); | |
50 | +#else | |
51 | + cpu_load_tlb(env); | |
52 | +#endif | |
53 | +} | |
54 | + | |
55 | +static inline void QEMU_NORETURN raise_exception(CPUSHState *env, int index, | |
56 | + uintptr_t retaddr) | |
57 | +{ | |
58 | + CPUState *cs = env_cpu(env); | |
59 | + | |
60 | + cs->exception_index = index; | |
61 | + cpu_loop_exit_restore(cs, retaddr); | |
62 | +} | |
63 | + | |
64 | +void helper_raise_illegal_instruction(CPUSHState *env) | |
65 | +{ | |
66 | + raise_exception(env, 0x180, 0); | |
67 | +} | |
68 | + | |
69 | +void helper_raise_slot_illegal_instruction(CPUSHState *env) | |
70 | +{ | |
71 | + raise_exception(env, 0x1a0, 0); | |
72 | +} | |
73 | + | |
74 | +void helper_raise_fpu_disable(CPUSHState *env) | |
75 | +{ | |
76 | + raise_exception(env, 0x800, 0); | |
77 | +} | |
78 | + | |
79 | +void helper_raise_slot_fpu_disable(CPUSHState *env) | |
80 | +{ | |
81 | + raise_exception(env, 0x820, 0); | |
82 | +} | |
83 | + | |
84 | +void helper_debug(CPUSHState *env) | |
85 | +{ | |
86 | + raise_exception(env, EXCP_DEBUG, 0); | |
87 | +} | |
88 | + | |
89 | +void helper_sleep(CPUSHState *env) | |
90 | +{ | |
91 | + CPUState *cs = env_cpu(env); | |
92 | + | |
93 | + cs->halted = 1; | |
94 | + env->in_sleep = 1; | |
95 | + raise_exception(env, EXCP_HLT, 0); | |
96 | +} | |
97 | + | |
98 | +void helper_trapa(CPUSHState *env, uint32_t tra) | |
99 | +{ | |
100 | + env->tra = tra << 2; | |
101 | + raise_exception(env, 0x160, 0); | |
102 | +} | |
103 | + | |
104 | +void helper_exclusive(CPUSHState *env) | |
105 | +{ | |
106 | + /* We do not want cpu_restore_state to run. */ | |
107 | + cpu_loop_exit_atomic(env_cpu(env), 0); | |
108 | +} | |
109 | + | |
110 | +void helper_macl(CPUSHState *env, uint32_t arg0, uint32_t arg1) | |
111 | +{ | |
112 | + env->mac += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1; | |
113 | + if (FIELD_EX32(env->sr, SR, S)) { | |
114 | + if ((int64_t)env->mac < 0) { | |
115 | + env->mac |= 0xffff000000000000; | |
116 | + } else { | |
117 | + env->mac &= 0x00007fffffffffff; | |
118 | + } | |
119 | + } | |
120 | +} | |
121 | + | |
122 | +void helper_macw(CPUSHState *env, uint32_t arg0, uint32_t arg1) | |
123 | +{ | |
124 | + env->mac += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1; | |
125 | + if (FIELD_EX32(env->sr, SR, S)) { | |
126 | + if (env->mac < -0x80000000) { | |
127 | + env->mac = 0x180000000; | |
128 | + } else if (env->mac > 0x000000007fffffff) { | |
129 | + env->mac = 0x17fffffff; | |
130 | + } | |
131 | + } | |
132 | +} | |
133 | + |
@@ -0,0 +1,1489 @@ | ||
1 | +/* | |
2 | + * SH translation | |
3 | + * | |
4 | + * Copyright (c) 2005 Samuel Tardieu | |
5 | + * Copyright (c) 2019 Yoshinori Sato | |
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 | |
10 | + * version 2.1 of the License, or (at your option) any later version. | |
11 | + * | |
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 | |
15 | + * Lesser General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU Lesser General Public | |
18 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | + */ | |
20 | + | |
21 | +#include "qemu/osdep.h" | |
22 | +#include "cpu.h" | |
23 | +#include "disas/disas.h" | |
24 | +#include "exec/exec-all.h" | |
25 | +#include "tcg-op.h" | |
26 | +#include "exec/cpu_ldst.h" | |
27 | +#include "exec/helper-proto.h" | |
28 | +#include "exec/helper-gen.h" | |
29 | +#include "exec/translator.h" | |
30 | +#include "trace-tcg.h" | |
31 | +#include "exec/log.h" | |
32 | +#include "qemu/qemu-print.h" | |
33 | + | |
34 | + | |
35 | +typedef struct DisasContext { | |
36 | + DisasContextBase base; | |
37 | + | |
38 | + uint32_t tbflags; /* should stay unmodified during the TB translation */ | |
39 | + uint32_t envflags; /* should stay in sync with env->flags using TCG ops */ | |
40 | + int memidx; | |
41 | + uint32_t delayed_pc; | |
42 | + uint32_t features; | |
43 | + int sr_rb; | |
44 | +} DisasContext; | |
45 | + | |
46 | +#if defined(CONFIG_USER_ONLY) | |
47 | +#define IS_USER(ctx) 1 | |
48 | +#else | |
49 | +#define IS_USER(ctx) (FIELD_EX32(ctx->tbflags, SR, MD) == 0) | |
50 | +#endif | |
51 | + | |
52 | +/* Target-specific values for ctx->base.is_jmp. */ | |
53 | +/* We want to exit back to the cpu loop for some reason. | |
54 | + Usually this is to recognize interrupts immediately. */ | |
55 | +#define DISAS_STOP DISAS_TARGET_0 | |
56 | + | |
57 | +/* global register indexes */ | |
58 | +static TCGv cpu_regs[32]; | |
59 | +static TCGv cpu_sr, cpu_sr_m, cpu_sr_q, cpu_sr_t; | |
60 | +static TCGv cpu_pc, cpu_ssr, cpu_spc, cpu_gbr; | |
61 | +static TCGv cpu_vbr, cpu_sgr, cpu_dbr; | |
62 | +static TCGv cpu_pr; | |
63 | +static TCGv_i64 cpu_mac; | |
64 | + | |
65 | +/* internal register indexes */ | |
66 | +static TCGv cpu_flags, cpu_delayed_pc, cpu_delayed_cond; | |
67 | + | |
68 | +#include "exec/gen-icount.h" | |
69 | + | |
70 | +void sh_translate_init(void) | |
71 | +{ | |
72 | + int i; | |
73 | + static const char * const gregnames[24] = { | |
74 | + "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0", | |
75 | + "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0", | |
76 | + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", | |
77 | + "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1", | |
78 | + "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1" | |
79 | + }; | |
80 | + /* cpu_regs[0] - cpu_regs[15] -> bank0 */ | |
81 | + /* cpu_regs[16] - cpu_regs[31] -> bank1 */ | |
82 | + for (i = 0; i < ARRAY_SIZE(gregnames); i++) { | |
83 | + cpu_regs[i] = tcg_global_mem_new_i32(cpu_env, | |
84 | + offsetof(CPUSHState, regs[i]), | |
85 | + gregnames[i]); | |
86 | + } | |
87 | + memcpy(cpu_regs + 24, cpu_regs + 8, 8 * sizeof(TCGv)); | |
88 | + | |
89 | + cpu_pc = tcg_global_mem_new_i32(cpu_env, | |
90 | + offsetof(CPUSHState, pc), "PC"); | |
91 | + cpu_sr = tcg_global_mem_new_i32(cpu_env, | |
92 | + offsetof(CPUSHState, sr), "SR"); | |
93 | + cpu_sr_m = tcg_global_mem_new_i32(cpu_env, | |
94 | + offsetof(CPUSHState, sr_m), "SR_M"); | |
95 | + cpu_sr_q = tcg_global_mem_new_i32(cpu_env, | |
96 | + offsetof(CPUSHState, sr_q), "SR_Q"); | |
97 | + cpu_sr_t = tcg_global_mem_new_i32(cpu_env, | |
98 | + offsetof(CPUSHState, sr_t), "SR_T"); | |
99 | + cpu_ssr = tcg_global_mem_new_i32(cpu_env, | |
100 | + offsetof(CPUSHState, ssr), "SSR"); | |
101 | + cpu_spc = tcg_global_mem_new_i32(cpu_env, | |
102 | + offsetof(CPUSHState, spc), "SPC"); | |
103 | + cpu_gbr = tcg_global_mem_new_i32(cpu_env, | |
104 | + offsetof(CPUSHState, gbr), "GBR"); | |
105 | + cpu_vbr = tcg_global_mem_new_i32(cpu_env, | |
106 | + offsetof(CPUSHState, vbr), "VBR"); | |
107 | + cpu_sgr = tcg_global_mem_new_i32(cpu_env, | |
108 | + offsetof(CPUSHState, sgr), "SGR"); | |
109 | + cpu_dbr = tcg_global_mem_new_i32(cpu_env, | |
110 | + offsetof(CPUSHState, dbr), "DBR"); | |
111 | + cpu_mac = tcg_global_mem_new_i64(cpu_env, | |
112 | + offsetof(CPUSHState, mac), "MAC"); | |
113 | + cpu_pr = tcg_global_mem_new_i32(cpu_env, | |
114 | + offsetof(CPUSHState, pr), "PR"); | |
115 | + cpu_flags = tcg_global_mem_new_i32(cpu_env, | |
116 | + offsetof(CPUSHState, flags), "_flags_"); | |
117 | + cpu_delayed_pc = tcg_global_mem_new_i32(cpu_env, | |
118 | + offsetof(CPUSHState, delayed_pc), | |
119 | + "_delayed_pc_"); | |
120 | + cpu_delayed_cond = tcg_global_mem_new_i32(cpu_env, | |
121 | + offsetof(CPUSHState, | |
122 | + delayed_cond), | |
123 | + "_delayed_cond_"); | |
124 | +} | |
125 | + | |
126 | +void superh_cpu_dump_state(CPUState *cs, FILE *f, int flags) | |
127 | +{ | |
128 | + SuperHCPU *cpu = SUPERH_CPU(cs); | |
129 | + CPUSHState *env = &cpu->env; | |
130 | + int i; | |
131 | + int regs; | |
132 | + | |
133 | + qemu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x\n", | |
134 | + env->pc, cpu_read_sr(env), env->pr); | |
135 | + qemu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n", | |
136 | + env->spc, env->ssr, env->gbr, env->vbr); | |
137 | + qemu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x\n", | |
138 | + env->sgr, env->dbr, env->delayed_pc); | |
139 | + regs = ((env->features & FEATURE_ISA) > 2) ? 24 : 16; | |
140 | + for (i = 0; i < regs; i += 4) { | |
141 | + qemu_printf("r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n", | |
142 | + i, env->regs[i], i + 1, env->regs[i + 1], | |
143 | + i + 2, env->regs[i + 2], i + 3, env->regs[i + 3]); | |
144 | + } | |
145 | + if (env->flags & DELAY_SLOT) { | |
146 | + qemu_printf("in delay slot (delayed_pc=0x%08x)\n", | |
147 | + env->delayed_pc); | |
148 | + } else if (env->flags & DELAY_SLOT_CONDITIONAL) { | |
149 | + qemu_printf("in conditional delay slot (delayed_pc=0x%08x)\n", | |
150 | + env->delayed_pc); | |
151 | + } else if (env->flags & DELAY_SLOT_RTE) { | |
152 | + qemu_fprintf(f, "in rte delay slot (delayed_pc=0x%08x)\n", | |
153 | + env->delayed_pc); | |
154 | + } | |
155 | +} | |
156 | + | |
157 | +static inline void gen_save_cpu_state(DisasContext *ctx, bool save_pc) | |
158 | +{ | |
159 | + if (save_pc) { | |
160 | + tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); | |
161 | + } | |
162 | + if (ctx->delayed_pc != (uint32_t) -1) { | |
163 | + tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc); | |
164 | + } | |
165 | + tcg_gen_movi_i32(cpu_flags, ctx->envflags); | |
166 | +} | |
167 | + | |
168 | +static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) | |
169 | +{ | |
170 | + /* Use a direct jump if in same page and singlestep not enabled */ | |
171 | + if (unlikely(ctx->base.singlestep_enabled)) { | |
172 | + return false; | |
173 | + } | |
174 | + return true; | |
175 | +} | |
176 | + | |
177 | +static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) | |
178 | +{ | |
179 | + tcg_gen_movi_i32(cpu_pc, dest); | |
180 | + if (ctx->base.singlestep_enabled) { | |
181 | + gen_helper_debug(cpu_env); | |
182 | + } else { | |
183 | + tcg_gen_lookup_and_goto_ptr(); | |
184 | + } | |
185 | + ctx->base.is_jmp = DISAS_NORETURN; | |
186 | +} | |
187 | + | |
188 | +static void gen_jump(DisasContext * ctx) | |
189 | +{ | |
190 | + if (ctx->delayed_pc == -1) { | |
191 | + /* Target is not statically known, it comes necessarily from a | |
192 | + delayed jump as immediate jump are conditinal jumps */ | |
193 | + tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc); | |
194 | + tcg_gen_discard_i32(cpu_delayed_pc); | |
195 | + if (ctx->base.singlestep_enabled) { | |
196 | + gen_helper_debug(cpu_env); | |
197 | + } else { | |
198 | + tcg_gen_lookup_and_goto_ptr(); | |
199 | + } | |
200 | + ctx->base.is_jmp = DISAS_NORETURN; | |
201 | + } else { | |
202 | + gen_goto_tb(ctx, 0, ctx->delayed_pc); | |
203 | + } | |
204 | +} | |
205 | + | |
206 | +/* Immediate conditional jump (bt or bf) */ | |
207 | +static void gen_conditional_jump(DisasContext *ctx, target_ulong dest, | |
208 | + bool jump_if_false) | |
209 | +{ | |
210 | + TCGLabel *l1 = gen_new_label(); | |
211 | + TCGCond cond_not_taken = jump_if_false ? TCG_COND_NE : TCG_COND_EQ; | |
212 | + | |
213 | + gen_save_cpu_state(ctx, false); | |
214 | + tcg_gen_brcondi_i32(cond_not_taken, cpu_sr_t, 0, l1); | |
215 | + gen_goto_tb(ctx, 0, dest); | |
216 | + gen_set_label(l1); | |
217 | + gen_goto_tb(ctx, 1, ctx->base.pc_next); | |
218 | + ctx->base.is_jmp = DISAS_NORETURN; | |
219 | +} | |
220 | + | |
221 | +/* Delayed conditional jump (bt or bf) */ | |
222 | +static void gen_delayed_conditional_jump(DisasContext * ctx) | |
223 | +{ | |
224 | + TCGLabel *l1 = gen_new_label(); | |
225 | + TCGv ds = tcg_temp_new(); | |
226 | + | |
227 | + tcg_gen_mov_i32(ds, cpu_delayed_cond); | |
228 | + tcg_gen_discard_i32(cpu_delayed_cond); | |
229 | + | |
230 | + tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1); | |
231 | + gen_goto_tb(ctx, 1, ctx->base.pc_next); | |
232 | + gen_set_label(l1); | |
233 | + gen_jump(ctx); | |
234 | +} | |
235 | + | |
236 | +static void gen_write_sr(TCGv val) | |
237 | +{ | |
238 | + tcg_gen_mov_i32(cpu_sr, val); | |
239 | + tcg_gen_extract_i32(cpu_sr_t, val, R_SR_T_SHIFT, 1); | |
240 | + tcg_gen_extract_i32(cpu_sr_q, val, R_SR_Q_SHIFT, 1); | |
241 | + tcg_gen_extract_i32(cpu_sr_m, val, R_SR_M_SHIFT, 1); | |
242 | +} | |
243 | + | |
244 | +static void gen_read_sr(TCGv ret) | |
245 | +{ | |
246 | + tcg_gen_mov_i32(ret, cpu_sr); | |
247 | + tcg_gen_deposit_i32(ret, ret, cpu_sr_t, R_SR_T_SHIFT, 1); | |
248 | + tcg_gen_deposit_i32(ret, ret, cpu_sr_q, R_SR_Q_SHIFT, 1); | |
249 | + tcg_gen_deposit_i32(ret, ret, cpu_sr_m, R_SR_M_SHIFT, 1); | |
250 | +} | |
251 | + | |
252 | +/* Include the auto-generated decoder. */ | |
253 | +#include "decode.inc.c" | |
254 | + | |
255 | +#define REG(ctx, rn) \ | |
256 | + (FIELD_EX32(ctx->base.tb->flags, SR, RB)) ? (rn + 16) : rn | |
257 | + | |
258 | +#define CHECK_NOT_DELAY_SLOT(ctx) \ | |
259 | + if (ctx->envflags & DELAY_SLOT_MASK) { \ | |
260 | + gen_save_cpu_state(ctx, true); \ | |
261 | + gen_helper_raise_slot_illegal_instruction(cpu_env); \ | |
262 | + } | |
263 | + | |
264 | +#define CHECK_PRIVILEGED(ctx) \ | |
265 | + if (IS_USER(ctx)) { \ | |
266 | + gen_save_cpu_state(ctx, true); \ | |
267 | + if (ctx->envflags & DELAY_SLOT_MASK) { \ | |
268 | + gen_helper_raise_slot_illegal_instruction(cpu_env); \ | |
269 | + } else { \ | |
270 | + gen_helper_raise_illegal_instruction(cpu_env); \ | |
271 | + } \ | |
272 | + } | |
273 | + | |
274 | +#define ISA(ctx) (ctx->features & FEATURE_ISA) | |
275 | +#define IS_SH2(ctx) (ISA(ctx) == 2) | |
276 | +#define R_SP 15 | |
277 | + | |
278 | +static bool trans_MOV_ir(DisasContext *ctx, arg_MOV_ir *a) | |
279 | +{ | |
280 | + tcg_gen_movi_i32(cpu_regs[REG(ctx, a->rn)], a->imm); | |
281 | + return true; | |
282 | +} | |
283 | + | |
284 | +static bool trans_MOV_pc_r(DisasContext *ctx, arg_MOV_pc_r *a) | |
285 | +{ | |
286 | + uint32_t pc_mask = ~((1 << a->sz) - 1); | |
287 | + TCGv addr = tcg_const_i32((a->dsp << a->sz) + | |
288 | + ((ctx->base.pc_next + 2) & pc_mask)); | |
289 | + tcg_gen_qemu_ld_i32(cpu_regs[REG(ctx, a->rn)], addr, | |
290 | + ctx->memidx, MO_SIGN | MO_TE | a->sz); | |
291 | + tcg_temp_free(addr); | |
292 | + return true; | |
293 | +} | |
294 | + | |
295 | +static bool trans_MOV_rr(DisasContext *ctx, arg_MOV_rr *a) | |
296 | +{ | |
297 | + tcg_gen_mov_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
298 | + return true; | |
299 | +} | |
300 | + | |
301 | +static bool trans_MOV_mr(DisasContext *ctx, arg_MOV_mr *a) | |
302 | +{ | |
303 | + tcg_gen_qemu_ld_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)], | |
304 | + ctx->memidx, MO_SIGN | MO_TE | a->sz); | |
305 | + return true; | |
306 | +} | |
307 | + | |
308 | +static bool trans_MOV_rm(DisasContext *ctx, arg_MOV_rm *a) | |
309 | +{ | |
310 | + tcg_gen_qemu_st_i32(cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, a->rn)], | |
311 | + ctx->memidx, MO_TE | a->sz); | |
312 | + return true; | |
313 | +} | |
314 | + | |
315 | +static bool trans_MOV_rmd(DisasContext *ctx, arg_MOV_rmd *a) | |
316 | +{ | |
317 | + TCGv addr = tcg_temp_new(); | |
318 | + tcg_gen_subi_i32(addr, cpu_regs[REG(ctx, a->rn)], 1 << a->sz); | |
319 | + tcg_gen_qemu_st_i32(cpu_regs[REG(ctx, a->rm)], addr, | |
320 | + ctx->memidx, MO_TE | a->sz); | |
321 | + tcg_gen_mov_i32(cpu_regs[REG(ctx, a->rn)], addr); | |
322 | + tcg_temp_free(addr); | |
323 | + return true; | |
324 | +} | |
325 | + | |
326 | +static bool trans_MOV_mir(DisasContext *ctx, arg_MOV_mir *a) | |
327 | +{ | |
328 | + tcg_gen_qemu_ld_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)], | |
329 | + ctx->memidx, MO_SIGN | MO_TE | a->sz); | |
330 | + if (a->rm != a->rn) { | |
331 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rm)], | |
332 | + cpu_regs[REG(ctx, a->rm)], 1 << a->sz); | |
333 | + } | |
334 | + return true; | |
335 | +} | |
336 | + | |
337 | +static bool trans_MOV_rm_rn_dsp(DisasContext *ctx, arg_MOV_rm_rn_dsp *a) | |
338 | +{ | |
339 | + TCGv addr; | |
340 | + addr = tcg_temp_new(); | |
341 | + tcg_gen_addi_i32(addr, cpu_regs[REG(ctx, a->rn)], a->dsp << a->sz); | |
342 | + tcg_gen_qemu_st_i32(cpu_regs[REG(ctx, a->rm)], addr, | |
343 | + ctx->memidx, MO_TE | a->sz); | |
344 | + tcg_temp_free(addr); | |
345 | + return true; | |
346 | +} | |
347 | + | |
348 | +static bool trans_MOV_rm_dsp_rn(DisasContext *ctx, arg_MOV_rm_dsp_rn *a) | |
349 | +{ | |
350 | + TCGv addr; | |
351 | + addr = tcg_temp_new(); | |
352 | + tcg_gen_addi_i32(addr, cpu_regs[REG(ctx, a->rm)], a->dsp << a->sz); | |
353 | + tcg_gen_qemu_ld_i32(cpu_regs[REG(ctx, a->rn)], addr, | |
354 | + ctx->memidx, MO_SIGN | MO_TE | a->sz); | |
355 | + tcg_temp_free(addr); | |
356 | + return true; | |
357 | +} | |
358 | + | |
359 | +static bool trans_MOV_rm_r0_rn(DisasContext *ctx, arg_MOV_rm_r0_rn *a) | |
360 | +{ | |
361 | + TCGv addr; | |
362 | + addr = tcg_temp_new(); | |
363 | + tcg_gen_add_i32(addr, cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, 0)]); | |
364 | + tcg_gen_qemu_st_i32(cpu_regs[REG(ctx, a->rm)], addr, | |
365 | + ctx->memidx, MO_TE | a->sz); | |
366 | + tcg_temp_free(addr); | |
367 | + return true; | |
368 | +} | |
369 | + | |
370 | +static bool trans_MOV_r0_rm_rn(DisasContext *ctx, arg_MOV_r0_rm_rn *a) | |
371 | +{ | |
372 | + TCGv addr; | |
373 | + addr = tcg_temp_new(); | |
374 | + tcg_gen_add_i32(addr, cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, 0)]); | |
375 | + tcg_gen_qemu_ld_i32(cpu_regs[REG(ctx, a->rn)], addr, | |
376 | + ctx->memidx, MO_SIGN | MO_TE | a->sz); | |
377 | + tcg_temp_free(addr); | |
378 | + return true; | |
379 | +} | |
380 | + | |
381 | +static bool trans_MOV_r0_dsp_gbr(DisasContext *ctx, arg_MOV_r0_dsp_gbr *a) | |
382 | +{ | |
383 | + TCGv addr; | |
384 | + addr = tcg_temp_new(); | |
385 | + tcg_gen_addi_i32(addr, cpu_gbr, a->dsp << a->sz); | |
386 | + tcg_gen_qemu_st_i32(cpu_regs[REG(ctx, 0)], addr, | |
387 | + ctx->memidx, MO_TE | a->sz); | |
388 | + tcg_temp_free(addr); | |
389 | + return true; | |
390 | +} | |
391 | + | |
392 | +static bool trans_MOV_dsp_gbr_r0(DisasContext *ctx, arg_MOV_r0_dsp_gbr *a) | |
393 | +{ | |
394 | + TCGv addr; | |
395 | + addr = tcg_temp_new(); | |
396 | + tcg_gen_addi_i32(addr, cpu_gbr, a->dsp << a->sz); | |
397 | + tcg_gen_qemu_ld_i32(cpu_regs[REG(ctx, 0)], addr, | |
398 | + ctx->memidx, MO_SIGN | MO_TE | a->sz); | |
399 | + tcg_temp_free(addr); | |
400 | + return true; | |
401 | +} | |
402 | + | |
403 | +static bool trans_MOVA(DisasContext *ctx, arg_MOVA *a) | |
404 | +{ | |
405 | + uint32_t pc; | |
406 | + if (ctx->envflags & DELAY_SLOT_MASK) { | |
407 | + pc = ctx->delayed_pc + 2; | |
408 | + } else { | |
409 | + pc= ctx->base.pc_next + 2; | |
410 | + } | |
411 | + tcg_gen_movi_i32(cpu_regs[REG(ctx, 0)], | |
412 | + ((pc & 0xfffffffc)+ a->dsp * 4)); | |
413 | + return true; | |
414 | +} | |
415 | + | |
416 | +static bool trans_MOVT(DisasContext *ctx, arg_MOVT *a) | |
417 | +{ | |
418 | + tcg_gen_mov_i32(cpu_regs[REG(ctx, a->rn)], cpu_sr_t); | |
419 | + return true; | |
420 | +} | |
421 | + | |
422 | +static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) | |
423 | +{ | |
424 | + TCGv temp = tcg_temp_new(); | |
425 | + switch (a->sz) { | |
426 | + case 0: /* Byte */ | |
427 | + tcg_gen_ext16u_i32(temp, cpu_regs[REG(ctx, a->rm)]); | |
428 | + tcg_gen_bswap16_i32(temp, temp); | |
429 | + tcg_gen_deposit_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)], | |
430 | + temp, 0, 16); | |
431 | + break; | |
432 | + case 1: /* Word */ | |
433 | + tcg_gen_rotli_i32(cpu_regs[REG(ctx, a->rn)], | |
434 | + cpu_regs[REG(ctx, a->rm)], 16); | |
435 | + break; | |
436 | + default: | |
437 | + g_assert_not_reached(); | |
438 | + } | |
439 | + tcg_temp_free(temp); | |
440 | + return true; | |
441 | +} | |
442 | + | |
443 | +static bool trans_XTRACT(DisasContext *ctx, arg_XTRACT *a) | |
444 | +{ | |
445 | + tcg_gen_shri_i32(cpu_regs[REG(ctx, a->rn)], | |
446 | + cpu_regs[REG(ctx, a->rn)], 16); | |
447 | + tcg_gen_deposit_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], | |
448 | + cpu_regs[REG(ctx, a->rm)], 16, 16); | |
449 | + return true; | |
450 | +} | |
451 | + | |
452 | +static bool trans_ADD_rr(DisasContext *ctx, arg_ADD_rr *a) | |
453 | +{ | |
454 | + tcg_gen_add_i32(cpu_regs[REG(ctx, a->rn)], | |
455 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
456 | + return true; | |
457 | +} | |
458 | + | |
459 | +static bool trans_ADD_ir(DisasContext *ctx, arg_ADD_ir *a) | |
460 | +{ | |
461 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rn)], | |
462 | + cpu_regs[REG(ctx, a->rn)], a->imm); | |
463 | + return true; | |
464 | +} | |
465 | + | |
466 | +static bool trans_ADDC(DisasContext *ctx, arg_ADDC *a) | |
467 | +{ | |
468 | + TCGv z = tcg_const_i32(0); | |
469 | + tcg_gen_add2_i32(cpu_regs[REG(ctx, a->rn)], cpu_sr_t, | |
470 | + cpu_regs[REG(ctx, a->rn)], z, | |
471 | + cpu_sr_t, z); | |
472 | + tcg_gen_add2_i32(cpu_regs[REG(ctx, a->rn)], cpu_sr_t, | |
473 | + cpu_regs[REG(ctx, a->rn)], cpu_sr_t, | |
474 | + cpu_regs[REG(ctx, a->rm)], z); | |
475 | + tcg_temp_free(z); | |
476 | + return true; | |
477 | +} | |
478 | + | |
479 | +static bool trans_ADDV(DisasContext *ctx, arg_ADDV *a) | |
480 | +{ | |
481 | + tcg_gen_add_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
482 | + tcg_gen_xor_i32(cpu_sr_t, cpu_sr_t, cpu_regs[REG(ctx, a->rn)]); | |
483 | + tcg_gen_shri_i32(cpu_sr_t, cpu_sr_t, 31); | |
484 | + tcg_gen_add_i32(cpu_regs[REG(ctx, a->rn)], | |
485 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
486 | + return true; | |
487 | +} | |
488 | + | |
489 | +static bool trans_SUB(DisasContext *ctx, arg_SUB *a) | |
490 | +{ | |
491 | + tcg_gen_sub_i32(cpu_regs[REG(ctx, a->rn)], | |
492 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
493 | + return true; | |
494 | +} | |
495 | + | |
496 | +static bool trans_SUBC(DisasContext *ctx, arg_SUBC *a) | |
497 | +{ | |
498 | + TCGv t0, t1; | |
499 | + t0 = tcg_const_i32(0); | |
500 | + t1 = tcg_temp_new(); | |
501 | + tcg_gen_add2_i32(t1, cpu_sr_t, cpu_sr_t, t0, cpu_regs[REG(ctx, a->rm)], t0); | |
502 | + tcg_gen_sub2_i32(cpu_regs[REG(ctx, a->rn)], cpu_sr_t, | |
503 | + cpu_regs[REG(ctx, a->rn)], t0, t1, cpu_sr_t); | |
504 | + tcg_gen_andi_i32(cpu_sr_t, cpu_sr_t, 1); | |
505 | + tcg_temp_free(t0); | |
506 | + tcg_temp_free(t1); | |
507 | + return true; | |
508 | +} | |
509 | + | |
510 | +static bool trans_SUBV(DisasContext *ctx, arg_SUBV *a) | |
511 | +{ | |
512 | + tcg_gen_sub_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
513 | + tcg_gen_xor_i32(cpu_sr_t, cpu_sr_t, cpu_regs[REG(ctx, a->rn)]); | |
514 | + tcg_gen_shri_i32(cpu_sr_t, cpu_sr_t, 31); | |
515 | + tcg_gen_sub_i32(cpu_regs[REG(ctx, a->rn)], | |
516 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
517 | + return true; | |
518 | +} | |
519 | + | |
520 | +static bool trans_CMP_cd(DisasContext *ctx, arg_CMP_cd *a) | |
521 | +{ | |
522 | + TCGCond cond; | |
523 | + bool cmpz = false; | |
524 | + switch(a->cd) { | |
525 | + case 0: /* EQ */ | |
526 | + cond = TCG_COND_EQ; | |
527 | + break; | |
528 | + case 3: /* GE */ | |
529 | + cond = TCG_COND_GE; | |
530 | + break; | |
531 | + case 7: /* GT */ | |
532 | + cond = TCG_COND_GT; | |
533 | + break; | |
534 | + case 6: /* HI */ | |
535 | + cond = TCG_COND_GTU; | |
536 | + break; | |
537 | + case 2: /* HS */ | |
538 | + cond = TCG_COND_GEU; | |
539 | + break; | |
540 | + case 5: /* PL */ | |
541 | + cond = TCG_COND_GT; | |
542 | + cmpz = true; | |
543 | + break; | |
544 | + case 1: /* PZ */ | |
545 | + cond = TCG_COND_GE; | |
546 | + cmpz = true; | |
547 | + break; | |
548 | + case 12: { /* STR */ | |
549 | + TCGv cmp1 = tcg_temp_new(); | |
550 | + TCGv cmp2 = tcg_temp_new(); | |
551 | + tcg_gen_xor_i32(cmp2, cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, a->rn)]); | |
552 | + tcg_gen_subi_i32(cmp1, cmp2, 0x01010101); | |
553 | + tcg_gen_andc_i32(cmp1, cmp1, cmp2); | |
554 | + tcg_gen_andi_i32(cmp1, cmp1, 0x80808080); | |
555 | + tcg_gen_setcondi_i32(TCG_COND_NE, cpu_sr_t, cmp1, 0); | |
556 | + tcg_temp_free(cmp2); | |
557 | + tcg_temp_free(cmp1); | |
558 | + return true; | |
559 | + } | |
560 | + default: | |
561 | + g_assert_not_reached(); | |
562 | + } | |
563 | + if (cmpz) { | |
564 | + tcg_gen_setcondi_i32(cond, cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 0); | |
565 | + } else { | |
566 | + tcg_gen_setcond_i32(cond, cpu_sr_t, | |
567 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
568 | + } | |
569 | + return true; | |
570 | +} | |
571 | + | |
572 | +static bool trans_CMP_eq(DisasContext *ctx, arg_CMP_eq *a) | |
573 | +{ | |
574 | + tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, | |
575 | + cpu_regs[REG(ctx, 0)], a->imm); | |
576 | + return true; | |
577 | +} | |
578 | + | |
579 | +static bool trans_DIV0S(DisasContext *ctx, arg_DIV0S *a) | |
580 | +{ | |
581 | + tcg_gen_shri_i32(cpu_sr_q, cpu_regs[REG(ctx, a->rn)], 31); | |
582 | + tcg_gen_shri_i32(cpu_sr_m, cpu_regs[REG(ctx, a->rm)], 31); | |
583 | + tcg_gen_xor_i32(cpu_sr_t, cpu_sr_q, cpu_sr_m); | |
584 | + return true; | |
585 | +} | |
586 | + | |
587 | +static bool trans_DIV0U(DisasContext *ctx, arg_DIV0U *a) | |
588 | +{ | |
589 | + TCGv z = tcg_const_i32(0); | |
590 | + tcg_gen_mov_i32(cpu_sr_t, z); | |
591 | + tcg_gen_mov_i32(cpu_sr_m, z); | |
592 | + tcg_gen_mov_i32(cpu_sr_q, z); | |
593 | + return true; | |
594 | +} | |
595 | + | |
596 | +static bool trans_DIV1(DisasContext *ctx, arg_DIV1 *a) | |
597 | +{ | |
598 | + TCGv t0 = tcg_temp_new(); | |
599 | + TCGv t1 = tcg_temp_new(); | |
600 | + TCGv t2 = tcg_temp_new(); | |
601 | + TCGv zero = tcg_const_i32(0); | |
602 | + | |
603 | + /* shift left arg1, saving the bit being pushed out and inserting | |
604 | + T on the right */ | |
605 | + tcg_gen_shri_i32(t0, cpu_regs[REG(ctx, a->rn)], 31); | |
606 | + tcg_gen_shli_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
607 | + tcg_gen_or_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], cpu_sr_t); | |
608 | + | |
609 | + /* Add or subtract arg0 from arg1 depending if Q == M. To avoid | |
610 | + using 64-bit temps, we compute arg0's high part from q ^ m, so | |
611 | + that it is 0x00000000 when adding the value or 0xffffffff when | |
612 | + subtracting it. */ | |
613 | + tcg_gen_xor_i32(t1, cpu_sr_q, cpu_sr_m); | |
614 | + tcg_gen_subi_i32(t1, t1, 1); | |
615 | + tcg_gen_neg_i32(t2, cpu_regs[REG(ctx, a->rm)]); | |
616 | + tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, zero, cpu_regs[REG(ctx, a->rm)], t2); | |
617 | + tcg_gen_add2_i32(cpu_regs[REG(ctx, a->rn)], t1, | |
618 | + cpu_regs[REG(ctx, a->rn)], zero, t2, t1); | |
619 | + | |
620 | + /* compute T and Q depending on carry */ | |
621 | + tcg_gen_andi_i32(t1, t1, 1); | |
622 | + tcg_gen_xor_i32(t1, t1, t0); | |
623 | + tcg_gen_xori_i32(cpu_sr_t, t1, 1); | |
624 | + tcg_gen_xor_i32(cpu_sr_q, cpu_sr_m, t1); | |
625 | + | |
626 | + tcg_temp_free(zero); | |
627 | + tcg_temp_free(t2); | |
628 | + tcg_temp_free(t1); | |
629 | + tcg_temp_free(t0); | |
630 | + return true; | |
631 | +} | |
632 | + | |
633 | +static bool trans_DT(DisasContext *ctx, arg_DT *a) | |
634 | +{ | |
635 | + tcg_gen_subi_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
636 | + tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 0); | |
637 | + return true; | |
638 | +} | |
639 | + | |
640 | +static bool trans_EXTS(DisasContext *ctx, arg_EXTS *a) | |
641 | +{ | |
642 | + switch(a->sz) { | |
643 | + case 0: | |
644 | + tcg_gen_ext8s_i32(cpu_regs[REG(ctx, a->rn)], | |
645 | + cpu_regs[REG(ctx, a->rm)]); | |
646 | + break; | |
647 | + case 1: | |
648 | + tcg_gen_ext16s_i32(cpu_regs[REG(ctx, a->rn)], | |
649 | + cpu_regs[REG(ctx, a->rm)]); | |
650 | + break; | |
651 | + } | |
652 | + return true; | |
653 | +} | |
654 | + | |
655 | +static bool trans_EXTU(DisasContext *ctx, arg_EXTS *a) | |
656 | +{ | |
657 | + switch(a->sz) { | |
658 | + case 0: | |
659 | + tcg_gen_ext8u_i32(cpu_regs[REG(ctx, a->rn)], | |
660 | + cpu_regs[REG(ctx, a->rm)]); | |
661 | + break; | |
662 | + case 1: | |
663 | + tcg_gen_ext16u_i32(cpu_regs[REG(ctx, a->rn)], | |
664 | + cpu_regs[REG(ctx, a->rm)]); | |
665 | + break; | |
666 | + } | |
667 | + return true; | |
668 | +} | |
669 | + | |
670 | +static bool trans_MULS(DisasContext *ctx, arg_MULS *a) | |
671 | +{ | |
672 | + TCGv arg1 = tcg_temp_new(); | |
673 | + TCGv arg2 = tcg_temp_new(); | |
674 | + TCGv_i64 low64 = tcg_temp_new_i64(); | |
675 | + tcg_gen_ext16s_i32(arg1, cpu_regs[REG(ctx, a->rm)]); | |
676 | + tcg_gen_ext16s_i32(arg2, cpu_regs[REG(ctx, a->rn)]); | |
677 | + tcg_gen_mul_i32(arg1, arg1, arg2); | |
678 | + tcg_gen_extu_i32_i64(low64, arg2); | |
679 | + tcg_gen_deposit_i64(cpu_mac, cpu_mac, low64, 0, 32); | |
680 | + tcg_temp_free(arg1); | |
681 | + tcg_temp_free(arg2); | |
682 | + tcg_temp_free_i64(low64); | |
683 | + return true; | |
684 | +} | |
685 | + | |
686 | +static bool trans_MULU(DisasContext *ctx, arg_MULU *a) | |
687 | +{ | |
688 | + TCGv arg1 = tcg_temp_new(); | |
689 | + TCGv arg2 = tcg_temp_new(); | |
690 | + TCGv_i64 low64 = tcg_temp_new_i64(); | |
691 | + tcg_gen_ext16u_i32(arg1, cpu_regs[REG(ctx, a->rm)]); | |
692 | + tcg_gen_ext16u_i32(arg2, cpu_regs[REG(ctx, a->rn)]); | |
693 | + tcg_gen_mul_i32(arg1, arg1, arg2); | |
694 | + tcg_gen_extu_i32_i64(low64, arg2); | |
695 | + tcg_gen_deposit_i64(cpu_mac, cpu_mac, low64, 0, 32); | |
696 | + tcg_temp_free(arg1); | |
697 | + tcg_temp_free(arg2); | |
698 | + tcg_temp_free_i64(low64); | |
699 | + return true; | |
700 | +} | |
701 | + | |
702 | +static bool trans_DMULS(DisasContext *ctx, arg_DMULS *a) | |
703 | +{ | |
704 | + TCGv_i64 arg1 = tcg_temp_new_i64(); | |
705 | + TCGv_i64 arg2 = tcg_temp_new_i64(); | |
706 | + tcg_gen_ext_i32_i64(arg1, cpu_regs[REG(ctx, a->rm)]); | |
707 | + tcg_gen_ext_i32_i64(arg2, cpu_regs[REG(ctx, a->rn)]); | |
708 | + tcg_gen_mul_i64(cpu_mac, arg1, arg2); | |
709 | + tcg_temp_free_i64(arg1); | |
710 | + tcg_temp_free_i64(arg2); | |
711 | + return true; | |
712 | +} | |
713 | + | |
714 | +static bool trans_DMULU(DisasContext *ctx, arg_DMULU *a) | |
715 | +{ | |
716 | + TCGv_i64 arg1 = tcg_temp_new_i64(); | |
717 | + TCGv_i64 arg2 = tcg_temp_new_i64(); | |
718 | + tcg_gen_extu_i32_i64(arg1, cpu_regs[REG(ctx, a->rm)]); | |
719 | + tcg_gen_extu_i32_i64(arg2, cpu_regs[REG(ctx, a->rn)]); | |
720 | + tcg_gen_mul_i64(cpu_mac, arg1, arg2); | |
721 | + tcg_temp_free_i64(arg1); | |
722 | + tcg_temp_free_i64(arg2); | |
723 | + return true; | |
724 | +} | |
725 | + | |
726 | +static bool trans_MUL(DisasContext *ctx, arg_MUL *a) | |
727 | +{ | |
728 | + TCGv low = tcg_temp_new(); | |
729 | + TCGv_i64 low64 = tcg_temp_new_i64(); | |
730 | + tcg_gen_mul_i32(low, cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, a->rn)]); | |
731 | + tcg_gen_extu_i32_i64(low64, low); | |
732 | + tcg_gen_deposit_i64(cpu_mac, cpu_mac, low64, 0, 32); | |
733 | + tcg_temp_free(low); | |
734 | + tcg_temp_free_i64(low64); | |
735 | + return true; | |
736 | +} | |
737 | + | |
738 | +static bool trans_MACL(DisasContext *ctx, arg_MACL *a) | |
739 | +{ | |
740 | + TCGv arg0, arg1; | |
741 | + arg0 = tcg_temp_new(); | |
742 | + tcg_gen_qemu_ld_i32(arg0, cpu_regs[REG(ctx, a->rm)], | |
743 | + ctx->memidx, MO_TE | MO_32); | |
744 | + arg1 = tcg_temp_new(); | |
745 | + tcg_gen_qemu_ld_i32(arg1, cpu_regs[REG(ctx, a->rn)], | |
746 | + ctx->memidx, MO_TE | MO_32); | |
747 | + gen_helper_macl(cpu_env, arg0, arg1); | |
748 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, a->rm)], 4); | |
749 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 4); | |
750 | + tcg_temp_free(arg1); | |
751 | + tcg_temp_free(arg0); | |
752 | + return true; | |
753 | +} | |
754 | + | |
755 | +static bool trans_MACW(DisasContext *ctx, arg_MACW *a) | |
756 | +{ | |
757 | + TCGv arg0, arg1; | |
758 | + arg0 = tcg_temp_new(); | |
759 | + tcg_gen_qemu_ld_i32(arg0, cpu_regs[REG(ctx, a->rm)], | |
760 | + ctx->memidx, MO_TE | MO_16); | |
761 | + arg1 = tcg_temp_new(); | |
762 | + tcg_gen_qemu_ld_i32(arg1, cpu_regs[REG(ctx, a->rn)], | |
763 | + ctx->memidx, MO_TE | MO_16); | |
764 | + gen_helper_macw(cpu_env, arg0, arg1); | |
765 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, a->rm)], 2); | |
766 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 2); | |
767 | + tcg_temp_free(arg1); | |
768 | + tcg_temp_free(arg0); | |
769 | + return true; | |
770 | +} | |
771 | + | |
772 | +static bool trans_NEG(DisasContext *ctx, arg_NEG *a) | |
773 | +{ | |
774 | + tcg_gen_neg_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
775 | + return true; | |
776 | +} | |
777 | + | |
778 | +static bool trans_NEGC(DisasContext *ctx, arg_NEG *a) | |
779 | +{ | |
780 | + TCGv z = tcg_const_i32(0); | |
781 | + tcg_gen_add2_i32(cpu_regs[REG(ctx, a->rn)], cpu_sr_t, | |
782 | + cpu_regs[REG(ctx, a->rm)], z, cpu_sr_t, z); | |
783 | + tcg_gen_sub2_i32(cpu_regs[REG(ctx, a->rn)], cpu_sr_t, | |
784 | + z, z, cpu_regs[REG(ctx, a->rn)], cpu_sr_t); | |
785 | + tcg_gen_andi_i32(cpu_sr_t, cpu_sr_t, 1); | |
786 | + tcg_temp_free(z); | |
787 | + return true; | |
788 | +} | |
789 | + | |
790 | +static bool trans_AND_rr(DisasContext *ctx, arg_AND_rr *a) | |
791 | +{ | |
792 | + tcg_gen_and_i32(cpu_regs[REG(ctx, a->rn)], | |
793 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
794 | + return true; | |
795 | +} | |
796 | + | |
797 | +static bool trans_AND_ir(DisasContext *ctx, arg_AND_ir *a) | |
798 | +{ | |
799 | + tcg_gen_andi_i32(cpu_regs[REG(ctx, 0)], | |
800 | + cpu_regs[REG(ctx, 0)], a->imm); | |
801 | + return true; | |
802 | +} | |
803 | + | |
804 | +static bool trans_AND_im(DisasContext *ctx, arg_AND_im *a) | |
805 | +{ | |
806 | + TCGv val = tcg_temp_new(); | |
807 | + TCGv addr = tcg_temp_new(); | |
808 | + tcg_gen_add_i32(addr, cpu_regs[REG(ctx, 0)], cpu_gbr); | |
809 | + tcg_gen_qemu_ld_i32(val, addr, | |
810 | + ctx->memidx, MO_TE | MO_8); | |
811 | + tcg_gen_andi_i32(val, val, a->imm); | |
812 | + tcg_gen_qemu_st_i32(val, addr, | |
813 | + ctx->memidx, MO_TE | MO_8); | |
814 | + tcg_temp_free(val); | |
815 | + tcg_temp_free(addr); | |
816 | + return true; | |
817 | +} | |
818 | + | |
819 | +static bool trans_OR_rr(DisasContext *ctx, arg_OR_rr *a) | |
820 | +{ | |
821 | + tcg_gen_or_i32(cpu_regs[REG(ctx, a->rn)], | |
822 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
823 | + return true; | |
824 | +} | |
825 | + | |
826 | +static bool trans_OR_ir(DisasContext *ctx, arg_OR_ir *a) | |
827 | +{ | |
828 | + tcg_gen_ori_i32(cpu_regs[REG(ctx, 0)], | |
829 | + cpu_regs[REG(ctx, 0)], a->imm); | |
830 | + return true; | |
831 | +} | |
832 | + | |
833 | +static bool trans_OR_im(DisasContext *ctx, arg_OR_im *a) | |
834 | +{ | |
835 | + TCGv val = tcg_temp_new(); | |
836 | + TCGv addr = tcg_temp_new(); | |
837 | + tcg_gen_add_i32(addr, cpu_regs[REG(ctx, 0)], cpu_gbr); | |
838 | + tcg_gen_qemu_ld_i32(val, addr, | |
839 | + ctx->memidx, MO_TE | MO_8); | |
840 | + tcg_gen_ori_i32(val, val, a->imm); | |
841 | + tcg_gen_qemu_st_i32(val, addr, | |
842 | + ctx->memidx, MO_TE | MO_8); | |
843 | + tcg_temp_free(val); | |
844 | + tcg_temp_free(addr); | |
845 | + return true; | |
846 | +} | |
847 | + | |
848 | +static bool trans_TST_rr(DisasContext *ctx, arg_TST_rr *a) | |
849 | +{ | |
850 | + TCGv temp = tcg_temp_new(); | |
851 | + tcg_gen_and_i32(temp, | |
852 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
853 | + tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, temp, 0); | |
854 | + tcg_temp_free(temp); | |
855 | + return true; | |
856 | +} | |
857 | + | |
858 | +static bool trans_TST_ir(DisasContext *ctx, arg_TST_ir *a) | |
859 | +{ | |
860 | + TCGv temp = tcg_temp_new(); | |
861 | + tcg_gen_andi_i32(temp, | |
862 | + cpu_regs[REG(ctx, 0)], a->imm); | |
863 | + tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, temp, 0); | |
864 | + tcg_temp_free(temp); | |
865 | + return true; | |
866 | +} | |
867 | + | |
868 | +static bool trans_TST_im(DisasContext *ctx, arg_TST_im *a) | |
869 | +{ | |
870 | + TCGv val = tcg_temp_new(); | |
871 | + TCGv addr = tcg_temp_new(); | |
872 | + tcg_gen_add_i32(addr, cpu_regs[REG(ctx, 0)], cpu_gbr); | |
873 | + tcg_gen_qemu_ld_i32(val, addr, | |
874 | + ctx->memidx, MO_TE | MO_8); | |
875 | + tcg_gen_andi_i32(val, val, a->imm); | |
876 | + tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0); | |
877 | + tcg_temp_free(val); | |
878 | + tcg_temp_free(addr); | |
879 | + return true; | |
880 | +} | |
881 | + | |
882 | +static bool trans_XOR_rr(DisasContext *ctx, arg_XOR_rr *a) | |
883 | +{ | |
884 | + tcg_gen_xor_i32(cpu_regs[REG(ctx, a->rn)], | |
885 | + cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
886 | + return true; | |
887 | +} | |
888 | + | |
889 | +static bool trans_XOR_ir(DisasContext *ctx, arg_XOR_ir *a) | |
890 | +{ | |
891 | + tcg_gen_xori_i32(cpu_regs[REG(ctx, 0)], | |
892 | + cpu_regs[REG(ctx, 0)], a->imm); | |
893 | + return true; | |
894 | +} | |
895 | + | |
896 | +static bool trans_XOR_im(DisasContext *ctx, arg_XOR_im *a) | |
897 | +{ | |
898 | + TCGv val = tcg_temp_new(); | |
899 | + TCGv addr = tcg_temp_new(); | |
900 | + tcg_gen_add_i32(addr, cpu_regs[REG(ctx, 0)], cpu_gbr); | |
901 | + tcg_gen_qemu_ld_i32(val, addr, | |
902 | + ctx->memidx, MO_TE | MO_8); | |
903 | + tcg_gen_xori_i32(val, val, a->imm); | |
904 | + tcg_gen_qemu_st_i32(val, addr, | |
905 | + ctx->memidx, MO_TE | MO_8); | |
906 | + tcg_temp_free(val); | |
907 | + tcg_temp_free(addr); | |
908 | + return true; | |
909 | +} | |
910 | + | |
911 | +static bool trans_NOT(DisasContext *ctx, arg_NOT *a) | |
912 | +{ | |
913 | + tcg_gen_not_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rm)]); | |
914 | + return true; | |
915 | +} | |
916 | + | |
917 | +static bool trans_TAS(DisasContext *ctx, arg_TAS *a) | |
918 | +{ | |
919 | + TCGv val = tcg_temp_new(); | |
920 | + tcg_gen_qemu_ld_i32(val, cpu_regs[REG(ctx, a->rn)], | |
921 | + ctx->memidx, MO_TE | MO_8); | |
922 | + tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0); | |
923 | + tcg_gen_ori_i32(val, val, 0x80); | |
924 | + tcg_gen_qemu_st_i32(val, cpu_regs[REG(ctx, a->rn)], | |
925 | + ctx->memidx, MO_TE | MO_8); | |
926 | + return true; | |
927 | +} | |
928 | + | |
929 | +static bool trans_ROTL(DisasContext *ctx, arg_ROTL *a) | |
930 | +{ | |
931 | + tcg_gen_rotli_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
932 | + tcg_gen_andi_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 1); | |
933 | + return true; | |
934 | +} | |
935 | + | |
936 | +static bool trans_ROTR(DisasContext *ctx, arg_ROTR *a) | |
937 | +{ | |
938 | + tcg_gen_andi_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 1); | |
939 | + tcg_gen_rotli_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
940 | + return true; | |
941 | +} | |
942 | + | |
943 | +static bool trans_ROTCL(DisasContext *ctx, arg_ROTCL *a) | |
944 | +{ | |
945 | + TCGv temp = tcg_temp_new(); | |
946 | + tcg_gen_shri_i32(temp, cpu_regs[REG(ctx, a->rn)], 31); | |
947 | + tcg_gen_shli_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
948 | + tcg_gen_or_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], cpu_sr_t); | |
949 | + tcg_gen_mov_i32(cpu_sr_t, temp); | |
950 | + tcg_temp_free(temp); | |
951 | + return true; | |
952 | +} | |
953 | + | |
954 | +static bool trans_ROTCR(DisasContext *ctx, arg_ROTCR *a) | |
955 | +{ | |
956 | + TCGv temp = tcg_temp_new(); | |
957 | + tcg_gen_andi_i32(temp, cpu_regs[REG(ctx, a->rn)], 1); | |
958 | + tcg_gen_shri_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
959 | + tcg_gen_deposit_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], | |
960 | + temp, 31, 1); | |
961 | + tcg_gen_mov_i32(cpu_sr_t, temp); | |
962 | + tcg_temp_free(temp); | |
963 | + return true; | |
964 | +} | |
965 | + | |
966 | +static bool trans_SHAL(DisasContext *ctx, arg_SHAL *a) | |
967 | +{ | |
968 | + tcg_gen_shri_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 31); | |
969 | + tcg_gen_shli_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
970 | + return true; | |
971 | +} | |
972 | + | |
973 | +static bool trans_SHLL(DisasContext *ctx, arg_SHLL *a) | |
974 | +{ | |
975 | + tcg_gen_shri_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 31); | |
976 | + tcg_gen_shli_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
977 | + return true; | |
978 | +} | |
979 | + | |
980 | +static bool trans_SHAR(DisasContext *ctx, arg_SHAR *a) | |
981 | +{ | |
982 | + tcg_gen_andi_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 1); | |
983 | + tcg_gen_sari_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
984 | + return true; | |
985 | +} | |
986 | + | |
987 | +static bool trans_SHLR(DisasContext *ctx, arg_SHLR *a) | |
988 | +{ | |
989 | + tcg_gen_shri_i32(cpu_sr_t, cpu_regs[REG(ctx, a->rn)], 31); | |
990 | + tcg_gen_shri_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 1); | |
991 | + return true; | |
992 | +} | |
993 | + | |
994 | +static bool trans_SHLL2(DisasContext *ctx, arg_SHLL2 *a) | |
995 | +{ | |
996 | + static const int cnt[] = {2, 8, 16}; | |
997 | + tcg_gen_shli_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], cnt[a->n]); | |
998 | + return true; | |
999 | +} | |
1000 | + | |
1001 | +static bool trans_SHLR2(DisasContext *ctx, arg_SHLR2 *a) | |
1002 | +{ | |
1003 | + static const int cnt[] = {2, 8, 16}; | |
1004 | + tcg_gen_shri_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], cnt[a->n]); | |
1005 | + return true; | |
1006 | +} | |
1007 | + | |
1008 | +static bool trans_BRANCH_T(DisasContext *ctx, arg_BRANCH_T *a) | |
1009 | +{ | |
1010 | + uint32_t dst = ctx->base.pc_next + 2 + a->dsp * 2; | |
1011 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1012 | + if (!a->d) { | |
1013 | + gen_conditional_jump(ctx, dst, a->nt); | |
1014 | + } else { | |
1015 | + if (a->nt) { | |
1016 | + tcg_gen_xori_i32(cpu_delayed_cond, cpu_sr_t, 1); | |
1017 | + } else { | |
1018 | + tcg_gen_mov_i32(cpu_delayed_cond, cpu_sr_t); | |
1019 | + } | |
1020 | + ctx->delayed_pc = dst; | |
1021 | + ctx->envflags |= DELAY_SLOT_CONDITIONAL; | |
1022 | + } | |
1023 | + return true; | |
1024 | +} | |
1025 | + | |
1026 | +static bool trans_BRA(DisasContext *ctx, arg_BRA *a) | |
1027 | +{ | |
1028 | + uint32_t dst = ctx->base.pc_next + 2 + a->dsp * 2; | |
1029 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1030 | + ctx->delayed_pc = dst; | |
1031 | + ctx->envflags |= DELAY_SLOT; | |
1032 | + return true; | |
1033 | +} | |
1034 | + | |
1035 | +static bool trans_BRAF(DisasContext *ctx, arg_BRAF *a) | |
1036 | +{ | |
1037 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1038 | + tcg_gen_addi_i32(cpu_delayed_pc, | |
1039 | + cpu_regs[REG(ctx, a->rm)], ctx->base.pc_next + 2); | |
1040 | + ctx->envflags |= DELAY_SLOT; | |
1041 | + ctx->delayed_pc = (uint32_t) - 1; | |
1042 | + return true; | |
1043 | +} | |
1044 | + | |
1045 | +static bool trans_BSR(DisasContext *ctx, arg_BSR *a) | |
1046 | +{ | |
1047 | + uint32_t dst = ctx->base.pc_next + 2 + a->dsp * 2; | |
1048 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1049 | + tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 2); | |
1050 | + ctx->delayed_pc = dst; | |
1051 | + ctx->envflags |= DELAY_SLOT; | |
1052 | + return true; | |
1053 | +} | |
1054 | + | |
1055 | +static bool trans_BSRF(DisasContext *ctx, arg_BSRF *a) | |
1056 | +{ | |
1057 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1058 | + tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 2); | |
1059 | + tcg_gen_addi_i32(cpu_delayed_pc, | |
1060 | + cpu_regs[REG(ctx, a->rm)], ctx->base.pc_next + 2); | |
1061 | + ctx->envflags |= DELAY_SLOT; | |
1062 | + ctx->delayed_pc = (uint32_t) - 1; | |
1063 | + return true; | |
1064 | +} | |
1065 | + | |
1066 | +static bool trans_JMP(DisasContext *ctx, arg_JMP *a) | |
1067 | +{ | |
1068 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1069 | + tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 2); | |
1070 | + tcg_gen_mov_i32(cpu_delayed_pc, cpu_regs[REG(ctx, a->rm)]); | |
1071 | + ctx->envflags |= DELAY_SLOT; | |
1072 | + ctx->delayed_pc = (uint32_t) - 1; | |
1073 | + return true; | |
1074 | +} | |
1075 | + | |
1076 | +static bool trans_JSR(DisasContext *ctx, arg_JSR *a) | |
1077 | +{ | |
1078 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1079 | + tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 2); | |
1080 | + tcg_gen_mov_i32(cpu_delayed_pc, cpu_regs[REG(ctx, a->rm)]); | |
1081 | + ctx->envflags |= DELAY_SLOT; | |
1082 | + ctx->delayed_pc = (uint32_t) - 1; | |
1083 | + return true; | |
1084 | +} | |
1085 | + | |
1086 | +static bool trans_RTS(DisasContext *ctx, arg_RTS *a) | |
1087 | +{ | |
1088 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1089 | + tcg_gen_mov_i32(cpu_delayed_pc, cpu_pr); | |
1090 | + ctx->envflags |= DELAY_SLOT; | |
1091 | + ctx->delayed_pc = (uint32_t) - 1; | |
1092 | + return true; | |
1093 | +} | |
1094 | + | |
1095 | +static bool trans_CLRMAC(DisasContext *ctx, arg_CLRMAC *a) | |
1096 | +{ | |
1097 | + tcg_gen_movi_i64(cpu_mac, 0); | |
1098 | + return true; | |
1099 | +} | |
1100 | + | |
1101 | +static bool trans_CLRT(DisasContext *ctx, arg_CLRT *a) | |
1102 | +{ | |
1103 | + tcg_gen_movi_i32(cpu_sr_t, 0); | |
1104 | + return true; | |
1105 | +} | |
1106 | + | |
1107 | +static bool trans_SETT(DisasContext *ctx, arg_SETT *a) | |
1108 | +{ | |
1109 | + tcg_gen_movi_i32(cpu_sr_t, 1); | |
1110 | + return true; | |
1111 | +} | |
1112 | + | |
1113 | +static bool trans_LDC_r(DisasContext *ctx, arg_LDC_r *a) | |
1114 | +{ | |
1115 | + CHECK_PRIVILEGED(ctx); | |
1116 | + switch(a->dst) { | |
1117 | + case 0: /* SR */ | |
1118 | + gen_write_sr(cpu_regs[REG(ctx, a->rm)]); | |
1119 | + ctx->base.is_jmp = DISAS_STOP; | |
1120 | + break; | |
1121 | + case 1: /* GBR */ | |
1122 | + tcg_gen_mov_i32(cpu_gbr, cpu_regs[REG(ctx, a->rm)]); | |
1123 | + break; | |
1124 | + case 2: /* VBR */ | |
1125 | + tcg_gen_mov_i32(cpu_vbr, cpu_regs[REG(ctx, a->rm)]); | |
1126 | + break; | |
1127 | + default: | |
1128 | + g_assert_not_reached(); | |
1129 | + } | |
1130 | + return true; | |
1131 | +} | |
1132 | + | |
1133 | +static bool trans_LDC_m(DisasContext *ctx, arg_LDC_m *a) | |
1134 | +{ | |
1135 | + CHECK_PRIVILEGED(ctx); | |
1136 | + switch(a->dst) { | |
1137 | + case 0: { /* SR */ | |
1138 | + TCGv val = tcg_temp_new(); | |
1139 | + tcg_gen_qemu_ld_i32(val, cpu_regs[REG(ctx, a->rm)], | |
1140 | + ctx->memidx, MO_TE | MO_32); | |
1141 | + gen_write_sr(val); | |
1142 | + tcg_temp_free(val); | |
1143 | + ctx->base.is_jmp = DISAS_STOP; | |
1144 | + break; | |
1145 | + } | |
1146 | + case 1: /* GBR */ | |
1147 | + tcg_gen_qemu_ld_i32(cpu_gbr, cpu_regs[REG(ctx, a->rm)], | |
1148 | + ctx->memidx, MO_TE | MO_32); | |
1149 | + break; | |
1150 | + case 2: /* VBR */ | |
1151 | + tcg_gen_qemu_ld_i32(cpu_vbr, cpu_regs[REG(ctx, a->rm)], | |
1152 | + ctx->memidx, MO_TE | MO_32); | |
1153 | + break; | |
1154 | + default: | |
1155 | + g_assert_not_reached(); | |
1156 | + } | |
1157 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, a->rm)], 4); | |
1158 | + return true; | |
1159 | +} | |
1160 | + | |
1161 | +static bool trans_LDS_r(DisasContext *ctx, arg_LDS_r *a) | |
1162 | +{ | |
1163 | + TCGv temp = tcg_temp_new(); | |
1164 | + switch(a->dst) { | |
1165 | + case 0: /* MACH */ | |
1166 | + tcg_gen_extrl_i64_i32(temp, cpu_mac); | |
1167 | + tcg_gen_concat_i32_i64(cpu_mac, cpu_regs[REG(ctx, a->rm)], temp); | |
1168 | + break; | |
1169 | + case 1: /* MACL */ | |
1170 | + tcg_gen_extrh_i64_i32(temp, cpu_mac); | |
1171 | + tcg_gen_concat_i32_i64(cpu_mac, temp, cpu_regs[REG(ctx, a->rm)]); | |
1172 | + break; | |
1173 | + case 2: /* PR */ | |
1174 | + tcg_gen_mov_i32(cpu_pr, cpu_regs[REG(ctx, a->rm)]); | |
1175 | + break; | |
1176 | + default: | |
1177 | + g_assert_not_reached(); | |
1178 | + } | |
1179 | + tcg_temp_free(temp); | |
1180 | + return true; | |
1181 | +} | |
1182 | + | |
1183 | +static bool trans_LDS_m(DisasContext *ctx, arg_LDS_m *a) | |
1184 | +{ | |
1185 | + TCGv hi = tcg_temp_new(); | |
1186 | + TCGv lo = tcg_temp_new(); | |
1187 | + switch(a->dst) { | |
1188 | + case 0: /* MACH */ | |
1189 | + tcg_gen_extrl_i64_i32(lo, cpu_mac); | |
1190 | + tcg_gen_qemu_ld_i32(hi, cpu_regs[REG(ctx, a->rm)], | |
1191 | + ctx->memidx, MO_TE | MO_32); | |
1192 | + tcg_gen_concat_i32_i64(cpu_mac, hi, lo); | |
1193 | + break; | |
1194 | + case 1: /* MACL */ | |
1195 | + tcg_gen_extrh_i64_i32(hi, cpu_mac); | |
1196 | + tcg_gen_qemu_ld_i32(lo, cpu_regs[REG(ctx, a->rm)], | |
1197 | + ctx->memidx, MO_TE | MO_32); | |
1198 | + tcg_gen_concat_i32_i64(cpu_mac, hi, lo); | |
1199 | + break; | |
1200 | + case 2: /* PR */ | |
1201 | + tcg_gen_qemu_ld_i32(cpu_pr, cpu_regs[REG(ctx, a->rm)], | |
1202 | + ctx->memidx, MO_TE | MO_32); | |
1203 | + break; | |
1204 | + default: | |
1205 | + g_assert_not_reached(); | |
1206 | + } | |
1207 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, a->rm)], cpu_regs[REG(ctx, a->rm)], 4); | |
1208 | + tcg_temp_free(hi); | |
1209 | + tcg_temp_free(lo); | |
1210 | + return true; | |
1211 | +} | |
1212 | + | |
1213 | +static bool trans_STC_r(DisasContext *ctx, arg_STC_r *a) | |
1214 | +{ | |
1215 | + CHECK_PRIVILEGED(ctx); | |
1216 | + switch(a->src) { | |
1217 | + case 0: /* SR */ | |
1218 | + gen_read_sr(cpu_regs[REG(ctx, a->rn)]); | |
1219 | + break; | |
1220 | + case 1: /* GBR */ | |
1221 | + tcg_gen_mov_i32(cpu_regs[REG(ctx, a->rn)], cpu_gbr); | |
1222 | + break; | |
1223 | + case 2: /* VBR */ | |
1224 | + tcg_gen_mov_i32(cpu_regs[REG(ctx, a->rn)], cpu_vbr); | |
1225 | + break; | |
1226 | + default: | |
1227 | + g_assert_not_reached(); | |
1228 | + } | |
1229 | + return true; | |
1230 | +} | |
1231 | + | |
1232 | +static bool trans_STC_m(DisasContext *ctx, arg_STC_m *a) | |
1233 | +{ | |
1234 | + CHECK_PRIVILEGED(ctx); | |
1235 | + tcg_gen_subi_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 4); | |
1236 | + switch(a->src) { | |
1237 | + case 0: { /* SR */ | |
1238 | + TCGv sr = tcg_temp_new(); | |
1239 | + gen_read_sr(sr); | |
1240 | + tcg_gen_qemu_st_i32(sr, cpu_regs[REG(ctx, a->rn)], | |
1241 | + ctx->memidx, MO_TE | MO_32); | |
1242 | + tcg_temp_free(sr); | |
1243 | + break; | |
1244 | + } | |
1245 | + case 1: /* GBR */ | |
1246 | + tcg_gen_qemu_st_i32(cpu_gbr, cpu_regs[REG(ctx, a->rn)], | |
1247 | + ctx->memidx, MO_TE | MO_32); | |
1248 | + break; | |
1249 | + case 2: /* VBR */ | |
1250 | + tcg_gen_qemu_st_i32(cpu_vbr, cpu_regs[REG(ctx, a->rn)], | |
1251 | + ctx->memidx, MO_TE | MO_32); | |
1252 | + break; | |
1253 | + default: | |
1254 | + g_assert_not_reached(); | |
1255 | + } | |
1256 | + return true; | |
1257 | +} | |
1258 | + | |
1259 | +static bool trans_STS_r(DisasContext *ctx, arg_STS_r *a) | |
1260 | +{ | |
1261 | + switch(a->src) { | |
1262 | + case 0: /* MACH */ | |
1263 | + tcg_gen_extrh_i64_i32(cpu_regs[a->rn], cpu_mac); | |
1264 | + break; | |
1265 | + case 1: /* MACL */ | |
1266 | + tcg_gen_extrl_i64_i32(cpu_regs[a->rn], cpu_mac); | |
1267 | + break; | |
1268 | + case 2: /* PR */ | |
1269 | + tcg_gen_mov_i32(cpu_regs[REG(ctx, a->rn)], cpu_pr); | |
1270 | + break; | |
1271 | + default: | |
1272 | + g_assert_not_reached(); | |
1273 | + } | |
1274 | + return true; | |
1275 | +} | |
1276 | + | |
1277 | +static bool trans_STS_m(DisasContext *ctx, arg_STS_m *a) | |
1278 | +{ | |
1279 | + TCGv val = tcg_temp_new(); | |
1280 | + tcg_gen_subi_i32(cpu_regs[REG(ctx, a->rn)], cpu_regs[REG(ctx, a->rn)], 4); | |
1281 | + switch(a->src) { | |
1282 | + case 0: /* MACH */ | |
1283 | + tcg_gen_extrh_i64_i32(val, cpu_mac); | |
1284 | + tcg_gen_qemu_st_i32(val, cpu_regs[REG(ctx, a->rn)], | |
1285 | + ctx->memidx, MO_TE | MO_32); | |
1286 | + break; | |
1287 | + case 1: /* MACL */ | |
1288 | + tcg_gen_extrl_i64_i32(val, cpu_mac); | |
1289 | + tcg_gen_qemu_st_i32(val, cpu_regs[REG(ctx, a->rn)], | |
1290 | + ctx->memidx, MO_TE | MO_32); | |
1291 | + break; | |
1292 | + case 2: /* PR */ | |
1293 | + tcg_gen_qemu_st_i32(cpu_pr, cpu_regs[REG(ctx, a->rn)], | |
1294 | + ctx->memidx, MO_TE | MO_32); | |
1295 | + break; | |
1296 | + default: | |
1297 | + g_assert_not_reached(); | |
1298 | + } | |
1299 | + tcg_temp_free(val); | |
1300 | + return true; | |
1301 | +} | |
1302 | + | |
1303 | +static bool trans_NOP(DisasContext *ctx, arg_NOP *a) | |
1304 | +{ | |
1305 | + return true; | |
1306 | +} | |
1307 | + | |
1308 | +static bool trans_TRAPA(DisasContext *ctx, arg_TRAPA *a) | |
1309 | +{ | |
1310 | + TCGv imm = tcg_const_i32(a->imm);; | |
1311 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1312 | + gen_save_cpu_state(ctx, true); | |
1313 | + gen_helper_trapa(cpu_env, imm); | |
1314 | + tcg_temp_free(imm); | |
1315 | + ctx->base.is_jmp = DISAS_NORETURN; | |
1316 | + return true; | |
1317 | +} | |
1318 | + | |
1319 | +static bool trans_RTE(DisasContext *ctx, arg_RTE *a) | |
1320 | +{ | |
1321 | + CHECK_PRIVILEGED(ctx); | |
1322 | + CHECK_NOT_DELAY_SLOT(ctx); | |
1323 | + if (IS_SH2(ctx)) { | |
1324 | + /* SH2 */ | |
1325 | + TCGv sr = tcg_temp_new(); | |
1326 | + tcg_gen_qemu_ld_i32(cpu_delayed_pc, cpu_regs[REG(ctx, R_SP)], | |
1327 | + ctx->memidx, MO_TE | MO_32); | |
1328 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, R_SP)], cpu_regs[REG(ctx, R_SP)], 4); | |
1329 | + tcg_gen_qemu_ld_i32(sr, cpu_regs[REG(ctx, R_SP)], | |
1330 | + ctx->memidx, MO_TE | MO_32); | |
1331 | + tcg_gen_addi_i32(cpu_regs[REG(ctx, R_SP)], cpu_regs[REG(ctx, R_SP)], 4); | |
1332 | + gen_write_sr(sr); | |
1333 | + tcg_temp_free(sr); | |
1334 | + } else { | |
1335 | + /* SH3 / SH4 */ | |
1336 | + gen_write_sr(cpu_ssr); | |
1337 | + tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); | |
1338 | + } | |
1339 | + ctx->envflags |= DELAY_SLOT_RTE; | |
1340 | + ctx->delayed_pc = (uint32_t) - 1; | |
1341 | + ctx->base.is_jmp = DISAS_STOP; | |
1342 | + | |
1343 | + return true; | |
1344 | +} | |
1345 | + | |
1346 | +static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) | |
1347 | +{ | |
1348 | + CHECK_PRIVILEGED(ctx); | |
1349 | + tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); | |
1350 | + gen_helper_sleep(cpu_env); | |
1351 | + return true; | |
1352 | +} | |
1353 | + | |
1354 | +static void sh_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) | |
1355 | +{ | |
1356 | + DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1357 | + CPUSHState *env = cs->env_ptr; | |
1358 | + uint32_t tbflags; | |
1359 | + | |
1360 | + tbflags = ctx->base.tb->flags; | |
1361 | + ctx->envflags = tbflags & TB_FLAG_ENVFLAGS_MASK; | |
1362 | + ctx->features = env->features; | |
1363 | + if (!IS_SH2(ctx)) { | |
1364 | + ctx->memidx = FIELD_EX32(tbflags, SR, MD) == 0 ? 1 : 0; | |
1365 | + ctx->sr_rb = FIELD_EX32(tbflags, SR, RB); | |
1366 | + } else { | |
1367 | + ctx->memidx = 0; | |
1368 | + ctx->sr_rb = 0; | |
1369 | + } | |
1370 | + /* We don't know if the delayed pc came from a dynamic or static branch, | |
1371 | + so assume it is a dynamic branch. */ | |
1372 | + ctx->delayed_pc = -1; /* use delayed pc from env pointer */ | |
1373 | +} | |
1374 | + | |
1375 | +static void sh_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) | |
1376 | +{ | |
1377 | +} | |
1378 | + | |
1379 | +static void sh_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) | |
1380 | +{ | |
1381 | + DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1382 | + | |
1383 | + tcg_gen_insn_start(ctx->base.pc_next, ctx->envflags); | |
1384 | +} | |
1385 | + | |
1386 | +static bool sh_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, | |
1387 | + const CPUBreakpoint *bp) | |
1388 | +{ | |
1389 | + DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1390 | + | |
1391 | + /* We have hit a breakpoint - make sure PC is up-to-date */ | |
1392 | + gen_save_cpu_state(ctx, true); | |
1393 | + gen_helper_debug(cpu_env); | |
1394 | + ctx->base.is_jmp = DISAS_NORETURN; | |
1395 | + /* The address covered by the breakpoint must be included in | |
1396 | + [tb->pc, tb->pc + tb->size) in order to for it to be | |
1397 | + properly cleared -- thus we increment the PC here so that | |
1398 | + the logic setting tb->size below does the right thing. */ | |
1399 | + ctx->base.pc_next += 2; | |
1400 | + return true; | |
1401 | +} | |
1402 | + | |
1403 | +static void sh_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) | |
1404 | +{ | |
1405 | + CPUSHState *env = cs->env_ptr; | |
1406 | + DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1407 | + uint32_t old_flags = ctx->envflags; | |
1408 | + uint32_t insn; | |
1409 | + | |
1410 | + insn = cpu_lduw_code(env, ctx->base.pc_next); | |
1411 | + ctx->base.pc_next += 2; | |
1412 | + if (!decode(ctx, insn)) { | |
1413 | + gen_save_cpu_state(ctx, true); | |
1414 | + if (old_flags & DELAY_SLOT_MASK) { | |
1415 | + gen_helper_raise_slot_illegal_instruction(cpu_env); | |
1416 | + } else { | |
1417 | + gen_helper_raise_illegal_instruction(cpu_env); | |
1418 | + } | |
1419 | + } | |
1420 | + if (old_flags & DELAY_SLOT_MASK) { | |
1421 | + /* go out of the delay slot */ | |
1422 | + ctx->envflags &= ~DELAY_SLOT_MASK; | |
1423 | + | |
1424 | + tcg_gen_movi_i32(cpu_flags, ctx->envflags); | |
1425 | + if (old_flags & DELAY_SLOT_CONDITIONAL) { | |
1426 | + gen_delayed_conditional_jump(ctx); | |
1427 | + } else { | |
1428 | + gen_jump(ctx); | |
1429 | + } | |
1430 | + } | |
1431 | +} | |
1432 | + | |
1433 | +static void sh_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) | |
1434 | +{ | |
1435 | + DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1436 | + | |
1437 | + switch (ctx->base.is_jmp) { | |
1438 | + case DISAS_STOP: | |
1439 | + gen_save_cpu_state(ctx, true); | |
1440 | + if (ctx->base.singlestep_enabled) { | |
1441 | + gen_helper_debug(cpu_env); | |
1442 | + } else { | |
1443 | + tcg_gen_exit_tb(NULL, 0); | |
1444 | + } | |
1445 | + break; | |
1446 | + case DISAS_NEXT: | |
1447 | + case DISAS_TOO_MANY: | |
1448 | + gen_save_cpu_state(ctx, false); | |
1449 | + gen_goto_tb(ctx, 0, ctx->base.pc_next); | |
1450 | + break; | |
1451 | + case DISAS_NORETURN: | |
1452 | + break; | |
1453 | + default: | |
1454 | + g_assert_not_reached(); | |
1455 | + } | |
1456 | +} | |
1457 | + | |
1458 | +static void sh_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) | |
1459 | +{ | |
1460 | + qemu_log("IN:\n"); /* , lookup_symbol(dcbase->pc_first)); */ | |
1461 | + log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); | |
1462 | +} | |
1463 | + | |
1464 | +static const TranslatorOps sh_tr_ops = { | |
1465 | + .init_disas_context = sh_tr_init_disas_context, | |
1466 | + .tb_start = sh_tr_tb_start, | |
1467 | + .insn_start = sh_tr_insn_start, | |
1468 | + .breakpoint_check = sh_tr_breakpoint_check, | |
1469 | + .translate_insn = sh_tr_translate_insn, | |
1470 | + .tb_stop = sh_tr_tb_stop, | |
1471 | + .disas_log = sh_tr_disas_log, | |
1472 | +}; | |
1473 | + | |
1474 | +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) | |
1475 | +{ | |
1476 | + DisasContext ctx; | |
1477 | + | |
1478 | + translator_loop(&sh_tr_ops, &ctx.base, cs, tb, max_insns); | |
1479 | +} | |
1480 | + | |
1481 | +void restore_state_to_opc(CPUSHState *env, TranslationBlock *tb, | |
1482 | + target_ulong *data) | |
1483 | +{ | |
1484 | + env->pc = data[0]; | |
1485 | + env->flags = data[1]; | |
1486 | + /* Theoretically delayed_pc should also be restored. In practice the | |
1487 | + branch instruction is re-executed after exception, so the delayed | |
1488 | + branch target will be recomputed. */ | |
1489 | +} |