Add # in front of CPU number
[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 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   /* current state of interrupt inputs */
49   int external_exception_pending;
50
51   /* the system this processor is contained within */
52   psim *system;
53   event_queue *events;
54   int cpu_nr;
55
56   /* if required, a cache to store decoded instructions */
57 #if WITH_IDECODE_CACHE
58   idecode_cache icache[IDECODE_CACHE_SIZE];
59 #endif
60
61   /* address reservation: keep the physical address and the contents
62      of memory at that address */
63   memory_reservation reservation;
64
65   /* offset from event time to this cpu's idea of the local time */
66   signed64 time_base_local_time;
67   signed64 decrementer_local_time;
68   event_entry_tag decrementer_event;
69
70   /* Counts of number of instructions executed.  */
71   long number_of_insns;
72 };
73
74
75 INLINE_CPU cpu *
76 cpu_create(psim *system,
77            core *memory,
78            event_queue *events,
79            int cpu_nr)
80 {
81   cpu *processor = ZALLOC(cpu);
82
83   /* create the virtual memory map from the core */
84   processor->physical = memory;
85   processor->virtual = vm_create(memory);
86   processor->instruction_map = vm_create_instruction_map(processor->virtual);
87   processor->data_map = vm_create_data_map(processor->virtual);
88
89   /* link back to core system */
90   processor->system = system;
91   processor->events = events;
92   processor->cpu_nr = cpu_nr;
93
94   return processor;
95 }
96
97
98 /* find ones way home */
99
100 INLINE_CPU psim *
101 cpu_system(cpu *processor)
102 {
103   return processor->system;
104 }
105
106 INLINE_CPU int
107 cpu_nr(cpu *processor)
108 {
109   return processor->cpu_nr;
110 }
111
112 INLINE_CPU event_queue *
113 cpu_event_queue(cpu *processor)
114 {
115   return processor->events;
116 }
117
118
119 /* The processors local concept of time */
120
121 INLINE_CPU signed64
122 cpu_get_time_base(cpu *processor)
123 {
124   return (event_queue_time(processor->events)
125           + processor->time_base_local_time);
126 }
127
128 INLINE_CPU void
129 cpu_set_time_base(cpu *processor,
130                   signed64 time_base)
131 {
132   processor->time_base_local_time = (event_queue_time(processor->events)
133                                      - time_base);
134 }
135
136 INLINE_CPU signed32
137 cpu_get_decrementer(cpu *processor)
138 {
139   return (processor->decrementer_local_time
140           - event_queue_time(processor->events));
141 }
142
143 STATIC_INLINE_CPU void
144 cpu_decrement_event(event_queue *queue,
145                     void *data)
146 {
147   cpu *processor = (cpu*)data;
148   if (!decrementer_interrupt(processor)) {
149     processor->decrementer_event = event_queue_schedule(processor->events,
150                                                         1, /* NOW! */
151                                                         cpu_decrement_event,
152                                                         processor);
153   }
154 }
155
156 INLINE_CPU void
157 cpu_set_decrementer(cpu *processor,
158                     signed32 decrementer)
159 {
160   signed64 old_decrementer = (processor->decrementer_local_time
161                               - event_queue_time(processor->events));
162   event_queue_deschedule(processor->events, processor->decrementer_event);
163   processor->decrementer_local_time = (event_queue_time(processor->events)
164                                        + decrementer);
165   if (decrementer < 0 && old_decrementer >= 0)
166     /* dec interrupt occures if the sign of the decrement reg is
167        changed by the load operation */
168     processor->decrementer_event = event_queue_schedule(processor->events,
169                                                         1, /* NOW! */
170                                                         cpu_decrement_event,
171                                                         processor);
172   else if (decrementer >= 0)
173     processor->decrementer_event = event_queue_schedule(processor->events,
174                                                         decrementer,
175                                                         cpu_decrement_event,
176                                                         processor);
177 }
178
179
180 /* program counter manipulation */
181
182 INLINE_CPU void
183 cpu_set_program_counter(cpu *processor,
184                         unsigned_word new_program_counter)
185 {
186   processor->program_counter = new_program_counter;
187 }
188
189 INLINE_CPU unsigned_word
190 cpu_get_program_counter(cpu *processor)
191 {
192   return processor->program_counter;
193 }
194
195 INLINE_CPU void
196 cpu_restart(cpu *processor,
197             unsigned_word nia)
198 {
199   processor->program_counter = nia;
200   psim_restart(processor->system, processor->cpu_nr);
201 }
202
203 INLINE_CPU void
204 cpu_halt(cpu *processor,
205          unsigned_word cia,
206          stop_reason reason,
207          int signal)
208 {
209   processor->program_counter = cia;
210   psim_halt(processor->system, processor->cpu_nr, cia, reason, signal);
211 }
212
213
214 #if WITH_IDECODE_CACHE
215 /* allow access to the cpu's instruction cache */
216 INLINE_CPU idecode_cache *
217 cpu_icache(cpu *processor)
218 {
219   return processor->icache;
220 }
221 #endif
222
223
224 /* address map revelation */
225
226 INLINE_CPU vm_instruction_map *
227 cpu_instruction_map(cpu *processor)
228 {
229   return processor->instruction_map;
230 }
231
232 INLINE_CPU vm_data_map *
233 cpu_data_map(cpu *processor)
234 {
235   return processor->data_map;
236 }
237
238 INLINE_CPU core *
239 cpu_core(cpu *processor)
240 {
241   return processor->physical;
242 }
243
244
245 /* reservation access */
246
247 INLINE_CPU memory_reservation *
248 cpu_reservation(cpu *processor)
249 {
250   return &processor->reservation;
251 }
252
253
254 /* register access */
255
256 INLINE_CPU registers *
257 cpu_registers(cpu *processor)
258 {
259   return &processor->regs;
260 }
261
262 INLINE_CPU void
263 cpu_synchronize_context(cpu *processor)
264 {
265 #if WITH_IDECODE_CACHE
266   /* kill off the contents of the cache */
267   int i;
268   for (i = 0; i < IDECODE_CACHE_SIZE; i++)
269     processor->icache[i].address = MASK(0,63);
270 #endif
271   vm_synchronize_context(processor->virtual,
272                          processor->regs.spr,
273                          processor->regs.sr,
274                          processor->regs.msr);
275 }
276
277
278 /* # of instructions counter access */
279
280 INLINE_CPU void
281 cpu_increment_number_of_insns(cpu *processor)
282 {
283   processor->number_of_insns++;
284 }
285
286 INLINE_CPU long
287 cpu_get_number_of_insns(cpu *processor)
288 {
289   return processor->number_of_insns;
290 }
291
292 INLINE_CPU void
293 cpu_print_info(cpu *processor, int verbose)
294 {
295   printf_filtered("CPU #%d executed %ld instructions.\n",
296                   processor->cpu_nr+1,
297                   processor->number_of_insns);
298 }
299
300 #endif /* _CPU_C_ */