xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/cpu.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
1 /*  This file is part of the program psim.
2 
3     Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, see <http://www.gnu.org/licenses/>.
17 
18     */
19 
20 
21 #ifndef _CPU_C_
22 #define _CPU_C_
23 
24 /* This must come before any other includes.  */
25 #include "defs.h"
26 
27 #include <setjmp.h>
28 
29 #include "cpu.h"
30 #include "idecode.h"
31 
32 #include <string.h>
33 
34 struct _cpu {
35 
36   /* the registers */
37   registers regs;
38 
39   /* current instruction address */
40   unsigned_word program_counter;
41 
42   /* the memory maps */
43   core *physical; /* all of memory */
44   vm *virtual;
45   vm_instruction_map *instruction_map; /* instructions */
46   vm_data_map *data_map; /* data */
47 
48   /* the system this processor is contained within */
49   cpu_mon *monitor;
50   os_emul *os_emulation;
51   psim *system;
52   event_queue *events;
53   int cpu_nr;
54 
55   /* Current CPU model information */
56   model_data *model_ptr;
57 
58 #if WITH_IDECODE_CACHE_SIZE
59   /* a cache to store cracked instructions */
60   idecode_cache icache[WITH_IDECODE_CACHE_SIZE];
61 #endif
62 
63   /* any interrupt state */
64   interrupts ints;
65 
66   /* address reservation: keep the physical address and the contents
67      of memory at that address */
68   memory_reservation reservation;
69 
70   /* offset from event time to this cpu's idea of the local time */
71   int64_t time_base_local_time;
72   int64_t decrementer_local_time;
73   event_entry_tag decrementer_event;
74 
75 };
76 
77 INLINE_CPU\
78 (cpu *)
cpu_create(psim * system,core * memory,cpu_mon * monitor,os_emul * os_emulation,int cpu_nr)79 cpu_create(psim *system,
80 	   core *memory,
81 	   cpu_mon *monitor,
82 	   os_emul *os_emulation,
83 	   int cpu_nr)
84 {
85   cpu *processor = ZALLOC(cpu);
86 
87   /* create the virtual memory map from the core */
88   processor->physical = memory;
89   processor->virtual = vm_create(memory);
90   processor->instruction_map = vm_create_instruction_map(processor->virtual);
91   processor->data_map = vm_create_data_map(processor->virtual);
92 
93   if (CURRENT_MODEL_ISSUE > 0)
94     processor->model_ptr = model_create (processor);
95 
96   /* link back to core system */
97   processor->system = system;
98   processor->events = psim_event_queue(system);
99   processor->cpu_nr = cpu_nr;
100   processor->monitor = monitor;
101   processor->os_emulation = os_emulation;
102 
103   return processor;
104 }
105 
106 
107 INLINE_CPU\
108 (void)
cpu_init(cpu * processor)109 cpu_init(cpu *processor)
110 {
111   memset(&processor->regs, 0, sizeof(processor->regs));
112   /* vm init is delayed until after the device tree has been init as
113      the devices may further init the cpu */
114   if (CURRENT_MODEL_ISSUE > 0)
115     model_init (processor->model_ptr);
116 }
117 
118 
119 /* find ones way home */
120 
121 INLINE_CPU\
122 (psim *)
cpu_system(cpu * processor)123 cpu_system(cpu *processor)
124 {
125   return processor->system;
126 }
127 
128 INLINE_CPU\
129 (int)
cpu_nr(cpu * processor)130 cpu_nr(cpu *processor)
131 {
132   return processor->cpu_nr;
133 }
134 
135 INLINE_CPU\
136 (cpu_mon *)
cpu_monitor(cpu * processor)137 cpu_monitor(cpu *processor)
138 {
139   return processor->monitor;
140 }
141 
142 INLINE_CPU\
143 (os_emul *)
cpu_os_emulation(cpu * processor)144 cpu_os_emulation(cpu *processor)
145 {
146   return processor->os_emulation;
147 }
148 
149 INLINE_CPU\
150 (model_data *)
cpu_model(cpu * processor)151 cpu_model(cpu *processor)
152 {
153   return processor->model_ptr;
154 }
155 
156 
157 /* program counter manipulation */
158 
159 INLINE_CPU\
160 (void)
cpu_set_program_counter(cpu * processor,unsigned_word new_program_counter)161 cpu_set_program_counter(cpu *processor,
162 			unsigned_word new_program_counter)
163 {
164   processor->program_counter = new_program_counter;
165 }
166 
167 INLINE_CPU\
168 (unsigned_word)
cpu_get_program_counter(cpu * processor)169 cpu_get_program_counter(cpu *processor)
170 {
171   return processor->program_counter;
172 }
173 
174 
175 INLINE_CPU\
176 (void)
cpu_restart(cpu * processor,unsigned_word nia)177 cpu_restart(cpu *processor,
178 	    unsigned_word nia)
179 {
180   ASSERT(processor != NULL);
181   cpu_set_program_counter(processor, nia);
182   psim_restart(processor->system, processor->cpu_nr);
183 }
184 
185 INLINE_CPU\
186 (void)
cpu_halt(cpu * processor,unsigned_word nia,stop_reason reason,int signal)187 cpu_halt(cpu *processor,
188 	 unsigned_word nia,
189 	 stop_reason reason,
190 	 int signal)
191 {
192   ASSERT(processor != NULL);
193   if (CURRENT_MODEL_ISSUE > 0)
194     model_halt(processor->model_ptr);
195   cpu_set_program_counter(processor, nia);
196   psim_halt(processor->system, processor->cpu_nr, reason, signal);
197 }
198 
199 EXTERN_CPU\
200 (void)
cpu_error(cpu * processor,unsigned_word cia,const char * fmt,...)201 cpu_error(cpu *processor,
202 	  unsigned_word cia,
203 	  const char *fmt,
204 	  ...)
205 {
206   char message[1024];
207   va_list ap;
208 
209   /* format the message */
210   va_start(ap, fmt);
211   vsprintf(message, fmt, ap);
212   va_end(ap);
213 
214   /* sanity check */
215   if (strlen(message) >= sizeof(message))
216     error("cpu_error: buffer overflow");
217 
218   if (processor != NULL) {
219     printf_filtered("cpu %d, cia 0x%lx: %s\n",
220 		    processor->cpu_nr + 1, (unsigned long)cia, message);
221     cpu_halt(processor, cia, was_signalled, -1);
222   }
223   else {
224     error("cpu: %s", message);
225   }
226 }
227 
228 
229 /* The processors local concept of time */
230 
231 INLINE_CPU\
232 (int64_t)
cpu_get_time_base(cpu * processor)233 cpu_get_time_base(cpu *processor)
234 {
235   return (event_queue_time(processor->events)
236 	  - processor->time_base_local_time);
237 }
238 
239 INLINE_CPU\
240 (void)
cpu_set_time_base(cpu * processor,int64_t time_base)241 cpu_set_time_base(cpu *processor,
242 		  int64_t time_base)
243 {
244   processor->time_base_local_time = (event_queue_time(processor->events)
245 				     - time_base);
246 }
247 
248 INLINE_CPU\
249 (int32_t)
cpu_get_decrementer(cpu * processor)250 cpu_get_decrementer(cpu *processor)
251 {
252   return (processor->decrementer_local_time
253 	  - event_queue_time(processor->events));
254 }
255 
256 STATIC_INLINE_CPU\
257 (void)
cpu_decrement_event(void * data)258 cpu_decrement_event(void *data)
259 {
260   cpu *processor = (cpu*)data;
261   processor->decrementer_event = NULL;
262   decrementer_interrupt(processor);
263 }
264 
265 INLINE_CPU\
266 (void)
cpu_set_decrementer(cpu * processor,int32_t decrementer)267 cpu_set_decrementer(cpu *processor,
268 		    int32_t decrementer)
269 {
270   int64_t old_decrementer = cpu_get_decrementer(processor);
271   event_queue_deschedule(processor->events, processor->decrementer_event);
272   processor->decrementer_event = NULL;
273   processor->decrementer_local_time = (event_queue_time(processor->events)
274 				       + decrementer);
275   if (decrementer < 0 && old_decrementer >= 0)
276     /* A decrementer interrupt occures if the sign of the decrement
277        register is changed from positive to negative by the load
278        instruction */
279     decrementer_interrupt(processor);
280   else if (decrementer >= 0)
281     processor->decrementer_event = event_queue_schedule(processor->events,
282 							decrementer,
283 							cpu_decrement_event,
284 							processor);
285 }
286 
287 
288 #if WITH_IDECODE_CACHE_SIZE
289 /* allow access to the cpu's instruction cache */
290 INLINE_CPU\
291 (idecode_cache *)
cpu_icache_entry(cpu * processor,unsigned_word cia)292 cpu_icache_entry(cpu *processor,
293 		 unsigned_word cia)
294 {
295   return &processor->icache[cia / 4 % WITH_IDECODE_CACHE_SIZE];
296 }
297 
298 
299 INLINE_CPU\
300 (void)
cpu_flush_icache(cpu * processor)301 cpu_flush_icache(cpu *processor)
302 {
303   int i;
304   /* force all addresses to 0xff... so that they never hit */
305   for (i = 0; i < WITH_IDECODE_CACHE_SIZE; i++)
306     processor->icache[i].address = MASK(0, 63);
307 }
308 #endif
309 
310 
311 /* address map revelation */
312 
313 INLINE_CPU\
314 (vm_instruction_map *)
cpu_instruction_map(cpu * processor)315 cpu_instruction_map(cpu *processor)
316 {
317   return processor->instruction_map;
318 }
319 
320 INLINE_CPU\
321 (vm_data_map *)
cpu_data_map(cpu * processor)322 cpu_data_map(cpu *processor)
323 {
324   return processor->data_map;
325 }
326 
327 INLINE_CPU\
328 (void)
cpu_page_tlb_invalidate_entry(cpu * processor,unsigned_word ea)329 cpu_page_tlb_invalidate_entry(cpu *processor,
330 			      unsigned_word ea)
331 {
332   vm_page_tlb_invalidate_entry(processor->virtual, ea);
333 }
334 
335 INLINE_CPU\
336 (void)
cpu_page_tlb_invalidate_all(cpu * processor)337 cpu_page_tlb_invalidate_all(cpu *processor)
338 {
339   vm_page_tlb_invalidate_all(processor->virtual);
340 }
341 
342 
343 /* interrupt access */
344 
345 INLINE_CPU\
346 (interrupts *)
cpu_interrupts(cpu * processor)347 cpu_interrupts(cpu *processor)
348 {
349   return &processor->ints;
350 }
351 
352 
353 
354 /* reservation access */
355 
356 INLINE_CPU\
357 (memory_reservation *)
cpu_reservation(cpu * processor)358 cpu_reservation(cpu *processor)
359 {
360   return &processor->reservation;
361 }
362 
363 
364 /* register access */
365 
366 INLINE_CPU\
367 (registers *)
cpu_registers(cpu * processor)368 cpu_registers(cpu *processor)
369 {
370   return &processor->regs;
371 }
372 
373 INLINE_CPU\
374 (void)
cpu_synchronize_context(cpu * processor,unsigned_word cia)375 cpu_synchronize_context(cpu *processor,
376 			unsigned_word cia)
377 {
378 #if (WITH_IDECODE_CACHE_SIZE)
379   /* kill of the cache */
380   cpu_flush_icache(processor);
381 #endif
382 
383   /* update virtual memory */
384   vm_synchronize_context(processor->virtual,
385 			 processor->regs.spr,
386 			 processor->regs.sr,
387 			 processor->regs.msr,
388 			 processor, cia);
389 }
390 
391 
392 /* might again be useful one day */
393 
394 INLINE_CPU\
395 (void)
cpu_print_info(cpu * processor,int verbose)396 cpu_print_info(cpu *processor, int verbose)
397 {
398 }
399 
400 #endif /* _CPU_C_ */
401