网站滑动效果怎么做,网站备案审核过规定时间了,网站开发选择框代码,网站制作400哪家好网站目录
往期文章传送门
一、硬件定时器
硬件实现
软件实现
二、上板测试 往期文章传送门 开发一个RISC-V上的操作系统#xff08;一#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统#xff08;二#xff09;—— 系统引导…目录
往期文章传送门
一、硬件定时器
硬件实现
软件实现
二、上板测试 往期文章传送门 开发一个RISC-V上的操作系统一—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统二—— 系统引导程序Bootloader_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统三—— 串口驱动程序UART_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统四—— 内存管理_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统五—— 协作式多任务_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统六—— 中断interrupt和异常exception_Patarw_Li的博客-CSDN博客 本节的代码在仓库的 05_HW_TIMER 目录下仓库链接riscv_os: 一个RISC-V上的简易操作系统
本文代码的运行调试会在前面开发的RISC-V处理器上进行仓库链接cpu_prj: 一个基于RISC-V指令集的CPU实现
一、硬件定时器
生活离不开对时间的管理操作系统也是一样。
时钟节拍Tick
操作系统中最小的时间单位。Tick的单位周期由硬件定时器的周期决定通常为1~100ms。Tick周期越小系统精度越高但开销越大。
系统时钟
操作系统维护一个整形计数值记录着系统启动直到当前发生的Tick总数。
硬件实现
在本项目中timer作为一个外设挂载在总线rib上rtl文件为 cpu_prj\FPGA\rtl\perips\timer.v 五个读写信号用于读写timer模块中的寄存器信号 timer_int_flag_o 用于给 clint 中断模块发出中断信号verilog 代码如下
// 32bit 定时器
module timer(input wire clk ,input wire rst_n ,// 读写信号 input wire wr_en_i , // write enableinput wire[INST_ADDR_BUS] wr_addr_i , // write addressinput wire[INST_REG_DATA] wr_data_i , // write datainput wire[INST_ADDR_BUS] rd_addr_i , // read addressoutput reg [INST_REG_DATA] rd_data_o , // read data// 中断信号output wire timer_int_flag_o );localparam TIMER_CTRL 4h0;localparam TIMER_COUNT 4h4;localparam TIMER_EVALUE 4h8;// [0]: timer enable// [1]: timer int enable// [2]: timer int pending, software write 0 to clear it// addr offset: 0x00reg[31:0] timer_ctrl;// timer current count, read only// addr offset: 0x04reg[31:0] timer_count;// timer expired value// addr offset: 0x08reg[31:0] timer_evalue;assign timer_int_flag_o ((timer_ctrl[2] 1b1) (timer_ctrl[1] 1b1))? 1b1 : 1b0;// 读写寄存器write before readalways (posedge clk or negedge rst_n) beginif (!rst_n) begintimer_ctrl ZERO_WORD;timer_evalue ZERO_WORD;endelse beginif (wr_en_i 1b1) begincase (wr_addr_i[3:0])TIMER_CTRL: begin// 这里代表软件只能把 timer_ctrl[2]置0无法将其置1timer_ctrl {wr_data_i[31:3], (timer_ctrl[2] wr_data_i[2]), wr_data_i[1:0]};endTIMER_EVALUE: begintimer_evalue wr_data_i;endendcaseendif(timer_ctrl[0] 1b1 timer_count timer_evalue) begintimer_ctrl[0] 1b0;timer_ctrl[2] 1b1;endcase (rd_addr_i[3:0])TIMER_CTRL: beginrd_data_o timer_ctrl;endTIMER_COUNT: beginrd_data_o timer_count;endTIMER_EVALUE: beginrd_data_o timer_evalue;enddefault: beginrd_data_o ZERO_WORD;endendcaseendend// 计数器 timer_countalways (posedge clk or negedge rst_n) beginif (!rst_n) begintimer_count ZERO_WORD;endelse beginif (timer_ctrl[0] ! 1b1 || timer_count timer_evalue) begintimer_count ZERO_WORD;endelse begintimer_count timer_count 1b1;endendendendmodule
其中
timer_ctrl 为控制寄存器低三位有效分别是第0位 timer enable 置1则 timer_count 开始计时第1位 timer int enable置1则允许发出中断信号反之则不允许第2位 timer int pending当 timer_count timer_evalue 时就把该位置1表示有中断信号要发出需要软件置0。
timer_count 为计数寄存器只读。
timer_evalue 存放过期值用来与 timer_count 寄存器比较当 timer_count timer_evalue 时则发出中断信号。
软件实现
代码实现为 riscv_os/05_HW_TIMER/timer.c
// 1s
#define TIMER_INTERVAL 50000000/** The TIMER control registers are memory-mapped at address TIMER (defined in inc/platform.h). * This macro returns the address of one of the registers.*/
#define TIMER_REG_ADDRESS(reg) ((volatile uint32_t *) (TIMER reg))/** TIMER registers map* timer_count is a read-only reg*/
#define TIMER_CTRL 0
#define TIMER_COUNT 4
#define TIMER_EVALUE 8#define timer_read_reg(reg) (*(TIMER_REG_ADDRESS(reg)))
#define timer_write_reg(reg, data) (*(TIMER_REG_ADDRESS(reg)) (data))#define TIMER_EN 1 0
#define TIMER_INT_EN 1 1
#define TIMER_INT_PENDING 1 2static uint32_t _tick 0;void timer_load(uint32_t interval)
{timer_write_reg(TIMER_EVALUE, interval);timer_write_reg(TIMER_CTRL, (timer_read_reg(TIMER_CTRL) | (TIMER_EN)));
}/** enable timer interrupt*/
void timer_init()
{timer_write_reg(TIMER_CTRL, (timer_read_reg(TIMER_CTRL) | (TIMER_INT_EN)));timer_load(TIMER_INTERVAL);
}void timer_handler()
{timer_write_reg(TIMER_CTRL, (timer_read_reg(TIMER_CTRL) ~(TIMER_INT_PENDING)));_tick;printf(tick: %d\n, _tick);timer_load(TIMER_INTERVAL);
}
其中
_tick 为该模块维护的全局时间节拍。
timer_load(uint32_t interval) 函数用于给定时器模块寄存器赋值interval 个硬件时钟周期后发出定时器中断如果 interval 板子系统时钟频率相当于1s。
timer_init() 函数用于给定时器模块寄存器初始化。
timer_handler() 函数用于执行定时器中断处理当定时器中断发生的时候执行这个函数的内容。该函数会将 _tick 值加一后执行 timer_load(uint32_t interval) 函数从而达到持续计数的功能。
二、上板测试
烧录到板子上后打开串口调试程序可以看到tick值一直在计数从而实现系统时钟的功能 遇到问题欢迎加群 892873718 交流~