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 38 struct _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 81 INLINE_CPU\ 82 (cpu *) 83 cpu_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 111 INLINE_CPU\ 112 (void) 113 cpu_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 125 INLINE_CPU\ 126 (psim *) 127 cpu_system(cpu *processor) 128 { 129 return processor->system; 130 } 131 132 INLINE_CPU\ 133 (int) 134 cpu_nr(cpu *processor) 135 { 136 return processor->cpu_nr; 137 } 138 139 INLINE_CPU\ 140 (cpu_mon *) 141 cpu_monitor(cpu *processor) 142 { 143 return processor->monitor; 144 } 145 146 INLINE_CPU\ 147 (os_emul *) 148 cpu_os_emulation(cpu *processor) 149 { 150 return processor->os_emulation; 151 } 152 153 INLINE_CPU\ 154 (model_data *) 155 cpu_model(cpu *processor) 156 { 157 return processor->model_ptr; 158 } 159 160 161 /* program counter manipulation */ 162 163 INLINE_CPU\ 164 (void) 165 cpu_set_program_counter(cpu *processor, 166 unsigned_word new_program_counter) 167 { 168 processor->program_counter = new_program_counter; 169 } 170 171 INLINE_CPU\ 172 (unsigned_word) 173 cpu_get_program_counter(cpu *processor) 174 { 175 return processor->program_counter; 176 } 177 178 179 INLINE_CPU\ 180 (void) 181 cpu_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 189 INLINE_CPU\ 190 (void) 191 cpu_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 203 EXTERN_CPU\ 204 (void) 205 cpu_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 235 INLINE_CPU\ 236 (signed64) 237 cpu_get_time_base(cpu *processor) 238 { 239 return (event_queue_time(processor->events) 240 - processor->time_base_local_time); 241 } 242 243 INLINE_CPU\ 244 (void) 245 cpu_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 252 INLINE_CPU\ 253 (signed32) 254 cpu_get_decrementer(cpu *processor) 255 { 256 return (processor->decrementer_local_time 257 - event_queue_time(processor->events)); 258 } 259 260 STATIC_INLINE_CPU\ 261 (void) 262 cpu_decrement_event(void *data) 263 { 264 cpu *processor = (cpu*)data; 265 processor->decrementer_event = NULL; 266 decrementer_interrupt(processor); 267 } 268 269 INLINE_CPU\ 270 (void) 271 cpu_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 */ 294 INLINE_CPU\ 295 (idecode_cache *) 296 cpu_icache_entry(cpu *processor, 297 unsigned_word cia) 298 { 299 return &processor->icache[cia / 4 % WITH_IDECODE_CACHE_SIZE]; 300 } 301 302 303 INLINE_CPU\ 304 (void) 305 cpu_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 317 INLINE_CPU\ 318 (vm_instruction_map *) 319 cpu_instruction_map(cpu *processor) 320 { 321 return processor->instruction_map; 322 } 323 324 INLINE_CPU\ 325 (vm_data_map *) 326 cpu_data_map(cpu *processor) 327 { 328 return processor->data_map; 329 } 330 331 INLINE_CPU\ 332 (void) 333 cpu_page_tlb_invalidate_entry(cpu *processor, 334 unsigned_word ea) 335 { 336 vm_page_tlb_invalidate_entry(processor->virtual, ea); 337 } 338 339 INLINE_CPU\ 340 (void) 341 cpu_page_tlb_invalidate_all(cpu *processor) 342 { 343 vm_page_tlb_invalidate_all(processor->virtual); 344 } 345 346 347 /* interrupt access */ 348 349 INLINE_CPU\ 350 (interrupts *) 351 cpu_interrupts(cpu *processor) 352 { 353 return &processor->ints; 354 } 355 356 357 358 /* reservation access */ 359 360 INLINE_CPU\ 361 (memory_reservation *) 362 cpu_reservation(cpu *processor) 363 { 364 return &processor->reservation; 365 } 366 367 368 /* register access */ 369 370 INLINE_CPU\ 371 (registers *) 372 cpu_registers(cpu *processor) 373 { 374 return &processor->regs; 375 } 376 377 INLINE_CPU\ 378 (void) 379 cpu_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 398 INLINE_CPU\ 399 (void) 400 cpu_print_info(cpu *processor, int verbose) 401 { 402 } 403 404 #endif /* _CPU_C_ */ 405