MaQueOS对时钟中断的初始化在系统初始化过程中完成。本章实验code2的main函数如代码清单2.1所示。
代码清单2.1 main函数(第2版)
下面对代码清单2.1进行说明。
在 第4~6行 中,本章实验code2中的main函数的第2版在第1版的基础上增加了对时钟中断的初始化。其中, 第5行 表示调用excp_init函数初始化时钟中断,初始化过程详见2.1.2节。 第6行 表示调用int_on函数使能全局中断,使能过程详见2.1.3节。
LoongArch架构提供了用于产生时钟中断的恒定频率定时器(以下简称定时器)。在使用定时器前,需要为其设定1个自减初始值,定时器会按照固定频率进行自减操作,当自减到0时,产生时钟中断信号。通过配置定时器,MaQueOS就会每隔固定的时间收到时钟中断信号,并进行时钟中断处理。
通过写TCFG寄存器中的字段,就可以进行定时器的配置。如图C.5所示,TCFG寄存器需要配置的字段包括定时器倒计时自减的初始值InitVal、循环模式控制位Periodic和定时器使能位EN。
·InitVal: 定时器倒计时自减计数的初始值。硬件将该值左移2位后的值作为最终的定时器的自减初始值。例如,若将InitVal字段设置为1,则定时器的自减初始值为4,即定时器在自减4次后,产生时钟中断信号。
·Periodic: 循环模式控制位。若该位为1,则定时器在倒计时自减至0时,在产生时钟中断信号的同时,将定时器的自减初始值重新加载为InitVal字段中的值左移2位后的值,然后在下一个时钟周期重新自减。若该位为0,则自减至0时,在产生定时器中断信号后停止自减。
·EN: 定时器使能位。只有当该位为1时,定时器才会进行倒计时自减,并在减至0时,产生定时器中断信号。
实现时钟中断的使能需要配置2个寄存器:ECFG寄存器和CRMD寄存器。其中,ECFG寄存器用于使能局部中断,使能过程详见2.1.2节;CRMD寄存器用于使能全局中断,使能过程详见2.1.3节。如前所述LoongArch架构支持13个中断,每个中断都有一个局部中断使能位,总共13位,分别对应ECFG寄存器的LIE字段中的13位,LIE字段在ECFG寄存器中的位置如图C.3所示,其中,定时器中断对应第11位。
时钟中断初始化的主要工作是对上面介绍的定时器进行配置,该工作由excp_init函数完成,excp_init函数的实现详见代码清单2.2。
代码清单2.2 excp_init函数(第1版)
下面对代码清单2.2进行说明。
·第13~14行: 通过写TCFG寄存器,进行定时器的配置。如上节所述,需要对TCFG寄存器的3个字段进行配置。其中,对TCFG寄存器的写操作由write_csr_64库函数 完成。
InitVal: 首先调用read_cpucfg库函数,获取定时器所用时钟对应的晶振频率(0x5f5e100),即定时器每秒自减0x5f5e100次。通过将该频率的值设置为定时器倒计时自减计数的初始值,达到将定时器中断产生的时间间隔设置为1秒的目的。
Periodic: 设置为1(CSR_TCFG_PER),表示打开定时器循环模式。
EN: 设置为1(CSR_TCFG_EN),表示使能定时器。
·第15行: 调用write_csr_64库函数,将中断处理函数exception_handler的入口地址填入例外入口地址寄存器EENTRY。exception_handler函数的分析详见2.2.2节。
·第16行: 调用write_csr_32库函数,将ECFG寄存器的LIE字段中的第11位设置为1,使能定时器中断。
在excp_init函数中完成初始化工作后,如代码清单2.1的第5行所示,在main函数中,调用int_on函数使能全局中断。int_on函数的实现详见代码清单2.3。
代码清单2.3 int_on函数
下面对代码清单2.3进行说明。
·第8行: 调用read_csr_32库函数读取CRMD寄存器的值。
·第9行: CRMD寄存器的部分字段如图C.1所示,其中,IE字段用于使能全局中断。因此,将IE字段设置为1(CSR_CRMD_IE)后,调用write_csr_32库函数,写回CRMD寄存器,从而使能全局中断。