1 | /* |
2 | * Copyright (C) 2010-2012 Guan Xuetao |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. |
7 | * |
8 | * Contributions from 2012-04-01 on are considered under GPL version 2, |
9 | * or (at your option) any later version. |
10 | */ |
11 | |
12 | #include "qemu/osdep.h" |
13 | #include "cpu.h" |
14 | #include "exec/exec-all.h" |
15 | #include "exec/gdbstub.h" |
16 | #include "exec/helper-proto.h" |
17 | #include "qemu/host-utils.h" |
18 | #ifndef CONFIG_USER_ONLY |
19 | #include "ui/console.h" |
20 | #endif |
21 | |
22 | #undef DEBUG_UC32 |
23 | |
24 | #ifdef DEBUG_UC32 |
25 | #define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__) |
26 | #else |
27 | #define DPRINTF(fmt, ...) do {} while (0) |
28 | #endif |
29 | |
30 | #ifndef CONFIG_USER_ONLY |
31 | void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg, |
32 | uint32_t cop) |
33 | { |
34 | /* |
35 | * movc pp.nn, rn, #imm9 |
36 | * rn: UCOP_REG_D |
37 | * nn: UCOP_REG_N |
38 | * 1: sys control reg. |
39 | * 2: page table base reg. |
40 | * 3: data fault status reg. |
41 | * 4: insn fault status reg. |
42 | * 5: cache op. reg. |
43 | * 6: tlb op. reg. |
44 | * imm9: split UCOP_IMM10 with bit5 is 0 |
45 | */ |
46 | switch (creg) { |
47 | case 1: |
48 | if (cop != 0) { |
49 | goto unrecognized; |
50 | } |
51 | env->cp0.c1_sys = val; |
52 | break; |
53 | case 2: |
54 | if (cop != 0) { |
55 | goto unrecognized; |
56 | } |
57 | env->cp0.c2_base = val; |
58 | break; |
59 | case 3: |
60 | if (cop != 0) { |
61 | goto unrecognized; |
62 | } |
63 | env->cp0.c3_faultstatus = val; |
64 | break; |
65 | case 4: |
66 | if (cop != 0) { |
67 | goto unrecognized; |
68 | } |
69 | env->cp0.c4_faultaddr = val; |
70 | break; |
71 | case 5: |
72 | switch (cop) { |
73 | case 28: |
74 | DPRINTF("Invalidate Entire I&D cache\n" ); |
75 | return; |
76 | case 20: |
77 | DPRINTF("Invalidate Entire Icache\n" ); |
78 | return; |
79 | case 12: |
80 | DPRINTF("Invalidate Entire Dcache\n" ); |
81 | return; |
82 | case 10: |
83 | DPRINTF("Clean Entire Dcache\n" ); |
84 | return; |
85 | case 14: |
86 | DPRINTF("Flush Entire Dcache\n" ); |
87 | return; |
88 | case 13: |
89 | DPRINTF("Invalidate Dcache line\n" ); |
90 | return; |
91 | case 11: |
92 | DPRINTF("Clean Dcache line\n" ); |
93 | return; |
94 | case 15: |
95 | DPRINTF("Flush Dcache line\n" ); |
96 | return; |
97 | } |
98 | break; |
99 | case 6: |
100 | if ((cop <= 6) && (cop >= 2)) { |
101 | /* invalid all tlb */ |
102 | tlb_flush(env_cpu(env)); |
103 | return; |
104 | } |
105 | break; |
106 | default: |
107 | goto unrecognized; |
108 | } |
109 | return; |
110 | unrecognized: |
111 | DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n" , |
112 | creg, cop); |
113 | } |
114 | |
115 | uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop) |
116 | { |
117 | /* |
118 | * movc rd, pp.nn, #imm9 |
119 | * rd: UCOP_REG_D |
120 | * nn: UCOP_REG_N |
121 | * 0: cpuid and cachetype |
122 | * 1: sys control reg. |
123 | * 2: page table base reg. |
124 | * 3: data fault status reg. |
125 | * 4: insn fault status reg. |
126 | * imm9: split UCOP_IMM10 with bit5 is 0 |
127 | */ |
128 | switch (creg) { |
129 | case 0: |
130 | switch (cop) { |
131 | case 0: |
132 | return env->cp0.c0_cpuid; |
133 | case 1: |
134 | return env->cp0.c0_cachetype; |
135 | } |
136 | break; |
137 | case 1: |
138 | if (cop == 0) { |
139 | return env->cp0.c1_sys; |
140 | } |
141 | break; |
142 | case 2: |
143 | if (cop == 0) { |
144 | return env->cp0.c2_base; |
145 | } |
146 | break; |
147 | case 3: |
148 | if (cop == 0) { |
149 | return env->cp0.c3_faultstatus; |
150 | } |
151 | break; |
152 | case 4: |
153 | if (cop == 0) { |
154 | return env->cp0.c4_faultaddr; |
155 | } |
156 | break; |
157 | } |
158 | DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n" , |
159 | creg, cop); |
160 | return 0; |
161 | } |
162 | |
163 | #ifdef CONFIG_CURSES |
164 | |
165 | /* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */ |
166 | #undef KEY_EVENT |
167 | #include <curses.h> |
168 | #undef KEY_EVENT |
169 | |
170 | /* |
171 | * FIXME: |
172 | * 1. curses windows will be blank when switching back |
173 | * 2. backspace is not handled yet |
174 | */ |
175 | static void putc_on_screen(unsigned char ch) |
176 | { |
177 | static WINDOW *localwin; |
178 | static int init; |
179 | |
180 | if (!init) { |
181 | /* Assume 80 * 30 screen to minimize the implementation */ |
182 | localwin = newwin(30, 80, 0, 0); |
183 | scrollok(localwin, TRUE); |
184 | init = TRUE; |
185 | } |
186 | |
187 | if (isprint(ch)) { |
188 | wprintw(localwin, "%c" , ch); |
189 | } else { |
190 | switch (ch) { |
191 | case '\n': |
192 | wprintw(localwin, "%c" , ch); |
193 | break; |
194 | case '\r': |
195 | /* If '\r' is put before '\n', the curses window will destroy the |
196 | * last print line. And meanwhile, '\n' implifies '\r' inside. */ |
197 | break; |
198 | default: /* Not handled, so just print it hex code */ |
199 | wprintw(localwin, "-- 0x%x --" , ch); |
200 | } |
201 | } |
202 | |
203 | wrefresh(localwin); |
204 | } |
205 | #else |
206 | #define putc_on_screen(c) do { } while (0) |
207 | #endif |
208 | |
209 | void helper_cp1_putc(target_ulong x) |
210 | { |
211 | putc_on_screen((unsigned char)x); /* Output to screen */ |
212 | DPRINTF("%c" , x); /* Output to stdout */ |
213 | } |
214 | #endif |
215 | |
216 | bool uc32_cpu_exec_interrupt(CPUState *cs, int interrupt_request) |
217 | { |
218 | if (interrupt_request & CPU_INTERRUPT_HARD) { |
219 | UniCore32CPU *cpu = UNICORE32_CPU(cs); |
220 | CPUUniCore32State *env = &cpu->env; |
221 | |
222 | if (!(env->uncached_asr & ASR_I)) { |
223 | cs->exception_index = UC32_EXCP_INTR; |
224 | uc32_cpu_do_interrupt(cs); |
225 | return true; |
226 | } |
227 | } |
228 | return false; |
229 | } |
230 | |