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