Timer interrupt

Implemented timer. First, it needs interrupt vector table at address 0x00000000.
The following (not optimized my first) arm code “_init_vector_table” copies _initialize_vector_start to _initialize_vector_end to 0x00000000.

First, I tried to copy that in C, but uint32_t* vector_table; *vector_table=… was not compiled as I expected by cross gcc 4.9 perhaps because 0 is NULL in C and *NULL is illegal.

.global  _initialize_vector_start
_initialize_vector_start:
        ldr     pc, _vec_Reset
        ldr     pc, _vec_Undef
        ldr     pc, _vec_SWI
        ldr     pc, _vec_PrefAbort
        ldr     pc, _vec_DataAbort
        ldr     pc, _vec_Reserved
        ldr     pc, _vec_IRQ
        ldr     pc, _vec_FIQ
_vec_Reset:             .word   _start
_vec_Undef:             .word   _hangup
_vec_SWI:               .word   _hangup
_vec_PrefAbort: .word   _hangup
_vec_DataAbort: .word   _hangup
_vec_Reserved:  .word   _hangup
_vec_IRQ:               .word   _IRQ_iterrupt
_vec_FIQ:               .word   _hangup
        .global  _initialize_vector_end
_initialize_vector_end:
# dummy instruction to keep initialize_vector_end label
        mov r0,r0

.global _init_vector_table
_init_vector_table:
  ldr r0, =0x0
  ldr r1, =_initialize_vector_start
  ldr r3, =_initialize_vector_end
  cmp r1, r3
  bxeq lr
  _init_vector_table_loop:
  ldr r2, [r1]
  str r2, [r0]
  add r1, #4
  add r0, #4
  cmp r1, r3
  bne _init_vector_table_loop
  bx lr

Then, _IRQ_iterrupt calls C function IRQ_handler.

_IRQ_iterrupt:
	stmfd	r13!, {r0-r12,lr}
	bl	IRQ_handler
	ldmfd	r13!, {r0-r12,lr}
	subs	pc,lr, #4

IRQ_handler sets g_interrupt flag.

volatile static bool g_interrupt = false;

// called by _IRQ_interrupt in startup.s
void IRQ_handler(void) {
  // disable IRQ
  _disable_IRQ();

  if (*INTERRUPT_IRQ_BASIC_PENDING & 0x01 != 0) {
    // Timer interrupt handler
    g_interrupt = true;
    // clear interrupt flag
    *TIMER_IRQ_CLR = 0;
  }

  // enable IRQ
  _enable_IRQ();
}

Then dirty main loop is checking the flag. I’ll change it to wait for interrupt like another x86 OS is doing.

  while (true) {
    _disable_IRQ();
    if (true == g_interrupt) {
      g_interrupt = false;
      _enable_IRQ();
      redraw();
    } else {
      _enable_IRQ();
    }
  }

Today’s code: https://github.com/sokoide/rpi-baremetal -> 004_timer_interrupt.

Leave a Reply

Your email address will not be published. Required fields are marked *