一、单周期CPU介绍
单周期CPU顾名思义就是一个指令周期内只执行一条指令的CPU。
比如下面的指令

在单周期CPU中执行的过程,体现为:
在每一个周期(时钟上升沿),就执行完一条指令。
二、CPU设计
CPU是由一个指令存储器(IM,instruction Memory)和数据存储器(DM,DataMemory)还有CPU组成。其架构如下:

| 模块 | 功能描述 |
| CPU | |
| 信号 | 描述 |
| clock(clock) | 时钟信号 |
| reset(rst) | 复位信号 |
| instruction(Instruction) | 执行的指令 |
| ReadMemData(ReadMemData) | 从内存中读出的数据 |
| InstAddress(PC) | 指令地址 |
| AluResult(MemDataAddr) | 从内存中读数据的地址 |
| MemWrite(MemWrite) | 是否写内存 |
| WriteMemData(WriteMemData) | 写入内存的数据 |
| WriteMemDataLength(WriteMemDataLength) | 表示写入内存的数据的位置,长度 |
| 模块 | 功能描述 |
| InstructionMemory | 指令存储器 |
| 信号 | 描述 |
| PC[8:2] | 指令地址 |
| Instruction | 指令 |
| 模块 | 功能描述 |
| DataMemory | 数据存储器 |
| 信号 | 描述 |
| clock | 时钟信号 |
| MemDataAddr[8:2] | 写入/读出内存数据的地址 |
| MemWrite | 是否写入内存 |
| WriteMemData | 写入内存的数据 |
| WriteMemDataLength | 表示写入内存的数据的位置,长度 |
| ReadMemData | 从内存中读出的数据 |
首先,CPU向指令存储器传入指令地址,也就是PC中存储的值,指令存储器就将对应的指令地址传给CPU。CPU开始执行指令 ,有的指令涉及到和数据存储器,比如LW,LB,LBU,LH,LHU指令需要读取数据存储器中的数据,SW,SH,SB指令需要将运算结果写入数据存储器中。就涉及到了CPU将数据和数据要存放的地址传给DM,也涉及到CPU将要读取的地址传给DM,DM将对应数据传回CPU。这就是CPU运作的大致流程,在单周期或者流水线CPU中基本没有什么变化。
而指令如何执行,CPU内部如何实现就是单周期和流水线CPU的差别所在。
CPU内部架构如图所示(看不清没办法了),大致描述一下过程,PC将指令地址传给IM,IM将指令送到控制器,控制器根据指令解析出指令的信号 (指令是否需要写入内存,指令是否需要写入寄存器,指令是否要进行符号扩展,指令的运算符是什么,下一个指令地址是什么等等) 之后,将信号传到各自的模块运算。

