예제 #1
0
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);
    }
}
예제 #6
0
/* 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;
}