# Machine Timer Interrupt (mtime) problem

**URL:** https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720
**Category:** RISC-V
**Created:** [October 29, 2018, 5:42pm UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720 "2018-10-29T17:42:58Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![aignacio](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/aignacio/32/556_2.png) [@aignacio](https://forums.sifive.com/u/aignacio)
#### Post date: [October 29, 2018, 5:42pm UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720/1 "2018-10-29T17:42:58Z")

</div>

Hey guys from SiFive team,

I’m facing some issues to enable **mtime** to generate local interrupts, also I cannot read exactly the value inside the mtime register. What steps exactly I need to run before start waiting for machine time interrupt by compare? I’m using the sample code below with coreplex IP E31 (based on SiFive examples):

> #include \<stdio.h\>  
> #include \<stdbool.h\>  
> #include \<stdlib.h\>  
> #include \<string.h\>  
> #include \<unistd.h\>  
> #include “platform.h”  
> #include “plic/plic\_driver.h”  
> #include “gpio.h”  
> #include “uart.h”
> 
> typedef void (\*interrupt\_function\_ptr\_t) (void);  
> interrupt\_function\_ptr\_t localISR[32];
> 
> void set\_timer()  
> {  
> volatile uint64\_t \* mtime = (uint64\_t\*) (CLINT\_CTRL\_ADDR + CLINT\_MTIME);  
> volatile uint64\_t \* mtimecmp = (uint64\_t\*) (CLINT\_CTRL\_ADDR + CLINT\_MTIMECMP);  
> uint64\_t now = _mtime;  
> uint64\_t then = now + 2_RTC\_FREQ;  
> \*mtimecmp = then;
> 
> ```
> printf("\n\rMTIME: %d",*mtime);
> 
> ```
> 
> printf(“\n\rMTIMECMP: %d”,\*mtimecmp);  
> printf(“\n\rMachine timer interrupt!”);  
> }
> 
> /_Entry Point for Machine Timer Interrupt Handler_/  
> void machine\_timer\_int\_isr()  
> {  
> set\_timer();  
> }
> 
> void invalid\_local\_isr()  
> {  
> printf(“\n\rUnexpected local interrupt!”);  
> }
> 
> int main(void)  
> {  
> for (int lisr = 0; lisr \< 32; lisr++) {  
> localISR[lisr] = invalid\_local\_isr;  
> }
> 
> ```
> localISR[IRQ_M_TIMER] = machine_timer_int_isr;
> 
> set_timer();
> 
> // Enable timer interrupts.
> set_csr(mie, MIP_MTIP);
> 
> // Enable all interrupts
> set_csr(mstatus, MSTATUS_MIE);
> 
> while(1) {
> //rdtime();
> asm volatile ("wfi");
> }
> 
> return 0;
> 
> ```
> 
> }

---

<div class="post-metadata">

### Author: ![ilg](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/ilg/32/871_2.png) [@ilg](https://forums.sifive.com/u/ilg)
#### Post date: [October 29, 2018, 7:01pm UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720/2 "2018-10-29T19:01:58Z")

</div>

> [@aignacio](#):
>
> volatile uint64\_t \* mtime = (uint64\_t\*) (CLINT\_CTRL\_ADDR + CLINT\_MTIME);  
> volatile uint64\_t \* mtimecmp = (uint64\_t\*) (CLINT\_CTRL\_ADDR + CLINT\_MTIMECMP);

I don’t know if this is the problem here, but anyway, the E31 registers are 32-bit, only the E51 registers can be safely addressed as 64-bit.

---

<div class="post-metadata">

### Author: ![aignacio](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/aignacio/32/556_2.png) [@aignacio](https://forums.sifive.com/u/aignacio)
#### Post date: [October 30, 2018, 1:52pm UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720/3 "2018-10-30T13:52:39Z")

</div>

Hello @ild,

Thanks for the answer, about the bit width that you’ve mentioned I think that the compiler do the job of allocating/manipulate two variables each time in 64 through E31. But what I have noted is that when you connect other interruptions in the global interruption port (at E31 eval RTL) the machine timer interrupt seems not work as expected…probably it’s related how PLIC managed this.

 ![Screenshot from 2018-10-30 09-55-42](https://us1.discourse-cdn.com/flex020/uploads/sifive/original/1X/fa1e50cd71628182d6ded0a84831ceb38aaa0d13.png)

---

<div class="post-metadata">

### Author: ![ilg](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/ilg/32/871_2.png) [@ilg](https://forums.sifive.com/u/ilg)
#### Post date: [October 30, 2018, 3:27pm UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720/4 "2018-10-30T15:27:08Z")

</div>

> [@aignacio](#):
>
> I think that the compiler do the job of allocating/manipulate two variables each time in 64 through E31

it does, but if you care about atomicity, you have to do it manually, as explained in the specs.

---

<div class="post-metadata">

### Author: ![thornschuh](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/thornschuh/32/134_2.png) [@thornschuh](https://forums.sifive.com/u/thornschuh)
#### Post date: [October 31, 2018, 11:09am UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720/5 "2018-10-31T11:09:39Z")

</div>

Besides this, aignacios example does not show the code how the mtvec csr is set. He also did not tell about the hardware he is using. For example the HiFive1 does not support vectored mode in mtvec, it just supports one global interrupt handler which has to check mcause.

When it is not working there are two possibilities:  
a) The interrupt is not triggered  
b) The interrupt is triggered but the service routine is not called because of incorrectly set up interrupt handler.

To check a) it is best to just poll the mip csr in the main while(1) loop and check if ithe mtip bit is set.  
If this happens the problem must be b)

