Delete old functional_unit support; Add --enable-sim-model-issue; Monitor branch...
[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 CPU model information */
66   model_data *model_ptr;
67
68 #if WITH_IDECODE_CACHE_SIZE
69   /* a cache to store cracked instructions */
70   idecode_cache icache[WITH_IDECODE_CACHE_SIZE];
71 #endif
72
73   /* address reservation: keep the physical address and the contents
74      of memory at that address */
75   memory_reservation reservation;
76
77   /* offset from event time to this cpu's idea of the local time */
78   signed64 time_base_local_time;
79   signed64 decrementer_local_time;
80   event_entry_tag decrementer_event;
81
82 };
83
84
85 INLINE_CPU cpu *
86 cpu_create(psim *system,
87            core *memory,
88            event_queue *events,
89            cpu_mon *monitor,
90            int cpu_nr)
91 {
92   cpu *processor = ZALLOC(cpu);
93
94   /* create the virtual memory map from the core */
95   processor->physical = memory;
96   processor->virtual = vm_create(memory);
97   processor->instruction_map = vm_create_instruction_map(processor->virtual);
98   processor->data_map = vm_create_data_map(processor->virtual);
99   processor->model_ptr = model_create (processor);
100
101   /* link back to core system */
102   processor->system = system;
103   processor->events = events;
104   processor->cpu_nr = cpu_nr;
105   processor->monitor = monitor;
106
107   return processor;
108 }
109
110
111 INLINE_CPU void
112 cpu_init(cpu *processor)
113 {
114   memset(&processor->regs, 0, sizeof(processor->regs));
115   /* FIXME - should any of VM be inited also ? */
116
117   model_init (processor, processor->model_ptr);
118 }
119
120
121 /* find ones way home */
122
123 INLINE_CPU psim *
124 cpu_system(cpu *processor)
125 {
126   return processor->system;
127 }
128
129 INLINE_CPU int
130 cpu_nr(cpu *processor)
131 {
132   return processor->cpu_nr;
133 }
134
135 INLINE_CPU event_queue *
136 cpu_event_queue(cpu *processor)
137 {
138   return processor->events;
139 }
140
141 INLINE_CPU cpu_mon *
142 cpu_monitor(cpu *processor)
143 {
144   return processor->monitor;
145 }
146
147 INLINE_CPU model_data *
148 cpu_model(cpu *processor)
149 {
150   return processor->model_ptr;
151 }
152
153 /* The processors local concept of time */
154
155 INLINE_CPU signed64
156 cpu_get_time_base(cpu *processor)
157 {
158   return (event_queue_time(processor->events)
159           - processor->time_base_local_time);
160 }
161
162 INLINE_CPU void
163 cpu_set_time_base(cpu *processor,
164                   signed64 time_base)
165 {
166   processor->time_base_local_time = (event_queue_time(processor->events)
167                                      - time_base);
168 }
169
170 INLINE_CPU signed32
171 cpu_get_decrementer(cpu *processor)
172 {
173   return (processor->decrementer_local_time
174           - event_queue_time(processor->events));
175 }
176
177 STATIC_INLINE_CPU void
178 cpu_decrement_event(event_queue *queue,
179                     void *data)
180 {
181   cpu *processor = (cpu*)data;
182   if (!decrementer_interrupt(processor)) {
183     processor->decrementer_event = event_queue_schedule(processor->events,
184                                                         1, /* NOW! */
185                                                         cpu_decrement_event,
186                                                         processor);
187   }
188 }
189
190 INLINE_CPU void
191 cpu_set_decrementer(cpu *processor,
192                     signed32 decrementer)
193 {
194   signed64 old_decrementer = (processor->decrementer_local_time
195                               - event_queue_time(processor->events));
196   event_queue_deschedule(processor->events, processor->decrementer_event);
197   processor->decrementer_local_time = (event_queue_time(processor->events)
198                                        + decrementer);
199   if (decrementer < 0 && old_decrementer >= 0)
200     /* dec interrupt occures if the sign of the decrement reg is
201        changed by the load operation */
202     processor->decrementer_event = event_queue_schedule(processor->events,
203                                                         1, /* NOW! */
204                                                         cpu_decrement_event,
205                                                         processor);
206   else if (decrementer >= 0)
207     processor->decrementer_event = event_queue_schedule(processor->events,
208                                                         decrementer,
209                                                         cpu_decrement_event,
210                                                         processor);
211 }
212
213
214 /* program counter manipulation */
215
216 INLINE_CPU void
217 cpu_set_program_counter(cpu *processor,
218                         unsigned_word new_program_counter)
219 {
220   processor->program_counter = new_program_counter;
221 }
222
223 INLINE_CPU unsigned_word
224 cpu_get_program_counter(cpu *processor)
225 {
226   return processor->program_counter;
227 }
228
229 INLINE_CPU void
230 cpu_restart(cpu *processor,
231             unsigned_word nia)
232 {
233   processor->program_counter = nia;
234   psim_restart(processor->system, processor->cpu_nr);
235 }
236
237 INLINE_CPU void
238 cpu_halt(cpu *processor,
239          unsigned_word cia,
240          stop_reason reason,
241          int signal)
242 {
243   if (processor == NULL) {
244     error("cpu_halt() processor=NULL, cia=0x%x, reason=%d, signal=%d\n",
245           cia,
246           reason,
247           signal);
248   }
249   else {
250     model_halt(processor, processor->model_ptr);
251     processor->program_counter = cia;
252     psim_halt(processor->system, processor->cpu_nr, cia, reason, signal);
253   }
254 }
255
256
257 #if WITH_IDECODE_CACHE_SIZE
258 /* allow access to the cpu's instruction cache */
259 INLINE_CPU idecode_cache *
260 cpu_icache_entry(cpu *processor,
261                  unsigned_word cia)
262 {
263   return &processor->icache[cia / 4 % WITH_IDECODE_CACHE_SIZE];
264 }
265
266
267 INLINE_CPU void
268 cpu_flush_icache(cpu *processor)
269 {
270   int i;
271   /* force all addresses to 0xff... so that they never hit */
272   for (i = 0; i < WITH_IDECODE_CACHE_SIZE; i++)
273     processor->icache[i].address = MASK(0, 63);
274 }
275 #endif
276
277
278 /* address map revelation */
279
280 INLINE_CPU vm_instruction_map *
281 cpu_instruction_map(cpu *processor)
282 {
283   return processor->instruction_map;
284 }
285
286 INLINE_CPU vm_data_map *
287 cpu_data_map(cpu *processor)
288 {
289   return processor->data_map;
290 }
291
292
293 /* reservation access */
294
295 INLINE_CPU memory_reservation *
296 cpu_reservation(cpu *processor)
297 {
298   return &processor->reservation;
299 }
300
301
302 /* register access */
303
304 INLINE_CPU registers *
305 cpu_registers(cpu *processor)
306 {
307   return &processor->regs;
308 }
309
310 INLINE_CPU void
311 cpu_synchronize_context(cpu *processor)
312 {
313 #if (WITH_IDECODE_CACHE)
314   /* kill of the cache */
315   cpu_flush_icache(processor);
316 #endif
317
318   /* update virtual memory */
319   vm_synchronize_context(processor->virtual,
320                          processor->regs.spr,
321                          processor->regs.sr,
322                          processor->regs.msr);
323 }
324
325
326 /* might again be useful one day */
327
328 INLINE_CPU void
329 cpu_print_info(cpu *processor, int verbose)
330 {
331 }
332
333 #endif /* _CPU_C_ */