---
# System prepended metadata

title: 作業系統工程 12-1作業

---

# <center>作業系統工程 12-1作業<br><font size=5>611121212 李奕承</font></center>


建立標頭檔和相關巨集
```clike
#ifndef __HWTIMER_H_
#define __HWTIMER_H_

//每次發生時間中斷的間隔
#define TIMER_INTERVAL 10000000
//存取 CLINT 暫存器的基址
#define CLINT_BASE 0x2000000L
//存取 CLINT 中時鐘暫存器的地址
#define CLINT_MTIME (CLINT_BASE + 0xBFF8)
//存取 CLINT 中用來比較時間的暫存器的地址
#define CLINT_MTIMECMP(hartid) (CLINT_BASE + 0x4000 + 8 * (hartid))

#endif
```

在總巨集 os.h 中引用
```clike
#include"hwtimer.h"
```
確保 riscv.h 中有以下幾個巨集
```clike
//讀取當前 hart 的編號
static inline reg_t r_mhartid()
{
    reg_t x;
    asm volatile("csrr %0, mhartid" : "=r" (x));
    return x;
}

//寫入 mie 暫存器
static inline void w_mie(reg_t x)
{
    asm volatile("csrw mie, %0" : : "r" (x));
}

//寫入 mstatus 暫存器
static inline void w_mstatus(reg_t x)
{
    asm volatile("csrw mstatus, %0" : : "r" (x));
}
```
接著編寫hwtimer.c
```clike
#include"os.h"

//將比較暫存器 CLINT_MTIMECMP 設置為下次發生中斷的時間
void timer_load(int interval)
{
    int id = r_mhartid();
    *(uint64_t *)CLINT_MTIMECMP(id) = *(uint64_t *)CLINT_MTIME + interval;
}

//初始化下次發生時間中斷的時間，打開時間中斷，打開全域中斷
void timer_init(void)
{    
    timer_load(TIMER_INTERVAL);
    w_mie(r_mie() | MIE_MTIE);
    w_mstatus(r_mstatus() | MSTATUS_MIE);
}


//宣告紀錄時間的參數
int seconds = 0;
int mintues = 0;
int hours = 0;


//時間進位的邏輯
void tick()
{
    seconds++;
    if(seconds == 60)
    {
        mintues++;
        seconds = 0;
        if(mintues == 60)
        {
            hours++;
            mintues = 0;
            if(hours == 24)
            {
                hours = 0;
            }
        }
    }
}

//顯示時間的函數
void clock()
{
    if(hours < 10)
    {printf("0%d : ", hours);}else{printf("%d : ", hours);}

    if(mintues < 10)
    {printf("0%d : ", mintues);}else{printf("%d : ", mintues);}

    if(seconds < 10)
    {printf("0%d ", seconds);}else{printf("%d ", seconds);}

    printf("\n");
}


//時間中斷處理函數，這裡每一次都加1秒，並且更新下次要發生的時間
void timer_handle(void)
{
    tick();
    timer_load(TIMER_INTERVAL);
}
```
將其他 .c 檔會用到的函數放到 os.h 中公開，這裡我加在 #include"hwtimer.h" 這行後面
```c  
#include"hwtimer.h"
void timer_init(void);
void timer_handle(void);
void clock(void);
void timer_load(int interval);
```
將 timer_handle() 放入中斷處理函數中
```clike
reg_t trap_handler(reg_t epc, reg_t cause)
{
    reg_t return_pc = epc;
    reg_t cause_code = cause & 0xfff;

    if(cause & 0x80000000)
    {
        switch (cause_code)
        {
        case 3:
            uart_puts("software interruption!\n");
            break;

        case 7:
            //這裡
            timer_handle();
            break;

        case 11:
            external_interrupt_handler();
            break;
        

        default:
            uart_puts("unknown async exception!\n");
            break;
        }
    }
    else
    {        
        printf("Sync exceptions!, code = %d\n", cause_code);
        uart_puts("OOPS! What can I do!\n");
        uart_puts("next time, this task will start at pc where exeception next \n");
        ((pcb_t *)current)->error = 1;
        return return_pc += 4;
    }
    return return_pc;
}
```

在你想顯示時間的 task中 加入clock() 函數，這裡我加在 schedule() 中的 PCB 顯示的後面

終端機的畫面
![](https://i.imgur.com/uhOVs3W.png)
每進一次 schedule() 就會顯示最新的時間
![](https://i.imgur.com/MHT4yvg.png)