---

<div class="post-metadata">

### Author: ![aignacio](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/aignacio/32/556_2.png) [@aignacio](https://forums.sifive.com/u/aignacio)
#### Post date: [October 31, 2018, 12:48pm UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720/6 "2018-10-31T12:48:23Z")

</div>

Hey Thomas,  
thanks for the answer, about the hardware that I’m using, it’s in the first question “E31 RTL eval”. And about the mtvec set, check the following code below. As I’m using the default init.c from freedom-e-sdk with a fewer modifications, the only defined symbol its USE\_LOCAR\_ISR, so in my understanding what happens it’s that **mtvec** is set with my handler trap entry function that’ll just call the local function defined in the vector (localISR[mcause & MCAUSE\_CAUSE] ()). So, in this case (mcause == IRQ\_M\_TIMER) it should call machine\_timer\_int\_isr(), right?

> //See LICENSE for license details.  
> #include \<stdint.h\>  
> #include \<stdio.h\>  
> #include \<unistd.h\>
> 
> #include “platform.h”  
> #include “encoding.h”
> 
> #define CPU\_FREQ 60000000  
> #define XSTR(x) #x  
> #define STR(x) XSTR(x)
> 
> #ifndef VECT\_IRQ  
> #define TRAP\_ENTRY trap\_entry  
> #else  
> #define TRAP\_ENTRY vtrap\_entry  
> #endif
> 
> extern int main(int argc, char\*\* argv);  
> extern void TRAP\_ENTRY();
> 
> unsigned long get\_cpu\_freq()  
> {  
> return CPU\_FREQ;  
> }
> 
> unsigned long get\_timer\_freq()  
> {  
> return get\_cpu\_freq();  
> }
> 
> uint64\_t get\_timer\_value()  
> {  
> #if \_\_riscv\_xlen == 32  
> while (1) {  
> uint32\_t hi = read\_csr(mcycleh);  
> uint32\_t lo = read\_csr(mcycle);  
> if (hi == read\_csr(mcycleh))  
> return ((uint64\_t)hi \<\< 32) | lo;  
> }  
> #else  
> return read\_csr(mcycle);  
> #endif  
> }
> 
> static void uart\_init(size\_t baud\_rate)  
> {  
> //UART0\_REG(UART\_REG\_DIV) = (get\_cpu\_freq() / 2) / baud\_rate - 1;  
> //UART0\_REG(UART\_REG\_TXCTRL) |= UART\_TXEN;  
> }
> 
> #ifdef USE\_PLIC  
> extern void handle\_m\_ext\_interrupt();  
> #endif
> 
> #ifdef USE\_M\_TIME  
> extern void set\_timer();  
> #endif
> 
> #ifdef USE\_LOCAL\_ISR  
> typedef void (\*my\_interrupt\_function\_ptr\_t) (void);  
> extern my\_interrupt\_function\_ptr\_t localISR;  
> #endif
> 
> #ifndef VECT\_IRQ  
> uintptr\_t handle\_trap(uintptr\_t mcause, uintptr\_t epc) **attribute** ((noinline));  
> uintptr\_t handle\_trap(uintptr\_t mcause, uintptr\_t epc)  
> {  
> if (0){  
> #ifdef USE\_PLIC  
> // External Machine-Level interrupt from PLIC  
> } else if ((mcause & MCAUSE\_INT) && ((mcause & MCAUSE\_CAUSE) == IRQ\_M\_EXT)) {  
> handle\_m\_ext\_interrupt();  
> #endif  
> #ifdef USE\_M\_TIME  
> // External Machine-Level interrupt from PLIC  
> } else if ((mcause & MCAUSE\_INT) && ((mcause & MCAUSE\_CAUSE) == IRQ\_M\_TIMER)){  
> set\_timer();  
> #endif  
> #ifdef USE\_LOCAL\_ISR  
> } else if (mcause & MCAUSE\_INT) {  
> localISR[mcause & MCAUSE\_CAUSE] ();  
> #endif  
> }  
> else {  
> write(1, “Unhandled Trap:\n”, 16);  
> \_exit(1 + mcause);  
> }  
> return epc;  
> }  
> #endif
> 
> #ifdef USE\_CLIC  
> void trap\_entry(void) **attribute** ((interrupt(“SiFive-CLIC-preemptible”), aligned(64)));  
> void trap\_entry(void)  
> {  
> unsigned long mcause = read\_csr(mcause);  
> unsigned long mepc = read\_csr(mepc);  
> handle\_trap(mcause, mepc);  
> }  
> #endif
> 
> void \_init()  
> {  
> #ifndef NO\_INIT  
> uart\_set\_cfg(0,15);  
> printf(“\n\rCore freq at " STR(CPU\_FREQ) " Hz\n”);
> 
> #ifdef USE\_CLIC  
> write\_csr(mtvec, ((unsigned long)&trap\_entry | MTVEC\_CLIC));  
> #else  
> write\_csr(mtvec, ((unsigned long)&TRAP\_ENTRY | MTVEC\_VECTORED));  
> #endif
> 
> #endif  
> }
> 
> void \_fini()  
> {  
> }

---

<div class="post-metadata">

### Author: ![aignacio](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/aignacio/32/556_2.png) [@aignacio](https://forums.sifive.com/u/aignacio)
#### Post date: [October 31, 2018, 12:55pm UTC](https://forums.sifive.com/t/machine-timer-interrupt-mtime-problem/1720/7 "2018-10-31T12:55:24Z")

</div>

@thornschuh and @ilg ,

One thing that I’ve noted it’s the connection of .global\_interrupts() input in the E31 RTL code because if I use the scheme like image below, machine timer starts counting as expected, but If I use the commented way, it just does not happens…I don’t know how the slack parameters affect the **mtimer** reg synthesis.  
 ![Screenshot from 2018-10-31 09-51-11](https://us1.discourse-cdn.com/flex020/uploads/sifive/original/1X/0445ca1291cad870309b9e916c5a6fbbdfd9c556.png)
