Riscv五级流水线32位cpu,systemverilog编写,指令集rv32i,支持数据前递,csr寄存器与中断控制器,可跑通dhrystone测试。 支持2bit饱和分支预测 本商品包括: 1.rv32五级流水线cpu代码 2.可以选择拓展的axi4总线接口代码 3.一份五级流水线cpu的详细说明文档 适合新手学习 图中展示了资源消耗情况

一、项目概述

本项目是一款基于RISC-V架构的32位五级流水线CPU,采用SystemVerilog语言编写,全面支持RV32I指令集。该CPU具备诸多关键技术特性,包括数据前递机制以解决数据相关问题、CSR(控制与状态寄存器)管理功能、中断控制器模块,同时集成2bit饱和分支预测器提升分支指令执行效率。在功能验证方面,该CPU可成功跑通Dhrystone基准测试,充分证明其指令执行的正确性与系统稳定性,适用于嵌入式系统等对性能和可靠性有一定要求的场景。

二、核心模块功能解析

(一)指令转换工具(machine_code.py)

1. 功能定位

该Python脚本是连接ELF格式固件与Verilog仿真环境的关键桥梁,主要作用是将编译生成的ELF固件文件转换为Verilog仿真可识别的指令格式文件,为CPU提供正确的指令输入,确保CPU在仿真环境中能够正常取指、译码并执行指令。

2. 核心处理流程
  1. 参数初始化:设定总存储长度为2^32字节,基地址为0x80000000(符合RISC-V架构下常见的内存映射规则),总线宽度(buswid)设为2(即每次处理2个word的数据),同时初始化用于存储地址与对应数据的字典(new)、地址序列列表(changeseq)等数据结构。
  2. 文件读取与解析:读取输出目录下的firmware.verilog文件,将文件内容按空格分割为单个数据单元。通过循环遍历这些数据单元,识别地址标识与对应指令数据:若数据长度为2,则判定为指令数据并添加到当前地址对应的列表中;若数据长度不为2,则解析出地址信息,计算其相对于基地址的偏移量并转换为特定单位的地址索引,同时在字典中初始化该地址对应的空列表以存储后续指令数据。
  3. 数据补零与格式转换:为保证指令数据长度符合总线宽度要求,对每个地址下的指令数据列表进行检查,若长度不是4*bus_wid的整数倍,则计算需要补零的数量并进行补零操作。随后,按照Verilog仿真文件的格式要求,将处理后的地址与指令数据写入instr.verilog文件,其中地址以16位十六进制格式呈现,指令数据则根据总线宽度进行拼接,确保CPU在取指过程中能够正确获取完整指令。

(二)固件代码(firmware.S)

1. 启动流程(_start函数)
  1. hartid获取与判断:通过csrr t0, mhartid指令读取当前硬件线程ID(hartid),并将其左移10位(slli t0, t0, 0xa)。再次读取hartid到a0寄存器,若a0不为零(bnez a0, park),则跳转到park函数使该硬件线程进入休眠状态,仅保留一个硬件线程执行后续初始化操作,避免多线程冲突。
  2. 中断初始化:通过csrwi mie, 0csrwi mip, 0指令分别禁用机器模式下的中断使能(mie)和中断挂起(mip)寄存器,防止初始化过程中受到中断干扰。
  3. 异常处理设置:使用auipc t0, 0x5addi t0, t0, 1036指令计算异常入口地址(trap_entry),并通过csrw mtvec, t0指令将该地址写入机器模式陷阱向量控制寄存器(mtvec),指定CPU发生异常时的跳转入口。
  4. 状态寄存器配置:通过lui t0, 0x6csrc mstatus, t0指令修改机器模式状态寄存器(mstatus),配置CPU的工作状态。同时,初始化全局指针(gp)和栈指针(sp),为后续函数调用和数据存储分配栈空间,并通过csrw mscratch, sp指令将栈指针写入机器模式暂存寄存器(mscratch),用于异常处理时保存上下文。
  5. 跳转至主入口:完成初始化后,通过j primarycpuentry指令跳转到primarycpuentry函数,进入系统主初始化流程。
2. 中断处理相关函数
  1. rthwinterrupt_disable:通过csrrci a0, mstatus, 8指令清除mstatus寄存器中的中断使能位,禁用中断,返回操作前的mstatus寄存器值,便于后续恢复中断状态。
  2. rthwinterrupt_enable:通过csrw mstatus, a0指令将传入的参数(即之前保存的mstatus值)写回mstatus寄存器,恢复中断使能状态,确保系统在合适的时机能够响应中断。
