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