- const device *stack_device = device_tree_find_device(system->devices,
- "/init/stack");
- unsigned_word stack_pointer;
- psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
- stack_device->callback->ioctl(stack_device,
- system,
- NULL, /*cpu*/
- 0, /*cia*/
- stack_pointer,
- argv,
- envp);
-}
-
-
-
-/* EXECUTE REAL CODE:
-
- Unfortunatly, there are multiple cases to consider vis:
-
- <icache> X <smp> X <events> X <keep-running-flag> X ...
-
- Consequently this function is written in multiple different ways */
-
-STATIC_INLINE_PSIM void
-run_until_stop(psim *system,
- volatile int *keep_running)
-{
- jmp_buf halt;
- jmp_buf restart;
- int cpu_nr;
-#if WITH_IDECODE_CACHE_SIZE
- for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
- cpu_flush_icache(system->processors[cpu_nr]);
-#endif
- psim_set_halt_and_restart(system, &halt, &restart);
-
-#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
-
- /* CASE 1: No instruction cache and no SMP.
-
- In this case, we can take advantage of the fact that the current
- instruction address does not need to be returned to the cpu
- object after every execution of an instruction. Instead it only
- needs to be saved when either A. the main loop exits or B. a
- cpu-{halt,restart} call forces the loop to be re-entered. The
- later functions always save the current cpu instruction
- address. */
-
- if (!setjmp(halt)) {
- do {
- if (!setjmp(restart)) {
- cpu *const processor = system->processors[0];
- unsigned_word cia = cpu_get_program_counter(processor);
- do {
- if (WITH_EVENTS) {
- if (event_queue_tick(system->events)) {
- cpu_set_program_counter(processor, cia);
- event_queue_process(system->events);
- cia = cpu_get_program_counter(processor);
- }
- }
- {
- instruction_word const instruction
- = vm_instruction_map_read(cpu_instruction_map(processor),
- processor, cia);
- cia = idecode_issue(processor, instruction, cia);
- }
- } while (keep_running == NULL || *keep_running);
- cpu_set_program_counter(processor, cia);
- }
- } while(keep_running == NULL || *keep_running);
- }
-#endif
-
-
-#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
-
- /* CASE 2: Instruction case but no SMP
-
- Here, the additional complexity comes from there being two
- different cache implementations. A simple function address cache
- or a full cracked instruction cache */
-
- if (!setjmp(halt)) {
- do {
- if (!setjmp(restart)) {
- cpu *const processor = system->processors[0];
- unsigned_word cia = cpu_get_program_counter(processor);
- do {
- if (WITH_EVENTS)
- if (event_queue_tick(system->events)) {
- cpu_set_program_counter(processor, cia);
- event_queue_process(system->events);
- cia = cpu_get_program_counter(processor);
- }
- {
- idecode_cache *const cache_entry = cpu_icache_entry(processor,
- cia);
- if (cache_entry->address == cia) {
- idecode_semantic *const semantic = cache_entry->semantic;
- cia = semantic(processor, cache_entry, cia);
- }
- else {
- instruction_word const instruction
- = vm_instruction_map_read(cpu_instruction_map(processor),
- processor,
- cia);
- idecode_semantic *const semantic = idecode(processor,
- instruction,
- cia,
- cache_entry);
- cache_entry->address = cia;
- cache_entry->semantic = semantic;
- cia = semantic(processor, cache_entry, cia);
- }
- }
- } while (keep_running == NULL || *keep_running);
- cpu_set_program_counter(processor, cia);
- }
- } while(keep_running == NULL || *keep_running);
- }
-#endif
-
-
-#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
-
- /* CASE 3: No ICACHE but SMP
-
- The complexity here comes from needing to correctly restart the
- system when it is aborted. In particular if cpu0 requests a
- restart, the next cpu is still cpu1. Cpu0 being restarted after
- all the other CPU's and the event queue have been processed */
-
- if (!setjmp(halt)) {
- int first_cpu = setjmp(restart);
- if (first_cpu == 0)
- first_cpu = system->last_cpu + 1;
- do {
- int current_cpu;
- for (current_cpu = first_cpu, first_cpu = 0;
- current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
- current_cpu++) {
- if (WITH_EVENTS && current_cpu == system->nr_cpus) {
- if (event_queue_tick(system->events))
- event_queue_process(system->events);
- }
- else {
- cpu *const processor = system->processors[current_cpu];
- unsigned_word const cia = cpu_get_program_counter(processor);
- instruction_word instruction =
- vm_instruction_map_read(cpu_instruction_map(processor),
- processor,
- cia);
- cpu_set_program_counter(processor,
- idecode_issue(processor, instruction, cia));
- }
- if (!(keep_running == NULL || *keep_running)) {
- system->last_cpu = current_cpu;
- break;
- }
- }
- } while (keep_running == NULL || *keep_running);
- }
-#endif
-
-#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
-
- /* CASE 4: ICACHE and SMP ...
-
- This time, everything goes wrong. Need to restart loops
- correctly, need to save the program counter and finally need to
- keep track of each processors current address! */
-
- if (!setjmp(halt)) {
- int first_cpu = setjmp(restart);
- if (!first_cpu)
- first_cpu = system->last_cpu + 1;
- do {
- int current_cpu;
- for (current_cpu = first_cpu, first_cpu = 0;
- current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
- current_cpu++) {
- if (WITH_EVENTS && current_cpu == system->nr_cpus) {
- if (event_queue_tick(system->events))
- event_queue_process(system->events);
- }
- else {
- cpu *processor = system->processors[current_cpu];
- unsigned_word const cia = cpu_get_program_counter(processor);
- idecode_cache *cache_entry = cpu_icache_entry(processor, cia);
- if (cache_entry->address == cia) {
- idecode_semantic *semantic = cache_entry->semantic;
- cpu_set_program_counter(processor,
- semantic(processor, cache_entry, cia));
- }
- else {
- instruction_word instruction =
- vm_instruction_map_read(cpu_instruction_map(processor),
- processor,
- cia);
- idecode_semantic *semantic = idecode(processor,
- instruction,
- cia,
- cache_entry);
- cache_entry->address = cia;
- cache_entry->semantic = semantic;
- cpu_set_program_counter(processor,
- semantic(processor, cache_entry, cia));
- }
- }
- if (!(keep_running == NULL || *keep_running))
- break;
- }
- } while (keep_running == NULL || *keep_running);