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