More model specific changes
[external/binutils.git] / sim / ppc / cpu.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1995, 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 2 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, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  
19     */
20
21
22 #ifndef _CPU_C_
23 #define _CPU_C_
24
25 #ifndef STATIC_INLINE_CPU
26 #define STATIC_INLINE_CPU STATIC_INLINE
27 #endif
28
29 #include <setjmp.h>
30
31 #include "cpu.h"
32 #include "idecode.h"
33
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #else
37 #ifdef HAVE_STRINGS_H
38 #include <strings.h>
39 #endif
40 #endif
41
42 struct _cpu {
43
44   /* the registers */
45   registers regs;
46
47   /* current instruction address */
48   unsigned_word program_counter;
49
50   /* the memory maps */
51   core *physical; /* all of memory */
52   vm *virtual;
53   vm_instruction_map *instruction_map; /* instructions */
54   vm_data_map *data_map; /* data */
55
56   /* current state of interrupt inputs */
57   int external_exception_pending;
58
59   /* the system this processor is contained within */
60   cpu_mon *monitor;
61   psim *system;
62   event_queue *events;
63   int cpu_nr;
64
65   /* Current functional unit information */
66   function_unit *func_unit;
67
68   /* Current CPU model information */
69   model_data *model_ptr;
70
71 #if WITH_IDECODE_CACHE_SIZE
72   /* a cache to store cracked instructions */
73   idecode_cache icache[WITH_IDECODE_CACHE_SIZE];
74 #endif
75
76   /* address reservation: keep the physical address and the contents
77      of memory at that address */
78   memory_reservation reservation;
79
80   /* offset from event time to this cpu's idea of the local time */
81   signed64 time_base_local_time;
82   signed64 decrementer_local_time;
83   event_entry_tag decrementer_event;
84
85 };
86
87
88 INLINE_CPU cpu *
89 cpu_create(psim *system,
90            core *memory,
91            event_queue *events,
92            cpu_mon *monitor,
93            int cpu_nr)
94 {
95   cpu *processor = ZALLOC(cpu);
96
97   /* create the virtual memory map from the core */
98   processor->physical = memory;
99   processor->virtual = vm_create(memory);
100   processor->instruction_map = vm_create_instruction_map(processor->virtual);
101   processor->data_map = vm_create_data_map(processor->virtual);
102   processor->model_ptr = model_create (processor);
103
104   /* link back to core system */
105   processor->system = system;
106   processor->events = events;
107   processor->cpu_nr = cpu_nr;
108   processor->monitor = monitor;
109
110   /* Create function unit if desired */
111   if (WITH_FUNCTION_UNIT)
112     processor->func_unit = function_unit_create ();
113
114   return processor;
115 }
116
117
118 INLINE_CPU void
119 cpu_init(cpu *processor)
120 {
121   memset(&processor->regs, 0, sizeof(processor->regs));
122   /* FIXME - should any of VM be inited also ? */
123
124   if (WITH_FUNCTION_UNIT)
125     function_unit_init (processor->func_unit);
126
127   model_init (processor, processor->model_ptr);
128 }
129
130
131 /* find ones way home */
132
133 INLINE_CPU psim *
134 cpu_system(cpu *processor)
135 {
136   return processor->system;
137 }
138
139 INLINE_CPU int
140 cpu_nr(cpu *processor)
141 {
142   return processor->cpu_nr;
143 }
144
145 INLINE_CPU event_queue *
146 cpu_event_queue(cpu *processor)
147 {
148   return processor->events;
149 }
150
151 INLINE_CPU cpu_mon *
152 cpu_monitor(cpu *processor)
153 {
154   return processor->monitor;
155 }
156
157 INLINE_CPU function_unit *
158 cpu_function_unit(cpu *processor)
159 {
160   return processor->func_unit;
161 }
162
163 INLINE_CPU model_data *
164 cpu_model(cpu *processor)
165 {
166   return processor->model_ptr;
167 }
168
169 /* The processors local concept of time */
170
171 INLINE_CPU signed64
172 cpu_get_time_base(cpu *processor)
173 {
174   return (event_queue_time(processor->events)
175           - processor->time_base_local_time);
176 }
177
178 INLINE_CPU void
179 cpu_set_time_base(cpu *processor,
180                   signed64 time_base)
181 {
182   processor->time_base_local_time = (event_queue_time(processor->events)
183                                      - time_base);
184 }
185
186 INLINE_CPU signed32
187 cpu_get_decrementer(cpu *processor)
188 {
189   return (processor->decrementer_local_time
190           - event_queue_time(processor->events));
191 }
192
193 STATIC_INLINE_CPU void
194 cpu_decrement_event(event_queue *queue,
195                     void *data)
196 {
197   cpu *processor = (cpu*)data;
198   if (!decrementer_interrupt(processor)) {
199     processor->decrementer_event = event_queue_schedule(processor->events,
200                                                         1, /* NOW! */
201                                                         cpu_decrement_event,
202                                                         processor);
203   }
204 }
205
206 INLINE_CPU void
207 cpu_set_decrementer(cpu *processor,
208                     signed32 decrementer)
209 {
210   signed64 old_decrementer = (processor->decrementer_local_time
211                               - event_queue_time(processor->events));
212   event_queue_deschedule(processor->events, processor->decrementer_event);
213   processor->decrementer_local_time = (event_queue_time(processor->events)
214                                        + decrementer);
215   if (decrementer < 0 && old_decrementer >= 0)
216     /* dec interrupt occures if the sign of the decrement reg is
217        changed by the load operation */
218     processor->decrementer_event = event_queue_schedule(processor->events,
219                                                         1, /* NOW! */
220                                                         cpu_decrement_event,
221                                                         processor);
222   else if (decrementer >= 0)
223     processor->decrementer_event = event_queue_schedule(processor->events,
224                                                         decrementer,
225                                                         cpu_decrement_event,
226                                                         processor);
227 }
228
229
230 /* program counter manipulation */
231
232 INLINE_CPU void
233 cpu_set_program_counter(cpu *processor,
234                         unsigned_word new_program_counter)
235 {
236   processor->program_counter = new_program_counter;
237 }
238
239 INLINE_CPU unsigned_word
240 cpu_get_program_counter(cpu *processor)
241 {
242   return processor->program_counter;
243 }
244
245 INLINE_CPU void
246 cpu_restart(cpu *processor,
247             unsigned_word nia)
248 {
249   processor->program_counter = nia;
250   psim_restart(processor->system, processor->cpu_nr);
251 }
252
253 INLINE_CPU void
254 cpu_halt(cpu *processor,
255          unsigned_word cia,
256          stop_reason reason,
257          int signal)
258 {
259   if (processor == NULL) {
260     error("cpu_halt() processor=NULL, cia=0x%x, reason=%d, signal=%d\n",
261           cia,
262           reason,
263           signal);
264   }
265   else {
266     if (WITH_FUNCTION_UNIT)
267       function_unit_halt(processor, processor->func_unit);
268
269     model_halt(processor, processor->model_ptr);
270     processor->program_counter = cia;
271     psim_halt(processor->system, processor->cpu_nr, cia, reason, signal);
272   }
273 }
274
275
276 #if WITH_IDECODE_CACHE_SIZE
277 /* allow access to the cpu's instruction cache */
278 INLINE_CPU idecode_cache *
279 cpu_icache_entry(cpu *processor,
280                  unsigned_word cia)
281 {
282   return &processor->icache[cia / 4 % WITH_IDECODE_CACHE_SIZE];
283 }
284
285
286 INLINE_CPU void
287 cpu_flush_icache(cpu *processor)
288 {
289   int i;
290   /* force all addresses to 0xff... so that they never hit */
291   for (i = 0; i < WITH_IDECODE_CACHE_SIZE; i++)
292     processor->icache[i].address = MASK(0, 63);
293 }
294 #endif
295
296
297 /* address map revelation */
298
299 INLINE_CPU vm_instruction_map *
300 cpu_instruction_map(cpu *processor)
301 {
302   return processor->instruction_map;
303 }
304
305 INLINE_CPU vm_data_map *
306 cpu_data_map(cpu *processor)
307 {
308   return processor->data_map;
309 }
310
311
312 /* reservation access */
313
314 INLINE_CPU memory_reservation *
315 cpu_reservation(cpu *processor)
316 {
317   return &processor->reservation;
318 }
319
320
321 /* register access */
322
323 INLINE_CPU registers *
324 cpu_registers(cpu *processor)
325 {
326   return &processor->regs;
327 }
328
329 INLINE_CPU void
330 cpu_synchronize_context(cpu *processor)
331 {
332 #if (WITH_IDECODE_CACHE)
333   /* kill of the cache */
334   cpu_flush_icache(processor);
335 #endif
336
337   /* update virtual memory */
338   vm_synchronize_context(processor->virtual,
339                          processor->regs.spr,
340                          processor->regs.sr,
341                          processor->regs.msr);
342 }
343
344
345 /* might again be useful one day */
346
347 INLINE_CPU void
348 cpu_print_info(cpu *processor, int verbose)
349 {
350 }
351
352 #endif /* _CPU_C_ */