3. 上下文切换函数
  1. rthwcontextswitchto:该函数用于切换到目标上下文。通过ld sp, 0(a0)指令从目标上下文结构中加载栈指针,再通过ld a0, 16(sp)加载目标mstatus值并通过csrw mstatus, a0指令恢复,最后跳转到rthwcontextswitchexit函数完成上下文切换的后续操作。
  2. rthwcontextswitch:该函数用于保存当前上下文并切换到新上下文。首先通过addi sp, sp, -256指令扩展栈空间,保存当前栈指针到目标上下文结构(sd sp, 0(a0)),随后依次保存返回地址(ra)、mstatus寄存器值等关键寄存器到栈中。根据mstatus寄存器中的中断使能状态设置相应标志位,再加载新上下文的栈指针(ld sp, 0(a1)),最后跳转到rthwcontextswitch_exit函数。
  3. rthwcontextswitchexit:该函数完成上下文切换的收尾工作。从栈中加载返回地址(ra)、mstatus值等寄存器并恢复,通过mret指令返回至新上下文的执行点,实现完整的上下文切换。
4. 数学运算函数

涵盖除法(udivsi3、divsi3等)、取模(umodsi3、moddi3等)、乘法(muldi3)等基础数学运算函数,为系统提供底层数学计算支持。例如,udivdi3函数通过循环移位和比较操作实现无符号64位除法,muldi3函数通过累加和移位操作实现乘法运算,这些函数采用RISC-V指令集实现,确保在该CPU架构下的高效执行。

5. 线程管理函数
  1. 线程创建与启动:rtthreadcreate函数负责创建线程,分配线程控制块和栈空间,初始化线程上下文;rtthreadstartup函数用于启动线程,设置线程状态为就绪态,将线程加入调度队列,触发调度器进行线程调度。
  2. 线程休眠与唤醒:rtthreadsleep、rtthreaddelay、rtthreadmdelay函数分别实现基于时钟节拍、指定节拍数和毫秒级的线程休眠功能,通过设置定时器和修改线程状态使线程让出CPU;rtthreadresume函数用于唤醒休眠的线程,将线程状态恢复为就绪态并重新加入调度队列。
  3. 线程删除与清理:rtthreaddelete函数用于删除线程,释放线程占用的资源,将线程从调度队列中移除;rtthreadcleanupexecute函数用于执行线程清理操作,释放线程相关的资源,确保系统资源的正确回收。
6. 定时器管理函数
  1. 定时器初始化:rttimerinit函数初始化定时器,设置定时器的超时时间、回调函数等参数,将定时器加入定时器链表。
  2. 定时器启动与停止:rttimerstart函数启动定时器,将定时器按照超时时间插入到相应的定时器队列;rttimerstop函数停止定时器,将定时器从定时器队列中移除,停止定时器的计时。
  3. 定时器检查与处理:rttimercheck和rtsofttimer_check函数分别用于检查硬件定时器和软件定时器的超时情况,当定时器超时时,执行相应的回调函数,处理定时器事件。
7. 内存管理函数
  1. 内存分配与释放:rtmalloc函数从堆中分配指定大小的内存块,通过查找空闲内存块链表找到合适的内存块并标记为已使用;rtfree函数释放之前分配的内存块,将其标记为空闲并合并相邻的空闲内存块,减少内存碎片。
  2. 内存初始化:rtsystemheap_init函数初始化系统堆,设置堆的起始地址和大小,初始化空闲内存块链表,为后续内存分配提供基础。
  3. 内存复制与填充:rtmemcpy函数实现内存块之间的数据复制,rtmemset函数将指定内存块填充为指定值,为内存操作提供基础支持。

三、系统工作流程

(一)启动阶段

  1. CPU上电后从_start函数开始执行,完成hartid判断、中断禁用、异常入口设置、栈指针初始化等操作,仅保留一个硬件线程继续执行。
  2. 跳转到primarycpuentry函数,初始化系统堆、中断控制器、UART(通用异步收发传输器)等硬件模块,配置控制台设备,输出系统启动信息。
  3. 初始化空闲线程(idle thread)和定时器线程,设置idle线程的钩子函数,用于在系统空闲时执行特定操作;启动定时器线程,用于处理软件定时器事件。

