Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* fr30 simulator support code |
2 | Copyright (C) 1998, 1999 Free Software Foundation, Inc. | |
3 | Contributed by Cygnus Solutions. | |
4 | ||
5 | This file is part of the GNU simulators. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | This program 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 | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License along | |
18 | with this program; if not, write to the Free Software Foundation, Inc., | |
19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
20 | ||
21 | #define WANT_CPU | |
22 | #define WANT_CPU_FR30BF | |
23 | ||
24 | #include "sim-main.h" | |
25 | #include "cgen-mem.h" | |
26 | #include "cgen-ops.h" | |
27 | ||
28 | /* Convert gdb dedicated register number to actual dr reg number. */ | |
29 | ||
30 | static int | |
31 | decode_gdb_dr_regnum (int gdb_regnum) | |
32 | { | |
33 | switch (gdb_regnum) | |
34 | { | |
35 | case TBR_REGNUM : return H_DR_TBR; | |
36 | case RP_REGNUM : return H_DR_RP; | |
37 | case SSP_REGNUM : return H_DR_SSP; | |
38 | case USP_REGNUM : return H_DR_USP; | |
39 | case MDH_REGNUM : return H_DR_MDH; | |
40 | case MDL_REGNUM : return H_DR_MDL; | |
41 | } | |
42 | abort (); | |
43 | } | |
44 | ||
45 | /* The contents of BUF are in target byte order. */ | |
46 | ||
47 | int | |
48 | fr30bf_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len) | |
49 | { | |
50 | if (rn < 16) | |
7a292a7a | 51 | SETTWI (buf, fr30bf_h_gr_get (current_cpu, rn)); |
c906108c SS |
52 | else |
53 | switch (rn) | |
54 | { | |
55 | case PC_REGNUM : | |
7a292a7a | 56 | SETTWI (buf, fr30bf_h_pc_get (current_cpu)); |
c906108c SS |
57 | break; |
58 | case PS_REGNUM : | |
7a292a7a | 59 | SETTWI (buf, fr30bf_h_ps_get (current_cpu)); |
c906108c SS |
60 | break; |
61 | case TBR_REGNUM : | |
62 | case RP_REGNUM : | |
63 | case SSP_REGNUM : | |
64 | case USP_REGNUM : | |
65 | case MDH_REGNUM : | |
66 | case MDL_REGNUM : | |
7a292a7a | 67 | SETTWI (buf, fr30bf_h_dr_get (current_cpu, |
c906108c SS |
68 | decode_gdb_dr_regnum (rn))); |
69 | break; | |
70 | default : | |
71 | return 0; | |
72 | } | |
73 | ||
74 | return -1; /*FIXME*/ | |
75 | } | |
76 | ||
77 | /* The contents of BUF are in target byte order. */ | |
78 | ||
79 | int | |
80 | fr30bf_store_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len) | |
81 | { | |
82 | if (rn < 16) | |
7a292a7a | 83 | fr30bf_h_gr_set (current_cpu, rn, GETTWI (buf)); |
c906108c SS |
84 | else |
85 | switch (rn) | |
86 | { | |
87 | case PC_REGNUM : | |
7a292a7a | 88 | fr30bf_h_pc_set (current_cpu, GETTWI (buf)); |
c906108c SS |
89 | break; |
90 | case PS_REGNUM : | |
7a292a7a | 91 | fr30bf_h_ps_set (current_cpu, GETTWI (buf)); |
c906108c SS |
92 | break; |
93 | case TBR_REGNUM : | |
94 | case RP_REGNUM : | |
95 | case SSP_REGNUM : | |
96 | case USP_REGNUM : | |
97 | case MDH_REGNUM : | |
98 | case MDL_REGNUM : | |
7a292a7a | 99 | fr30bf_h_dr_set (current_cpu, |
c906108c SS |
100 | decode_gdb_dr_regnum (rn), |
101 | GETTWI (buf)); | |
102 | break; | |
103 | default : | |
104 | return 0; | |
105 | } | |
106 | ||
107 | return -1; /*FIXME*/ | |
108 | } | |
109 | \f | |
110 | /* Cover fns to access the ccr bits. */ | |
111 | ||
112 | BI | |
113 | fr30bf_h_sbit_get_handler (SIM_CPU *current_cpu) | |
114 | { | |
115 | return CPU (h_sbit); | |
116 | } | |
117 | ||
118 | void | |
119 | fr30bf_h_sbit_set_handler (SIM_CPU *current_cpu, BI newval) | |
120 | { | |
121 | int old_sbit = CPU (h_sbit); | |
122 | int new_sbit = (newval != 0); | |
123 | ||
124 | CPU (h_sbit) = new_sbit; | |
125 | ||
126 | /* When switching stack modes, update the registers. */ | |
127 | if (old_sbit != new_sbit) | |
128 | { | |
129 | if (old_sbit) | |
130 | { | |
131 | /* Switching user -> system. */ | |
132 | CPU (h_dr[H_DR_USP]) = CPU (h_gr[H_GR_SP]); | |
133 | CPU (h_gr[H_GR_SP]) = CPU (h_dr[H_DR_SSP]); | |
134 | } | |
135 | else | |
136 | { | |
137 | /* Switching system -> user. */ | |
138 | CPU (h_dr[H_DR_SSP]) = CPU (h_gr[H_GR_SP]); | |
139 | CPU (h_gr[H_GR_SP]) = CPU (h_dr[H_DR_USP]); | |
140 | } | |
141 | } | |
142 | ||
143 | /* TODO: r15 interlock */ | |
144 | } | |
145 | \f | |
146 | /* Cover fns to access the ccr bits. */ | |
147 | ||
148 | UQI | |
149 | fr30bf_h_ccr_get_handler (SIM_CPU *current_cpu) | |
150 | { | |
151 | int ccr = ( (GET_H_CBIT () << 0) | |
152 | | (GET_H_VBIT () << 1) | |
153 | | (GET_H_ZBIT () << 2) | |
154 | | (GET_H_NBIT () << 3) | |
155 | | (GET_H_IBIT () << 4) | |
156 | | (GET_H_SBIT () << 5)); | |
157 | ||
158 | return ccr; | |
159 | } | |
160 | ||
161 | void | |
162 | fr30bf_h_ccr_set_handler (SIM_CPU *current_cpu, UQI newval) | |
163 | { | |
164 | int ccr = newval & 0x3f; | |
165 | ||
166 | SET_H_CBIT ((ccr & 1) != 0); | |
167 | SET_H_VBIT ((ccr & 2) != 0); | |
168 | SET_H_ZBIT ((ccr & 4) != 0); | |
169 | SET_H_NBIT ((ccr & 8) != 0); | |
170 | SET_H_IBIT ((ccr & 0x10) != 0); | |
171 | SET_H_SBIT ((ccr & 0x20) != 0); | |
172 | } | |
173 | \f | |
174 | /* Cover fns to access the scr bits. */ | |
175 | ||
176 | UQI | |
177 | fr30bf_h_scr_get_handler (SIM_CPU *current_cpu) | |
178 | { | |
179 | int scr = ( (GET_H_TBIT () << 0) | |
180 | | (GET_H_D0BIT () << 1) | |
181 | | (GET_H_D1BIT () << 2)); | |
182 | return scr; | |
183 | } | |
184 | ||
185 | void | |
186 | fr30bf_h_scr_set_handler (SIM_CPU *current_cpu, UQI newval) | |
187 | { | |
188 | int scr = newval & 7; | |
189 | ||
190 | SET_H_TBIT ((scr & 1) != 0); | |
191 | SET_H_D0BIT ((scr & 2) != 0); | |
192 | SET_H_D1BIT ((scr & 4) != 0); | |
193 | } | |
194 | \f | |
195 | /* Cover fns to access the ilm bits. */ | |
196 | ||
197 | UQI | |
198 | fr30bf_h_ilm_get_handler (SIM_CPU *current_cpu) | |
199 | { | |
200 | return CPU (h_ilm); | |
201 | } | |
202 | ||
203 | void | |
204 | fr30bf_h_ilm_set_handler (SIM_CPU *current_cpu, UQI newval) | |
205 | { | |
206 | int ilm = newval & 0x1f; | |
207 | int current_ilm = CPU (h_ilm); | |
208 | ||
209 | /* We can only set new ilm values < 16 if the current ilm is < 16. Otherwise | |
210 | we add 16 to the value we are given. */ | |
211 | if (current_ilm >= 16 && ilm < 16) | |
212 | ilm += 16; | |
213 | ||
214 | CPU (h_ilm) = ilm; | |
215 | } | |
216 | \f | |
217 | /* Cover fns to access the ps register. */ | |
218 | ||
219 | USI | |
220 | fr30bf_h_ps_get_handler (SIM_CPU *current_cpu) | |
221 | { | |
222 | int ccr = GET_H_CCR (); | |
223 | int scr = GET_H_SCR (); | |
224 | int ilm = GET_H_ILM (); | |
225 | ||
226 | return ccr | (scr << 8) | (ilm << 16); | |
227 | } | |
228 | ||
229 | void | |
230 | fr30bf_h_ps_set_handler (SIM_CPU *current_cpu, USI newval) | |
231 | { | |
232 | int ccr = newval & 0xff; | |
233 | int scr = (newval >> 8) & 7; | |
234 | int ilm = (newval >> 16) & 0x1f; | |
235 | ||
236 | SET_H_CCR (ccr); | |
237 | SET_H_SCR (scr); | |
238 | SET_H_ILM (ilm); | |
239 | } | |
240 | \f | |
241 | /* Cover fns to access the dedicated registers. */ | |
242 | ||
243 | SI | |
244 | fr30bf_h_dr_get_handler (SIM_CPU *current_cpu, UINT dr) | |
245 | { | |
246 | switch (dr) | |
247 | { | |
248 | case H_DR_SSP : | |
249 | if (! GET_H_SBIT ()) | |
250 | return GET_H_GR (H_GR_SP); | |
251 | else | |
252 | return CPU (h_dr[H_DR_SSP]); | |
253 | case H_DR_USP : | |
254 | if (GET_H_SBIT ()) | |
255 | return GET_H_GR (H_GR_SP); | |
256 | else | |
257 | return CPU (h_dr[H_DR_USP]); | |
258 | case H_DR_TBR : | |
259 | case H_DR_RP : | |
260 | case H_DR_MDH : | |
261 | case H_DR_MDL : | |
262 | return CPU (h_dr[dr]); | |
263 | } | |
264 | return 0; | |
265 | } | |
266 | ||
267 | void | |
268 | fr30bf_h_dr_set_handler (SIM_CPU *current_cpu, UINT dr, SI newval) | |
269 | { | |
270 | switch (dr) | |
271 | { | |
272 | case H_DR_SSP : | |
273 | if (! GET_H_SBIT ()) | |
274 | SET_H_GR (H_GR_SP, newval); | |
275 | else | |
276 | CPU (h_dr[H_DR_SSP]) = newval; | |
277 | break; | |
278 | case H_DR_USP : | |
279 | if (GET_H_SBIT ()) | |
280 | SET_H_GR (H_GR_SP, newval); | |
281 | else | |
282 | CPU (h_dr[H_DR_USP]) = newval; | |
283 | break; | |
284 | case H_DR_TBR : | |
285 | case H_DR_RP : | |
286 | case H_DR_MDH : | |
287 | case H_DR_MDL : | |
288 | CPU (h_dr[dr]) = newval; | |
289 | break; | |
290 | } | |
291 | } | |
292 | \f | |
293 | #if WITH_PROFILE_MODEL_P | |
294 | ||
295 | /* FIXME: Some of these should be inline or macros. Later. */ | |
296 | ||
297 | /* Initialize cycle counting for an insn. | |
298 | FIRST_P is non-zero if this is the first insn in a set of parallel | |
299 | insns. */ | |
300 | ||
301 | void | |
302 | fr30bf_model_insn_before (SIM_CPU *cpu, int first_p) | |
303 | { | |
304 | MODEL_FR30_1_DATA *d = CPU_MODEL_DATA (cpu); | |
305 | d->load_regs_pending = 0; | |
306 | } | |
307 | ||
308 | /* Record the cycles computed for an insn. | |
309 | LAST_P is non-zero if this is the last insn in a set of parallel insns, | |
310 | and we update the total cycle count. | |
311 | CYCLES is the cycle count of the insn. */ | |
312 | ||
313 | void | |
314 | fr30bf_model_insn_after (SIM_CPU *cpu, int last_p, int cycles) | |
315 | { | |
316 | PROFILE_DATA *p = CPU_PROFILE_DATA (cpu); | |
317 | MODEL_FR30_1_DATA *d = CPU_MODEL_DATA (cpu); | |
318 | ||
319 | PROFILE_MODEL_TOTAL_CYCLES (p) += cycles; | |
320 | PROFILE_MODEL_CUR_INSN_CYCLES (p) = cycles; | |
321 | d->load_regs = d->load_regs_pending; | |
322 | } | |
323 | ||
324 | static INLINE int | |
325 | check_load_stall (SIM_CPU *cpu, int regno) | |
326 | { | |
327 | const MODEL_FR30_1_DATA *d = CPU_MODEL_DATA (cpu); | |
328 | UINT load_regs = d->load_regs; | |
329 | ||
330 | if (regno != -1 | |
331 | && (load_regs & (1 << regno)) != 0) | |
332 | { | |
333 | PROFILE_DATA *p = CPU_PROFILE_DATA (cpu); | |
334 | ++ PROFILE_MODEL_LOAD_STALL_CYCLES (p); | |
335 | if (TRACE_INSN_P (cpu)) | |
336 | cgen_trace_printf (cpu, " ; Load stall."); | |
337 | return 1; | |
338 | } | |
339 | else | |
340 | return 0; | |
341 | } | |
342 | ||
343 | int | |
344 | fr30bf_model_fr30_1_u_exec (SIM_CPU *cpu, const IDESC *idesc, | |
345 | int unit_num, int referenced, | |
346 | INT in_Ri, INT in_Rj, INT out_Ri) | |
347 | { | |
348 | int cycles = idesc->timing->units[unit_num].done; | |
349 | cycles += check_load_stall (cpu, in_Ri); | |
350 | cycles += check_load_stall (cpu, in_Rj); | |
351 | return cycles; | |
352 | } | |
353 | ||
354 | int | |
355 | fr30bf_model_fr30_1_u_cti (SIM_CPU *cpu, const IDESC *idesc, | |
356 | int unit_num, int referenced, | |
357 | INT in_Ri) | |
358 | { | |
359 | PROFILE_DATA *p = CPU_PROFILE_DATA (cpu); | |
360 | /* (1 << 1): The pc is the 2nd element in inputs, outputs. | |
361 | ??? can be cleaned up */ | |
362 | int taken_p = (referenced & (1 << 1)) != 0; | |
363 | int cycles = idesc->timing->units[unit_num].done; | |
364 | int delay_slot_p = CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_DELAY_SLOT); | |
365 | ||
366 | cycles += check_load_stall (cpu, in_Ri); | |
367 | if (taken_p) | |
368 | { | |
369 | /* ??? Handling cti's without delay slots this way will run afoul of | |
370 | accurate system simulation. Later. */ | |
371 | if (! delay_slot_p) | |
372 | { | |
373 | ++cycles; | |
374 | ++PROFILE_MODEL_CTI_STALL_CYCLES (p); | |
375 | } | |
376 | ++PROFILE_MODEL_TAKEN_COUNT (p); | |
377 | } | |
378 | else | |
379 | ++PROFILE_MODEL_UNTAKEN_COUNT (p); | |
380 | ||
381 | return cycles; | |
382 | } | |
383 | ||
384 | int | |
385 | fr30bf_model_fr30_1_u_load (SIM_CPU *cpu, const IDESC *idesc, | |
386 | int unit_num, int referenced, | |
387 | INT in_Rj, INT out_Ri) | |
388 | { | |
389 | MODEL_FR30_1_DATA *d = CPU_MODEL_DATA (cpu); | |
390 | int cycles = idesc->timing->units[unit_num].done; | |
391 | d->load_regs_pending |= 1 << out_Ri; | |
392 | cycles += check_load_stall (cpu, in_Rj); | |
393 | return cycles; | |
394 | } | |
395 | ||
396 | int | |
397 | fr30bf_model_fr30_1_u_store (SIM_CPU *cpu, const IDESC *idesc, | |
398 | int unit_num, int referenced, | |
399 | INT in_Ri, INT in_Rj) | |
400 | { | |
401 | int cycles = idesc->timing->units[unit_num].done; | |
402 | cycles += check_load_stall (cpu, in_Ri); | |
403 | cycles += check_load_stall (cpu, in_Rj); | |
404 | return cycles; | |
405 | } | |
406 | ||
407 | int | |
408 | fr30bf_model_fr30_1_u_ldm (SIM_CPU *cpu, const IDESC *idesc, | |
409 | int unit_num, int referenced, | |
410 | INT reglist) | |
411 | { | |
412 | return idesc->timing->units[unit_num].done; | |
413 | } | |
414 | ||
415 | int | |
416 | fr30bf_model_fr30_1_u_stm (SIM_CPU *cpu, const IDESC *idesc, | |
417 | int unit_num, int referenced, | |
418 | INT reglist) | |
419 | { | |
420 | return idesc->timing->units[unit_num].done; | |
421 | } | |
422 | ||
423 | #endif /* WITH_PROFILE_MODEL_P */ |