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