Files
ciciec2026_loongson/rtl/ip/open-la500/doc/设计概述.md
2026-04-12 22:20:18 +08:00

9.0 KiB
Raw Permalink Blame History

设计概述

系统框图

系统框图展示了OpenLA500处理器核的内部结构。指令的执行始终按照取指、译码、执行、访存、写回的顺序进行。各级流水会存储指令执行的中间状态在完成当前阶段的操作后将结果存入下一级流水进行下一个阶段的操作。

执行流程

处理器核内维护nextpc信号,表示取指地址。待取指开始时,fetch_pc会发往icachetlbbtb进行不同的工作,以及存入触发器。在下一拍即fs_stage取指级,btb完成分支预测,将结果直接送往nextpc,更改其取指方向。以及由fetch_pc以及tlb虚实地址翻译的结果,在icache指令缓存中得到inst指令码,并存入触发器。下一级ds_stage译码级在拿到指令码后,便交给decoder进行译码。译码后可以得到具体的操作码op,以及寄存器号,并可借此在regfile寄存器堆或者csr控制寄存器中索引到寄存器值rf_dataes_stage执行级在得到操作码及操作数后,便可送至alu运算部件进行简单运算,以及送往div除法部件、mul乘法部件进行多拍较复杂的运算。此外,由alu可以得到访存地址,并发至tlbdcache数据缓存完成访存请求的处理,基本同icache。在mem_stage访存级,可得到访存、乘除法的运算结果,并由op选择最终的运算结果final_res,并存入触发器。wb_stage写回级便会将最终运算结果写回到regfilecsr。对于i/dcache,若取指/访存请求缺失,便会发送请求至axi_bridge并通过标准的AXI3总线协议与外界通信。


流水级的各阶段需要与其他不同的模块进行交互,确认其任务是否完成。以下针对流水级及各模块进行介绍:

取指阶段

pfs

该级流水的主要功能是维护nextpc,也就是流水线取指的虚地址。其实从更为严谨的角度来看pfs并不应该单独称为一级流水,因为nextpcwire类型,或者说pfs在正常的执行流程中不会缓存信号,当拍便可获得取指方向。实际上pfs为各级能够影响取指地址的流水级的衍生。nextpc的维护逻辑可以说是五级流水中最为复杂的一部分,因为icache并不是时刻处于就绪的状态,由inst_addr_ok信号指示其是否就绪。因此,对于某些特殊情况下出现的转顺即逝的信息,比如流水线刷新等,需要构建状态机缓存信息。待取指方向确认,且icache就绪,pfs会置起fetch_en,紧接着btbicachetlb便会接收pfs发出的fetch_pc,开始相应的操作。

btb

分支预测器,根据PC直接预测其跳转地址。32项btb组织为CAM表的形式,由PC查询。此外,还包括一个ras组织为一个8项的栈存储函数调用过程中的返回地址。btb分支预测的结果会在下一拍返回,若预测正确则可消除下一拍产生于fs级流水的空泡,预测错误不会造成任何性能损失。

icache

指令缓存,两路组相连的结构。fetch_pc进入icache后,首先根据由fetch_pc拆解而来的index部分,索引出两路的cache行。其次再根据tag部分与tlb翻译得到的物理页号是否相等判断是否有命中项。若命中,下一拍返回inst_rdata,若未命中,则进入icache处理miss请求的状态机,inst_addr_ok拉低。等待miss请求处理完毕后再接收新的取指请求。替换策略为随机替换。

tlb

组织为32项CAM表的形式,指令和数据共用,需要两个查询端口。通过fetch_pc的虚页号查询是否存在命中项,命中则返回物理页号。若未命中,则会标记该指令存在tlb缺失例外,并进入例外处理程序。待对应tlb项在页表中找到并由软件填入tlb后,重新执行该指令。

fs

fs取值级便是真正意义上的第一级流水。fs级接收icache返回的指令码inst_rdata,由inst_data_ok指示指令码是否就绪。若icache missfs级便会阻塞。额外需要注意一点,tlb的读取有一拍的延迟因为32项的CAM表会有较长的逻辑。因此tlb的读取结果是在fs级得到,也就表示tlb相关的例外判断是在fs级完成,而取指请求是在pfs级发出。所以fs级需要具备中止上一拍pfs级发往icache的取指请求的能力,体现在tlb_excp_cancel_req信号中,dcache同理。

