void interrupts_info (SIM_DESC sd, struct interrupts *interrupts) { signed64 t; sim_io_printf (sd, "Interrupts Info:\n"); sim_io_printf (sd, " Interrupts raised: %lu\n", interrupts->nb_interrupts_raised); if (interrupts->start_mask_cycle >= 0) { t = cpu_current_cycle (interrupts->cpu); t -= interrupts->start_mask_cycle; if (t > interrupts->max_mask_cycles) interrupts->max_mask_cycles = t; sim_io_printf (sd, " Current interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); } t = interrupts->min_mask_cycles == CYCLES_MAX ? interrupts->max_mask_cycles : interrupts->min_mask_cycles; sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->max_mask_cycles; sim_io_printf (sd, " Longest interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->last_mask_cycles; sim_io_printf (sd, " Last interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); if (interrupts->xirq_start_mask_cycle >= 0) { t = cpu_current_cycle (interrupts->cpu); t -= interrupts->xirq_start_mask_cycle; if (t > interrupts->xirq_max_mask_cycles) interrupts->xirq_max_mask_cycles = t; sim_io_printf (sd, " XIRQ Current interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); } t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ? interrupts->xirq_max_mask_cycles : interrupts->xirq_min_mask_cycles; sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->xirq_max_mask_cycles; sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->xirq_last_mask_cycles; sim_io_printf (sd, " XIRQ Last interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); }
static unsigned m68hc11eepr_io_write_buffer (struct hw *me, const void *source, int space, unsigned_word base, unsigned nr_bytes) { SIM_DESC sd; struct m68hc11eepr *controller; sim_cpu *cpu; uint8 val; HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); sd = hw_system (me); controller = hw_data (me); cpu = STATE_CPU (sd, 0); /* Programming several bytes at a time is not possible. */ if (space != io_map && nr_bytes != 1) { sim_memory_error (cpu, SIM_SIGBUS, base, "EEprom write error (only 1 byte can be programmed)"); return 0; } if (nr_bytes != 1) hw_abort (me, "Cannot write more than 1 byte to EEPROM device at a time"); val = *((const uint8*) source); /* Write to the EEPROM control register. */ if (space == io_map && base == M6811_PPROG) { uint8 wrong_bits; uint16 addr; addr = base + cpu_get_io_base (cpu); /* Setting EELAT and EEPGM at the same time is an error. Clearing them both is ok. */ wrong_bits = (cpu->ios[M6811_PPROG] ^ val) & val; wrong_bits &= (M6811_EELAT | M6811_EEPGM); if (wrong_bits == (M6811_EEPGM|M6811_EELAT)) { sim_memory_error (cpu, SIM_SIGBUS, addr, "Wrong eeprom programing value"); return 0; } if ((val & M6811_EELAT) == 0) { val = 0; } if ((val & M6811_EEPGM) && !(cpu->ios[M6811_PPROG] & M6811_EELAT)) { sim_memory_error (cpu, SIM_SIGBUS, addr, "EEProm high voltage applied after EELAT"); } if ((val & M6811_EEPGM) && controller->eeprom_wmode == 0) { sim_memory_error (cpu, SIM_SIGSEGV, addr, "EEProm high voltage applied without address"); } if (val & M6811_EEPGM) { controller->eeprom_wcycle = cpu_current_cycle (cpu); } else if (cpu->ios[M6811_PPROG] & M6811_PPROG) { int i; unsigned long t = cpu_current_cycle (cpu); t -= controller->eeprom_wcycle; if (t < controller->eeprom_min_cycles) { sim_memory_error (cpu, SIM_SIGILL, addr, "EEprom programmed only for %lu cycles", t); } /* Program the byte by clearing some bits. */ if (!(cpu->ios[M6811_PPROG] & M6811_ERASE)) { controller->eeprom[controller->eeprom_waddr] &= controller->eeprom_wbyte; } /* Erase a byte, row or the complete eeprom. Erased value is 0xFF. Ignore row or complete eeprom erase when we are programming the CONFIG register (last EEPROM byte). */ else if ((cpu->ios[M6811_PPROG] & M6811_BYTE) || controller->eeprom_waddr == controller->size - 1) { controller->eeprom[controller->eeprom_waddr] = 0xff; } else if (cpu->ios[M6811_BYTE] & M6811_ROW) { size_t max_size; /* Size of EEPROM (-1 because the last byte is the CONFIG register. */ max_size = controller->size; controller->eeprom_waddr &= 0xFFF0; for (i = 0; i < 16 && controller->eeprom_waddr < max_size; i++) { controller->eeprom[controller->eeprom_waddr] = 0xff; controller->eeprom_waddr ++; } } else { size_t max_size; max_size = controller->size; for (i = 0; i < max_size; i++) { controller->eeprom[i] = 0xff; } } /* Save the eeprom in a file. We have to save after each change because the simulator can be stopped or crash... */ if (m6811eepr_memory_rw (controller, O_WRONLY | O_CREAT) != 0) { sim_memory_error (cpu, SIM_SIGABRT, addr, "EEPROM programing failed: errno=%d", errno); } controller->eeprom_wmode = 0; } cpu->ios[M6811_PPROG] = val; return 1; } /* The CONFIG IO register is mapped at end of EEPROM. It's not visible. */ if (space == io_map && base == M6811_CONFIG) { base = controller->size - 1; } else { base = base - controller->base_address; } /* Writing the memory is allowed for the Debugger or simulator (cpu not running). */ if (cpu_is_running (cpu)) { if ((cpu->ios[M6811_PPROG] & M6811_EELAT) == 0) { sim_memory_error (cpu, SIM_SIGSEGV, base, "EEprom not configured for writing"); return 0; } if (controller->eeprom_wmode != 0) { sim_memory_error (cpu, SIM_SIGSEGV, base, "EEprom write error"); return 0; } controller->eeprom_wmode = 1; controller->eeprom_waddr = base; controller->eeprom_wbyte = val; } else { controller->eeprom[base] = val; m6811eepr_memory_rw (controller, O_WRONLY); } return 1; }
void interrupts_info (SIM_DESC sd, struct interrupts *interrupts) { signed64 t, prev_interrupt; int i; sim_io_printf (sd, "Interrupts Info:\n"); sim_io_printf (sd, " Interrupts raised: %lu\n", interrupts->nb_interrupts_raised); if (interrupts->start_mask_cycle >= 0) { t = cpu_current_cycle (interrupts->cpu); t -= interrupts->start_mask_cycle; if (t > interrupts->max_mask_cycles) interrupts->max_mask_cycles = t; sim_io_printf (sd, " Current interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); } t = interrupts->min_mask_cycles == CYCLES_MAX ? interrupts->max_mask_cycles : interrupts->min_mask_cycles; sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); t = interrupts->max_mask_cycles; sim_io_printf (sd, " Longest interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); t = interrupts->last_mask_cycles; sim_io_printf (sd, " Last interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); if (interrupts->xirq_start_mask_cycle >= 0) { t = cpu_current_cycle (interrupts->cpu); t -= interrupts->xirq_start_mask_cycle; if (t > interrupts->xirq_max_mask_cycles) interrupts->xirq_max_mask_cycles = t; sim_io_printf (sd, " XIRQ Current interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); } t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ? interrupts->xirq_max_mask_cycles : interrupts->xirq_min_mask_cycles; sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); t = interrupts->xirq_max_mask_cycles; sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); t = interrupts->xirq_last_mask_cycles; sim_io_printf (sd, " XIRQ Last interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t, PRINT_TIME | PRINT_CYCLE)); if (interrupts->pending_mask) { sim_io_printf (sd, " Pending interrupts : "); for (i = 0; i < M6811_INT_NUMBER; i++) { enum M6811_INT int_number = interrupts->interrupt_order[i]; if (interrupts->pending_mask & (1 << int_number)) { sim_io_printf (sd, "%s ", interrupt_names[int_number]); } } sim_io_printf (sd, "\n"); } prev_interrupt = 0; sim_io_printf (sd, "N Interrupt Cycle Taken Latency" " Delta between interrupts\n"); for (i = 0; i < MAX_INT_HISTORY; i++) { int which; struct interrupt_history *h; signed64 dt; which = interrupts->history_index - i - 1; if (which < 0) which += MAX_INT_HISTORY; h = &interrupts->interrupts_history[which]; if (h->taken_cycle == 0) break; dt = h->taken_cycle - h->raised_cycle; sim_io_printf (sd, "%2d %-9.9s %15.15s ", i, interrupt_names[h->type], cycle_to_string (interrupts->cpu, h->taken_cycle, 0)); sim_io_printf (sd, "%15.15s", cycle_to_string (interrupts->cpu, dt, 0)); if (prev_interrupt) { dt = prev_interrupt - h->taken_cycle; sim_io_printf (sd, " %s", cycle_to_string (interrupts->cpu, dt, PRINT_TIME)); } sim_io_printf (sd, "\n"); prev_interrupt = h->taken_cycle; } }
/* Process the current interrupt if there is one. This operation must be called after each instruction to handle the interrupts. If interrupts are masked, it does nothing. */ int interrupts_process (struct interrupts *interrupts) { int id; uint8 ccr; /* See if interrupts are enabled/disabled and keep track of the number of cycles the interrupts are masked. Such information is then reported by the info command. */ ccr = cpu_get_ccr (interrupts->cpu); if (ccr & M6811_I_BIT) { if (interrupts->start_mask_cycle < 0) interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->start_mask_cycle >= 0 && (ccr & M6811_I_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->start_mask_cycle; if (t < interrupts->min_mask_cycles) interrupts->min_mask_cycles = t; if (t > interrupts->max_mask_cycles) interrupts->max_mask_cycles = t; interrupts->start_mask_cycle = -1; interrupts->last_mask_cycles = t; } if (ccr & M6811_X_BIT) { if (interrupts->xirq_start_mask_cycle < 0) interrupts->xirq_start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->xirq_start_mask_cycle >= 0 && (ccr & M6811_X_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->xirq_start_mask_cycle; if (t < interrupts->xirq_min_mask_cycles) interrupts->xirq_min_mask_cycles = t; if (t > interrupts->xirq_max_mask_cycles) interrupts->xirq_max_mask_cycles = t; interrupts->xirq_start_mask_cycle = -1; interrupts->xirq_last_mask_cycles = t; } id = interrupts_get_current (interrupts); if (id >= 0) { uint16 addr; struct interrupt_history *h; /* Implement the breakpoint-on-interrupt. */ if (interrupts->interrupts[id].stop_mode & SIM_STOP_WHEN_TAKEN) { sim_io_printf (CPU_STATE (interrupts->cpu), "Interrupt %s will be handled\n", interrupt_names[id]); sim_engine_halt (CPU_STATE (interrupts->cpu), interrupts->cpu, 0, cpu_get_pc (interrupts->cpu), sim_stopped, SIM_SIGTRAP); } cpu_push_all (interrupts->cpu); addr = memory_read16 (interrupts->cpu, interrupts->vectors_addr + id * 2); cpu_call (interrupts->cpu, addr); /* Now, protect from nested interrupts. */ if (id == M6811_INT_XIRQ) { cpu_set_ccr_X (interrupts->cpu, 1); } else { cpu_set_ccr_I (interrupts->cpu, 1); } /* Update the interrupt history table. */ h = &interrupts->interrupts_history[interrupts->history_index]; h->type = id; h->taken_cycle = cpu_current_cycle (interrupts->cpu); h->raised_cycle = interrupts->interrupts[id].cpu_cycle; if (interrupts->history_index >= MAX_INT_HISTORY-1) interrupts->history_index = 0; else interrupts->history_index++; interrupts->nb_interrupts_raised++; cpu_add_cycles (interrupts->cpu, 14); return 1; } return 0; }
/* Update the mask of pending interrupts. This operation must be called when the state of some 68HC11 IO register changes. It looks the different registers that indicate a pending interrupt (timer, SCI, SPI, ...) and records the interrupt if it's there and enabled. */ void interrupts_update_pending (struct interrupts *interrupts) { int i; uint8 *ioregs; unsigned long clear_mask; unsigned long set_mask; clear_mask = 0; set_mask = 0; ioregs = &interrupts->cpu->ios[0]; for (i = 0; i < TableSize(idefs); i++) { struct interrupt_def *idef = &idefs[i]; uint8 data; /* Look if the interrupt is enabled. */ if (idef->enable_paddr) { data = ioregs[idef->enable_paddr]; if (!(data & idef->enabled_mask)) { /* Disable it. */ clear_mask |= (1 << idef->int_number); continue; } } /* Interrupt is enabled, see if it's there. */ data = ioregs[idef->int_paddr]; if (!(data & idef->int_mask)) { /* Disable it. */ clear_mask |= (1 << idef->int_number); continue; } /* Ok, raise it. */ set_mask |= (1 << idef->int_number); } /* Some interrupts are shared (M6811_INT_SCI) so clear the interrupts before setting the new ones. */ interrupts->pending_mask &= ~clear_mask; interrupts->pending_mask |= set_mask; /* Keep track of when the interrupt is raised by the device. Also implements the breakpoint-on-interrupt. */ if (set_mask) { signed64 cycle = cpu_current_cycle (interrupts->cpu); int must_stop = 0; for (i = 0; i < M6811_INT_NUMBER; i++) { if (!(set_mask & (1 << i))) continue; interrupts->interrupts[i].cpu_cycle = cycle; if (interrupts->interrupts[i].stop_mode & SIM_STOP_WHEN_RAISED) { must_stop = 1; sim_io_printf (CPU_STATE (interrupts->cpu), "Interrupt %s raised\n", interrupt_names[i]); } } if (must_stop) sim_engine_halt (CPU_STATE (interrupts->cpu), interrupts->cpu, 0, cpu_get_pc (interrupts->cpu), sim_stopped, SIM_SIGTRAP); } }
/* Process the current interrupt if there is one. This operation must be called after each instruction to handle the interrupts. If interrupts are masked, it does nothing. */ int interrupts_process (struct interrupts *interrupts) { int id; uint8 ccr; /* See if interrupts are enabled/disabled and keep track of the number of cycles the interrupts are masked. Such information is then reported by the info command. */ ccr = cpu_get_ccr (interrupts->cpu); if (ccr & M6811_I_BIT) { if (interrupts->start_mask_cycle < 0) interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->start_mask_cycle >= 0 && (ccr & M6811_I_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->start_mask_cycle; if (t < interrupts->min_mask_cycles) interrupts->min_mask_cycles = t; if (t > interrupts->max_mask_cycles) interrupts->max_mask_cycles = t; interrupts->start_mask_cycle = -1; interrupts->last_mask_cycles = t; } if (ccr & M6811_X_BIT) { if (interrupts->xirq_start_mask_cycle < 0) interrupts->xirq_start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->xirq_start_mask_cycle >= 0 && (ccr & M6811_X_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->xirq_start_mask_cycle; if (t < interrupts->xirq_min_mask_cycles) interrupts->xirq_min_mask_cycles = t; if (t > interrupts->xirq_max_mask_cycles) interrupts->xirq_max_mask_cycles = t; interrupts->xirq_start_mask_cycle = -1; interrupts->xirq_last_mask_cycles = t; } id = interrupts_get_current (interrupts); if (id >= 0) { uint16 addr; cpu_push_all (interrupts->cpu); addr = memory_read16 (interrupts->cpu, interrupts->vectors_addr + id * 2); cpu_call (interrupts->cpu, addr); /* Now, protect from nested interrupts. */ if (id == M6811_INT_XIRQ) { cpu_set_ccr_X (interrupts->cpu, 1); } else { cpu_set_ccr_I (interrupts->cpu, 1); } interrupts->nb_interrupts_raised++; cpu_add_cycles (interrupts->cpu, 14); return 1; } return 0; }