func: static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
  
  {
  
      ARMCPU *cpu;
  
      uint32_t val;
  
      int irq;
  
  
  
      switch (offset) {
  
      case 4: /* Interrupt Control Type.  */
  
          return (s->num_irq / 32) - 1;
  
      case 0x10: /* SysTick Control and Status.  */
  
          val = s->systick.control;
  
          s->systick.control &= ~SYSTICK_COUNTFLAG;
  
          return val;
  
      case 0x14: /* SysTick Reload Value.  */
  
          return s->systick.reload;
  
      case 0x18: /* SysTick Current Value.  */
  
          {
  
              int64_t t;
  
              if ((s->systick.control & SYSTICK_ENABLE) == 0)
  
                  return 0;
  
              t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  
              if (t >= s->systick.tick)
  
                  return 0;
  
              val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
  
              /* The interrupt in triggered when the timer reaches zero.
  
                 However the counter is not reloaded until the next clock
  
                 tick.  This is a hack to return zero during the first tick.  */
  
              if (val > s->systick.reload)
  
                  val = 0;
  
              return val;
  
          }
  
      case 0x1c: /* SysTick Calibration Value.  */
  
          return 10000;
  
      case 0xd00: /* CPUID Base.  */
  
          cpu = ARM_CPU(current_cpu);
  
          return cpu->env.cp15.c0_cpuid;
  
      case 0xd04: /* Interrupt Control State.  */
  
          /* VECTACTIVE */
  
          val = s->gic.running_irq[0];
  
          if (val == 1023) {
  
              val = 0;
  
          } else if (val >= 32) {
  
              val -= 16;
  
          }
  
          /* RETTOBASE */
  
          if (s->gic.running_irq[0] == 1023
  
                  || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
  
              val |= (1 << 11);
  
          }
  
          /* VECTPENDING */
  
          if (s->gic.current_pending[0] != 1023)
  
              val |= (s->gic.current_pending[0] << 12);
  
          /* ISRPENDING */
  
          for (irq = 32; irq < s->num_irq; irq++) {
  
              if (s->gic.irq_state[irq].pending) {
  
                  val |= (1 << 22);
  
                  break;
  
              }
  
          }
  
          /* PENDSTSET */
  
          if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
  
              val |= (1 << 26);
  
          /* PENDSVSET */
  
          if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
  
              val |= (1 << 28);
  
          /* NMIPENDSET */
  
          if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
  
              val |= (1 << 31);
  
          return val;
  
      case 0xd08: /* Vector Table Offset.  */
  
          cpu = ARM_CPU(current_cpu);
  
          return cpu->env.v7m.vecbase;
  
      case 0xd0c: /* Application Interrupt/Reset Control.  */
  
          return 0xfa05000;
  
      case 0xd10: /* System Control.  */
  
          /* TODO: Implement SLEEPONEXIT.  */
  
          return 0;
  
      case 0xd14: /* Configuration Control.  */
  
          /* TODO: Implement Configuration Control bits.  */
  
          return 0;
  
      case 0xd24: /* System Handler Status.  */
  
          val = 0;
  
          if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
  
          if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
  
          if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
  
          if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
  
          if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
  
          if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
  
          if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
  
          if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
  
          if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
  
          if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
  
          if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
  
          if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
  
          if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
  
          if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
  
          return val;
  
      case 0xd28: /* Configurable Fault Status.  */
  
          /* TODO: Implement Fault Status.  */
  
          qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
  
          return 0;
  
      case 0xd2c: /* Hard Fault Status.  */
  
      case 0xd30: /* Debug Fault Status.  */
  
      case 0xd34: /* Mem Manage Address.  */
  
      case 0xd38: /* Bus Fault Address.  */
  
      case 0xd3c: /* Aux Fault Status.  */
  
          /* TODO: Implement fault status registers.  */
  
          qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
  
          return 0;
  
      case 0xd40: /* PFR0.  */
  
          return 0x00000030;
  
      case 0xd44: /* PRF1.  */
  
          return 0x00000200;
  
      case 0xd48: /* DFR0.  */
  
          return 0x00100000;
  
      case 0xd4c: /* AFR0.  */
  
          return 0x00000000;
  
      case 0xd50: /* MMFR0.  */
  
          return 0x00000030;
  
      case 0xd54: /* MMFR1.  */
  
          return 0x00000000;
  
      case 0xd58: /* MMFR2.  */
  
          return 0x00000000;
  
      case 0xd5c: /* MMFR3.  */
  
          return 0x00000000;
  
      case 0xd60: /* ISAR0.  */
  
          return 0x01141110;
  
      case 0xd64: /* ISAR1.  */
  
          return 0x02111000;
  
      case 0xd68: /* ISAR2.  */
  
          return 0x21112231;
  
      case 0xd6c: /* ISAR3.  */
  
          return 0x01111110;
  
      case 0xd70: /* ISAR4.  */
  
          return 0x01310102;
  
      /* TODO: Implement debug registers.  */
  
      default:
  
          qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
  
          return 0;
  
      }
  
  }
  