| 模块 | 功能描述 |
| PC | 负责PC更新,仅在 clk 或者 rst 为 posedge 时更新 PC。 |
| 信号 | 描述 |
| NextPC(NextInstAddress) | 从NextPC模块送来的下一条指令地址 |
| PC(InstAddress) | 指令地址 |
| clock(clock) | 时钟信号 |
| reset(reset) | 复位信号 |
| 模块 | 功能描述 |
| NextPC | 计算下一条指令地址 |
| 信号 | 描述 |
| NextPC(NextInstAddress) | 计算出的PC值 |
| PC(InstAddress) | 当前正在处理的指令的PC值 |
| NextPCSignal(NextPCSignal) | 控制信号,选择哪一个作为下一个PC值 |
| JumpAddr(JumpAddr) | J/JAL指令中的25位立即数作为跳转地址 |
| JumpReg(RegSourceData) | JR/JARL指令跳转地址 |
| 模块 | 功能描述 |
| CU | 控制器模块,产生控制信号 |
| 信号 | 描述 |
| Opcode | 指令中的opcode字段 |
| Func | 指令中的function字段 |
| RegTarget | 指令中的rt字段,(用于区分bltz,bltzal...) |
| AluZeroSignal | 用于判断分支指令是否跳转 |
| RegWrite | 是否写寄存器 |
| MemWrite | 是否写内存 |
| SignExt | 是否扩展立即数 |
| RegimmSignal | 表示是否是(BLTZ,BLTZAL...) |
| AluOpcode | ALU的操作符 |
| NextPCSignal | 下一条指令地址选择信号 |
| AluSrcASignal | 操作数A选择信号 |
| AluSrcBSignal | 操作数B选择信号 |
| WriteRegDataSignal | 写入寄存器数据的选择信号 |
| WriteRegSignal | 写入寄存器地址的选择信号 |
| MemRead | 是否读内存 |
| 模块 | 功能描述 |
| Register | 通用寄存器组, |
| 信号 | 描述 |
| clock(clock) | 时钟信号 |
| reset(reset) | 复位信号 |
| RegWrite(RegWrite) | 是否写寄存器 |
| ReadRegAddr1(RegSource) | 读rs的地址 |
| ReadRegAddr2(RegTarget) | 读rt的地址 |
| WriteRegAddr(WriteRegAddr) | 写寄存器的地址 |
| WriteRegData(WriteRegData) | 写寄存器的数据 |
| ReadRegData1(RegSourceData) | 读出rs的数据 |
| ReadRegData2(WriteMemData) | 读出rt的数据 |
| 模块 | 功能描述 |
| SRC_A | 选择ALU的操作数A |
| 信号 | 描述 |
| DataIn0(RegSourceData) | 读出rs的数据 |
| DataIn1(Shamt) | 移位指令的位移量 |
| Signal(AluSrcASignal) | ALU的操作数A选择信号 |
| DataOut(AluOperandA) | 操作数A |
| 模块 | 功能描述 |
| SRC_B | 选择ALU的操作数B |
| 信号 | 描述 |
| DataIn0(WriteMemData) | 读出rt的数据 |
| DataIn1(Imm32) | 扩展后的32位立即数 |
| Signal(AluSrcBSignal) | ALU的操作数B选择信号 |
| DataOut(AluOperandB) | 操作数B |
| 模块 | 功能描述 |
| ALU | 运算器模块 |
| 信号 | 描述 |
| AluOperandA(AluOperandA) | 操作数A |
| AluOperandB(AluOperandB) | 操作数B |
| AluOpcode(AluOpcode) | ALU的操作符 |
| MemRead(MemRead) | 是否读内存 |
| MemWrite(MemWrite) | 是否写内存 |
| AluResult(AluResult) | 运算结果 |
| AluZeroSignal(AluZeroSignal) | 判断运算结果与0的关系 |
| AluOverflowSignal(AluOverflowSignal) | 判断运算结果是否溢出 |
| WriteMemDataLength(WriteMemDataLength) | 表示写入内存的数据的位置,长度 |
| ReadMemExtSignal(ReadMemExtSignal) | 表示从内存读出的数据如何拓展 |
| RegimmSignal(RegimmSignal) | 表示操作数B是否是0,针对(BLTZ等指令) |
| 模块 | 功能描述 |
| WR_REG_ADDR | 选择写寄存器的地址 |
| 信号 | 描述 |
| DataIn0(RegDst) | 写入rd寄存器 |
| DataIn1(RegTarget) | 写入rt寄存器 |
| .DataIn2(5'b11111) | 31号寄存器 |
| Signal(WriteRegSignal) | 选择信号 |
| DataOut(WriteRegAddr) | 写寄存器的地址 |
| 模块 | 功能描述 |
| WR_REG_DATA | 选择写寄存器的数据 |
| 信号 | 描述 |
| DataIn0(AluResult) | 运算器运算结果 |
| DataIn1(MemDataExt) | 从内存读出并扩展后的数据 |
| DataIn2(InstAddress + 4) | 当前指令的下一条指令地址,(JALR,JAL,BLTZAL...) |
| Signal(WriteRegDataSignal) | 选择信号 |
| DataOut(WriteRegData) | 写寄存器的数据 |
| 模块 | 功能描述 |
| SignExtension | 扩展立即数 |
| 信号 | 描述 |
| Imm16 | 指令中的16位立即数 |
| SignExt | 扩展信号,表示零扩展还是符号扩展 |
| Imm32 | 扩展后的32位立即数 |
| 模块 | 功能描述 |
| MemDataExtension | 扩展从内存中读出的数据 |
| 信号 | 描述 |
| ReadMemData | 读出的数据 |
| ReadMemExtSignal | 扩展信号 |
| MemDataExt | 扩展后的数据 |

这里带大家模拟执行一条指令,便于大家理解。
就比如第一条指令
首先,PC将00400000传给IM,IM读取到指令,2402ff9d(就是addiu $2,$0,-99的二进制码,表示将0号寄存器中的值加上-99,存储到2号寄存器中)传给CPU的控制器, 控制器解析指令,得到这条指令需要写入寄存器,需要对立即数进行负号扩展,运算器运算符是00001(定义为加法),下一个指令地址(NextPC)是顺序执行,在当前指令地址上加4。第一个运算数是寄存器R0(AluSrc1Signal是0表示读寄存器),第二个运算数是立即数(AluSrc2Signal是1),写入寄存器的数据不需要扩展,不需要读内存。这些信号传到各自模块中后,ALUSRC1会根据指令中的对应字段确认是几号寄存器,去寄存器中读取值,ALUSRC2会从立即数扩展器中得到扩展后的立即数,ALU得到ALUSRC1和ALUSRC2的两个运算符,得到AluCode是加法,计算之后,将结果传给寄存器,寄存器写入对应寄存器。这条指令就执行完成了。
详细资源:
chris-william0829/bit-mini-mips-single-cycle-cpu (github.com)
1万+

被折叠的 条评论
为什么被折叠?