译码阶段

ds

译码级,其功能便是将指令码解析为对应的操作码,并根据寄存器号,从regfile中取出寄存器值。不过寄存器的最新值可能还未被写入到regfile中,因为后续流水线中的指令正在执行,结果未获得或者未写回,而当前指令可能依赖于这些指令的结果。因此译码级与后续流水线构建了前递路径(es_to_ds_forward_bus/ms_to_ds_forward_bus),用于前递未写回的结果,或者通知ds级结果未获取,需要阻塞。此外,经过译码,已知晓该指令是否为跳转指令,以及是否跳转。也就可以识别分支预测器的预测结果是否正确,ds级便可通过br_bus对取指方向进行修正,以及更新分支预测器的历史信息。btb的预测包括两个方面,该PC是否为跳转指令;识别为跳转指令时是否跳转。ds级需要鉴别并对分支预测器执行特定的更新操作。

执行阶段

es

执行级,根据译码得到的操作码,送往alumuldiv进行特定类型的运算。alu用于处理较简单的运算,比如加减、移位运算。mul为华莱士树实现的乘法部件,拆为两级。div为常规的迭代除法部件需要34个周期得到结果。此外若为访存指令执行级便可通过加减运算得到访存地址。同pfs等待dcache准备就绪,即data_addr_ok置起,es便可发出data_fetch以及data_addr,由tlb进行虚实地址映射以及dcache取回数据。不过需要注意若当前指令或者后续流水线中的指令存在例外,需要及时中止data_fetch的置起。

访存阶段

dcache

数据缓存,在icache的基础上新增了处理写请求的能力。每个cache行新增一个dirty位,用于标识该cache行是否为脏,在被替换时判断是否需要写回。此外,写请求在命中的情况下,相较于读请求,需要额外的一拍将数据写入到ram中。这额外一拍的延迟可以通过构建写请求状态机节省。待确认写请求命中后,进入状态机,使得dcache可以继续接收新的请求。不过需要注意规避读写请求同时出现在单端口的ram上。

ms

访存级,等待dcache数据返回,由data_data_ok指示data_rdata是否有效。ms级同fs级,需要由tlb_excp_cancel_req信号取消掉上一拍es发往dcache的访存请求。写请求不同于读请求需要等待接收数据,待请求发出后,不管命不命中,可继续向后流动。

写回阶段

ws

写回级,此时指令已执行完毕,并得到result,需根据执行结果修改处理器状态,包括两个方面:写通用寄存器regfile以及状态寄存器csr;根据指令触发的例外类型,修改csr寄存器,以及清空流水线并调整取指方向至例外入口。


流水级间交互

最理想的情况下同一时刻五个阶段都处于工作的状态也就表示同一时刻在处理五条指令。此时处理器核在通过流水线切分得到较高频率时带宽仍然保持为1指令/拍。但在实际情况下,如前文所述,并不会如此,各级流水总是会出现阻塞的情况。因此,流水级之间需要交互,避免一级流水的操作还未完成便被上一级覆盖。

流水级之间的交互逻辑中,需要维护以下关键信号:

  • stage_valid:由触发器维护,表示当前流水级是否在处理指令。
  • stage_ready_go:表示流水级是否需要被阻塞。
  • stage_allowin:表示当前流水级是否允许上一级流水进入,该信号传递至上一级,与上一级流水交互,两种情况下该信号置起,当前流水无正在处理的指令;或者当前流水级中的指令已处理完毕且下一级流水允许进入。该信号会由最后一级流水向前传递,只要某一流水级阻塞,其stage_allowin拉低,同一时刻,前面所有流水级的stage_allowin都会拉低(假设所有流水级中都有指令在处理)。
  • stage_to_nextstage_valid:表示当前流水级中是否有处理完毕的指令,该信号传递至下一级,与下一级流水交互。下一级流水在收到高电平信号时,且其下一级流水的stage_allowin为高电平,则会在下一拍置起下一级流水的stage_valid,实现流水级间指令的流动。stage_to_nextstage_bus总线信号中传递缓存信号,会随着stage_to_nextstage_valid流动。