I am trying to set up a machine timer interrupt using the following code (on the HiFive1 RevB on Linux with the freedom-e-SDK on the CLI. I just post the most relevant parts here; it’s written in assembler for the most part because that’s what I am trying to learn…):
main.c
#include <stdio.h>
#include "super_blink.h"
int main() {
setup_GPIO();
setup_timer_irq();
// set a delay so the first interrupt handler can fire
delay(DELAY);
while (1) {
// the idea being that delay sets the timer
// for the first interrupt. In the interrupt
// routine, we set the next delay so all we need
// to do here is to loop endlessly
}
}
setup_timer_irq.S
.section .text
.align 2
.global setup_timer_irq
.include "gpio.inc"
.include "memory_map.inc"
setup_timer_irq:
addi sp, sp, -16 # Allocate stack frame
sw ra, 12(sp) # save return address to the stack
lw t0, irq_handler # load address of irq_handler
slli t0, t0, 1 # shift address left by one; LSB will be 0 which is direct mode (what we want)
csrw mtvec, t0 # write handler address and mode
# Here we cannot use csrsi because it can only set up to 5 bits
li t0, 0x88 # set 4rd and 8th bit
csrw mie, t0 # activate machine timer interrupt
# write high value to the timercmp just to be sure we don't
# trigger an interrupt by mistake
li t0, 0x7FFFFFFF # high number
li t1, 0xFFFFFFFF # high number
li t2, MTIMECMP # load address of timecmp register
sw t0, 4(t2) # store the first number to the upper part first
sw t1, 0(t2) # then the second to the lower part
csrsi mstatus, 0x4 # set 3rd bit to activate machine interrupts.
lw ra, 12(sp) # load return address
addi sp, sp, 16 # deallocate stack frame
ret
irq_handler:
# save only the registers we use in this function
addi sp, sp, -28 # Allocate stack frame
sw ra, 24(sp) # save return address to the stack
sw t0, 20(sp) # save temporary
sw t1, 16(sp) # save temporary
sw t2, 12(sp) # save temporary
sw t3, 8(sp) # save temporary
sw a0, 4(sp) # save first argument to function
li t0, GPIO_CTRL_ADDR # load base GPIO address
lw t1, GPIO_OUTPUT_VAL(t0) # load state
beqz t1, switchOnRed # if none is blinking yet, blink the red one
li t3, GPIO_RED_LED
beq t1, t3, switchOnBlue # if red is on, switch on blue LED
li t3, GPIO_BLUE_LED
beq t1, t3, switchOnGreen # if blue is on, switch on green LED
# here, neither the red or blue are on, so the one that is on
# must be the green one. In that case we just fall through to
# switch on the red LED
switchOnRed:
li t2, GPIO_RED_LED # load value indicating red LED
j exit
switchOnBlue:
li t2, GPIO_BLUE_LED # load value indicating blue LED
j exit
switchOnGreen:
li t2, GPIO_GREEN_LED # load value indicating green LED
j exit
exit:
sw t2, GPIO_OUTPUT_VAL(t0) # write new LED values to the right address
li a0, 200 # load the desired delay value (in ms) as the first arg to the function
jal delay # call delay function to set new delay
lw ra, 24(sp) # load return address
lw t0, 20(sp) # restore temporary
lw t1, 16(sp) # restore temporary
lw t2, 12(sp) # restore temporary
lw t3, 8(sp) # restore temporary
lw a0, 4(sp) # restore first argument to function
addi sp, sp, 28 # deallocate stack frame
mret # exit IRQ handler
(note that this is most likely buggy since I have no prior practical experience with either embedded development nor assembler)
When I run this on the Hifive1 Rev B, nothing happens. Connecting with gdb through J-Link shows me that the code is hanging in the while loop (as expected). When I set a break point in the irq_handler: code it never gets hit though.
In order to debug this I want to print the CSR register values for MIE and MSTATUS etc, but gdb only prints regular registers, not the CSRs it seems:
main () at first.c:14
14 while (1) {
(gdb) inf reg
ra 0x20010190 0x20010190 <main+18>
sp 0x80000560 0x80000560
gp 0x800008d8 0x800008d8
tp 0x0 0x0
t0 0x200bff8 33603576
t1 0x23b 571
t2 0x1c03 7171
fp 0x80000570 0x80000570
s1 0x2000080 33554560
a0 0xc8 200
a1 0x20010ed0 536940240
a2 0x20010ed4 536940244
a3 0x1 1
a4 0x10028 65576
a5 0x0 0
a6 0x1f 31
a7 0x0 0
s2 0x2000080 33554560
s3 0x0 0
s4 0x0 0
s5 0x0 0
s6 0x0 0
s7 0x0 0
s8 0x0 0
s9 0x0 0
s10 0x0 0
s11 0x0 0
t3 0x2004000 33570816
t4 0x0 0
t5 0x0 0
t6 0x0 0
pc 0x20010190 0x20010190 <main+18>
(gdb) p $t1
$1 = 571
(gdb) p $mie
$2 = void
(gdb) p $mstatus
$3 = void
Does anyone know how I can get gdb to print the CSRs I am interested in? Other pointers about how to debug my code are also welcome of course