(二)中断处理阶段

  1. 当外部设备产生中断请求时,若中断使能,CPU暂停当前执行的指令,保存当前上下文(如程序计数器、寄存器值等)到栈或mscratch寄存器。
  2. 根据mtvec寄存器指定的异常入口地址,跳转到trapentry函数,在该函数中识别中断类型,调用相应的中断处理函数(如PLIC控制器的中断处理函数plicclaim和plic_complete)。
  3. 中断处理完成后,恢复之前保存的上下文,通过mret指令返回至中断发生前的执行点,继续执行原程序。

(三)线程调度阶段

  1. 系统启动后,调度器(rt_schedule)根据线程的优先级和状态,从就绪队列中选择优先级最高的线程作为当前执行线程。
  2. 当发生线程休眠、时间片耗尽、中断处理完成等情况时,触发调度器重新调度,通过上下文切换函数(rthwcontext_switch)保存当前线程的上下文,加载目标线程的上下文,实现线程的切换。
  3. 空闲线程在没有其他就绪线程时执行,执行idle钩子函数或进入低功耗状态,等待新的线程被唤醒或中断事件的发生。

(四)定时器处理阶段

  1. 定时器初始化后,通过rttimerstart函数启动定时器,定时器按照设定的超时时间开始计时。
  2. 当定时器超时时,定时器检查函数(rttimercheck、rtsofttimer_check)检测到超时事件,执行定时器的回调函数,处理相应的业务逻辑(如唤醒休眠的线程)。
  3. 对于周期性定时器,在回调函数中重新启动定时器,实现定时器的周期性触发。

四、关键技术特性

(一)数据前递机制

在五级流水线(取指、译码、执行、访存、写回)中,为解决数据相关问题(如前一条指令的结果尚未写回寄存器,后一条指令就需要使用该结果),采用数据前递技术。在执行阶段,通过检测源操作数的寄存器地址与前一条或几条指令的目标寄存器地址是否一致,若一致且前一条指令已完成执行阶段,直接将前一条指令的执行结果作为当前指令的操作数,无需等待数据写回寄存器,减少流水线阻塞,提高CPU的执行效率。

(二)2bit饱和分支预测

为减少分支指令对流水线的影响,采用2bit饱和分支预测算法。该算法通过一个2位的状态寄存器记录分支指令的历史执行情况(如强不跳转、弱不跳转、弱跳转、强跳转)。当分支指令执行时,根据状态寄存器的值预测分支是否跳转:若预测跳转,则提前从目标地址取指,避免流水线清空;若预测错误,则更新状态寄存器并清空流水线,重新从正确地址取指。通过记录分支历史,提高分支预测的准确率,减少分支指令带来的性能损失。

(三)CSR寄存器与中断控制器

  1. CSR寄存器管理:CPU实现了RISC-V架构定义的多种CSR寄存器,如mstatus(机器状态寄存器)、mie(机器中断使能寄存器)、mip(机器中断挂起寄存器)、mtvec(机器陷阱向量控制寄存器)、mepc(机器异常程序计数器)等。通过专门的CSR指令(如csrr、csrw、csrci、csrsi等)实现对这些寄存器的读写操作,用于配置CPU的工作状态、中断使能、异常处理入口等。
  2. 中断控制器:集成PLIC(平台级中断控制器),用于管理外部设备的中断请求。PLIC接收外部设备的中断信号,按照中断优先级进行仲裁,将最高优先级的中断请求发送给CPU。CPU通过plicclaim函数获取中断源ID,执行相应的中断处理函数,处理完成后通过pliccomplete函数通知PLIC中断处理完成,实现中断的正确响应和处理。

五、测试验证

该CPU可成功跑通Dhrystone基准测试。Dhrystone测试程序主要用于衡量计算机系统的整数运算性能和程序执行效率,通过执行大量的整数运算、分支判断、函数调用等操作,统计单位时间内的执行次数(Dhrystone MIPS)。在测试过程中,CPU能够正确执行测试程序中的所有指令,包括RV32I指令集中的算术运算、逻辑运算、分支跳转、加载存储、CSR操作等指令,完成测试程序的初始化、数据处理和结果输出,证明该CPU的指令集兼容性和功能正确性,具备稳定可靠的运行能力。

Riscv五级流水线32位cpu,systemverilog编写,指令集rv32i,支持数据前递,csr寄存器与中断控制器,可跑通dhrystone测试。 支持2bit饱和分支预测 本商品包括: 1.rv32五级流水线cpu代码 2.可以选择拓展的axi4总线接口代码 3.一份五级流水线cpu的详细说明文档 适合新手学习 图中展示了资源消耗情况

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