HNU计算机体系结构-实验一:RISC-V指令理解

前言

体系结构的第一个实验,实际上是中科大的实验,GitHub直接搜ustc_ca可以搜出很多,我也是借鉴了几位大佬的。这个课是计科第一年开课的,所以以后的实验内容可能会有所调整。

这次实验的内容也很简单,用ripes跑一遍即可,这个软件还是很智能的,每一步骤干什么,用的哪个寄存器,以及数值是多少都能显示出来。

闲麻烦不想在GitHub上下载的,直接放到网盘了。

具体用法是先打开ripes.exe,左上角editor->setiing,然后
在这里插入图片描述
选择另一个文件夹里的编译器,然后就可以运行代码了。
在这里插入图片描述

一般这个实验都在期中前做的,所以一定要认认真真的跑一遍流水线,把一些基本指令的流程都弄懂,期中必考的。
还有一个坑就是bge指令的立即数那里,它那个是要左移一位的,最高位补的数字和次高位一样

1.实验目的

参考提供为了更好的理解RISC-V,通过学习RV32I Core的设计图,理解每条指令的数据流和控制信号,为之后指令流水线及乱序发射实验打下基础。

看不清的可以下载
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b2v9Zhr2-1686648622231)(C:\Users\86159\AppData\Roaming\Typora\typora-user-images\1680504587112.png)]

各部分的部件的主要控制信号如下:

1.HarzardUnit

流水线冲突处理模块,基本手段:(1)插入气泡stall,(2)定向路径(前递,转发)forward,(3)冲刷流水段flush,组合逻辑电路,信号说明:

输入:

  • CpuRst: 外部信号,用来初始化CPU,当CpuRst1时CPU全局复位清零(所有段寄存器flush),Cpu_Rst0时cpu开始执行指令
  • ICacheMiss, DCacheMiss:为后续实验预留信号,暂时可以无视,用来处理cache miss
  • BranchE,JalrE,JalD: 控制相关处理信号
  • Rs1D,Rs2D,Rs1E,Rs2E,RdE,RdM,RdW: 译码,执行,访存,写会阶段处理数据相关的信号,对应的源寄存器和目标寄存器号码。
  • RegReadE: 标记A1A2对应的寄存器值是否被用到。
  • MemToRegE: 标志EX段从data mamory加载数据到寄存器
  • RegWriteM,RegWriteW: 标记MEM段和WB段是否有目标寄存器写入操作。

输出:

  • StallF,FlushF: IF段插入气泡(维持状态不变)/冲刷(清零)
  • StallD,FlushD: ID段插入气泡/冲刷
  • StallE,FlushE: EX段插入气泡/冲刷
  • StallM,FlushM: MEM段插入气泡/冲刷
  • StallW,FlushW: WB段插入气泡/冲刷
  • Forward1E,Forward2E: 定向路径控制信号

2.ControlUnit

控制模块(译码器),根据指令的操作码部分Op,func3部分Fn3和func7部分Fn7产生如下控制信号:

输入:

  • Op:是指令的操作码部分
  • Fn3:是指令的func3部分
  • Fn7:是指令的func7部分

输出:

  • JalD==1: 标志Jal指令到达指令ID译码阶段
  • JalrD==1: 标志Jalr指令到达指令ID译码阶段
  • RegWriteD: 表示指令ID译码阶段的寄存器写入模式
  • MemToRegD==1: 标志ID阶段指令需要从data memory读取数据到寄存器
  • MemWriteD: 共4bit,为1的部分有效,指示data memory的四个字节中哪些需要写入
  • LoadNpcD: 标志将NextPC输出到ResultM
  • RegReadD: 标志两个源寄存器的使用情况,RegReadD[1] == 1,表示A1对应的寄存器值被使用到了,RegReadD[0] == 1,表示A2对应的寄存器值被使用到了,用于forward处理
  • BranchTypeD: 表示不同分支类型(参见BranchDecisionMaking部分)
  • AluContrlD: 表示不同算数逻辑运算种类(参见ALU部分)
  • AluSrc2D: Alu输入源Operand2的选择
  • AluSrc1D: Alu输入源Operand1的选择
  • ImmType: 立即数编码格式类型

3.NPC_Generator

用来生成Next PC值的模块,根据不同的跳转信号选择不同的新PC值

输入:

  • PCF:旧的PC值
  • JalrTarget:jalr指令的对应的跳转目标
  • BranchTarget:branch指令的对应的跳转目标
  • JalTarget:jal指令的对应的跳转目标
  • BranchE==1:Ex阶段的Branch指令确定跳转
  • JalD==1:ID阶段的Jal指令确定跳转
  • JalrE==1:Ex阶段的Jalr指令确定跳转

输出:

  • PC_In:NPC的值

4.RegisterFile

上升沿写入,异步读的寄存器堆,0号寄存器值始终为32’b0

5.ImmOperandUnit

利用正在被译码的指令的部分编码值,生成不同类型的32bit立即数

输入:

  • IN:是指令除了opcode以外的部分编码值
  • Type:表示立即数编码类型,全部类型定义在Parameters中

输出:

  • OUT:表示指令对应的立即数32bit实际值

6.BranchDecisionMaking

跳转判断单元,根据控制信号BranchTypeE指定的分支类型,对操作数Operand1Operand2进行比较并决定是否跳转,将判断结果通过BranchE输出。各分支类型对应的控制信号如下

7.ALU

算数逻辑运算单元,接受Operand1Operand2两个操作数,按照控制信号AluContrl执行对应的算术逻辑运算,将结果从AluOut输出

8.DataExt

输入:

  • IN:是从Data Memory中load的32bit字
  • LoadedBytesSelect:等价于AluOutM[1:0],是读Data Memory地址的低两位,因为DataMemory是按字(32bit)进行访问的,所以需要把字节地址转化为字地址传给DataMem,DataMem一次返回一个字,低两位地址用来从32bit字中挑选出我们需要的字节
  • RegWriteW:表示不同的寄存器写入模式,所有模式定义在Parameters中

输出:

  • OUT:表示要写入寄存器的最终值

2.实验步骤

参考提供的RISC-V 32I的设计图,思考每条指令的数据通路,熟悉RISC-V电路图,并且为后续动态分支预测和Tomasulo实验打下基础。

1.安装模拟器Ripes

具体步骤见https://github.com/mortbopet/Ripes

已提供riscv32gcc编译器的ubuntu版本和windows版本,其余版本下载参考:

https://github.com/mortbopet/Ripes/blob/master/docs/c_programming.md

下载后页面如下:

在这里插入图片描述

2.生成汇编指令

输入以下代码后生成对应汇编指令

void main()
{
     int A[100];
     int i;
     for(i=0;i<100;i++)
       A[i]=i;
     for(i=1;i<100;i++)
       A[i]=A[i-1]+1000;
}

生成的汇编指令如下:

00010144 <main>://主函数的开始
	//x2的值减去432,然后存回x2。x2寄存器是栈指针,这条指令是为了分配栈空间
    10144:        e5010113        addi x2 x2 -432
    //x8的值存储到x2加上428的内存地址。x8寄存器是帧指针,所以这条指令是为了保存帧指针。
    10148:        1a812623        sw x8 428 x2
    //x2寄存器的值加上432,然后存回x8寄存器。这条指令是为了更新帧指针
    1014c:        1b010413        addi x8 x2 432
    //x0寄存器的值存储到x8寄存器减去20的内存地址。这条指令初始化一个局部变量i为0
    10150:        fe042623        sw x0 -20 x8
    //无条件跳转到当前地址加上40的位置,并将返回地址存储到x0寄存器。
    //因为x0寄存器是零寄存器,所以返回地址会被丢弃。这条指令是为了跳过下面的循环体。
    10154:        0280006f        jal x0 40
    //将x8寄存器减去20的内存地址的值加载到x15寄存器。这条指令是为了读取局部变量i的值
    10158:        fec42783        lw x15 -20 x8
    //将x15寄存器的值左移两位,然后存回x15寄存器。这条指令相当于将i乘以4,因为每个整数占4个字节
    1015c:        00279793        slli x15 x15 2
    //将x8寄存器的值减去16,然后存回x14寄存器。这条指令是为了计算数组A在栈上的起始地址
    10160:        ff040713        addi x14 x8 -16
    //将x14寄存器和x15寄存器的值相加,然后存回x15寄存器。这条指令是为了计算A[i]在栈上的地址
    10164:        00f707b3        add x15 x14 x15
    //将x8寄存器减去20的内存地址的值加载到x14寄存器。这条指令又一次读取局部变量i的值
    10168:        fec42703        lw x14 -20 x8
    //将x14寄存器的值存储到x15寄存器减去404的内存地址。这条指令相当于执行A[i]=i
    1016c:        e6e7a623        sw x14 -404 x15
    //将x8寄存器减去20的内存地址的值加载到x15寄存器。这条指令又一次读取局部变量i的值
    10170:        fec42783        lw x15 -20 x8
    //将x15寄存器的值加上1,然后存回x15寄存器。这条指令相当于执行i++
    10174:        00178793        addi x15 x15 1
    //将x15寄存器的值存储到x8寄存器减去20的内存地址。这条指令相当于更新局部变量i的值
    10178:        fef42623        sw x15 -20 x8
    //将x8寄存器减去20的内存地址的值加载到x14寄存器。这条指令又一次读取局部变量i的值
    1017c:        fec42703        lw x14 -20 x8
    //将x0寄存器的值加上99,然后存回x15寄存器。这条指令相当于将99赋值给一个临时变量
    10180:        06300793        addi x15 x0 99
    //比较x15寄存器和x14寄存器的值,如果x15大于等于x14,就跳转到当前地址减去44的位置。
    //这条指令相当于执行if(i<100) goto loop
    10184:        fce7dae3        bge x15 x14 -44
    //将x0寄存器的值加上1,然后存回x15寄存器。这条指令相当于初始化一个局部变量j为1
    10188:        00100793        addi x15 x0 1
    //将x15寄存器的值存储到x8寄存器减去20的内存地址。这条指令相当于更新局部变量j的值
    1018c:        fef42623        sw x15 -20 x8
    //无条件跳转到当前地址加上64的位置,并将返回地址存储到x0寄存器。
    //因为x0寄存器是零寄存器,所以返回地址会被丢弃。这条指令是为了跳过下面的循环体。
    10190:        0400006f        jal x0 64
    //将x8寄存器减去20的内存地址的值加载到x15寄存器。这条指令是为了读取局部变量j的值
    10194:        fec42783        lw x15 -20 x8
    //将x15寄存器的值减去1,然后存回x15寄存器。这条指令相当于执行j–1
    10198:        fff78793        addi x15 x15 -1
    //将x15的值左移两位,然后存回x15寄存器。这条指令相当于将j-1乘以4,因为每个整数占4个字节
    1019c:        00279793        slli x15 x15 2
    //将x8寄存器的值减去16,然后存回x14寄存器。这条指令是为了计算数组A在栈上的起始地址
    101a0:        ff040713        addi x14 x8 -16
    //将x14寄存器和x15寄存器的值相加,然后存回x15寄存器。这条指令是为了计算A[j-1]在栈上的地址
    *101a4:        00f707b3        add x15 x14 x15
    //将x15寄存器减去404的内存地址的值加载到x15寄存器。这条指令相当于获得A[j-1]的值
    101a8:        e6c7a783        lw x15 -404 x15
    //将x15寄存器的值加上1000,然后存回x14寄存器。这条指令相当于将A[j-1]+1000的值存在x14中
    101ac:        3e878713        addi x14 x15 1000
    //将x8寄存器减去20的内存地址的值加载到x15寄存器。这条指令又一次读取局部变量j的值
    101b0:        fec42783        lw x15 -20 x8
    //将x15寄存器的值左移两位,然后存回x15寄存器。这条指令相当于将j乘以4,因为每个整数占4个字节
    101b4:        00279793        slli x15 x15 2
    //将x8寄存器的值减去16,然后存回x13寄存器。这条指令是为了计算数组A在栈上的起始地址
    101b8:        ff040693        addi x13 x8 -16
    //将x13寄存器和x15寄存器的值相加,然后存回x15寄存器。这条指令是为了计算A[j]在栈上的地址
    101bc:        00f687b3        add x15 x13 x15
    //将x14寄存器的值存储到x15寄存器减去404的内存地址。这条指令相当于执行A[j]=A[j-1]+1000
    101c0:        e6e7a623        sw x14 -404 x15
    //将x8寄存器减去20的内存地址的值加载到x15寄存器。这条指令又一次读取局部变量j的值
    *101c4:        fec42783        lw x15 -20 x8
    //将x15寄存器的值加上1,然后存回x15寄存器。这条指令相当于执行j++
    101c8:        00178793        addi x15 x15 1
    //将x15寄存器的值存储到x8寄存器减去20的内存地址。这条指令相当于更新局部变量j的值
    *101cc:        fef42623        sw x15 -20 x8
    //将x8寄存器减去20的内存地址的值加载到x14寄存器。这条指令又一次读取局部变量j的值
    101d0:        fec42703        lw x14 -20 x8
    //将x0寄存器的值加上99,然后存回x15寄存器。这条指令相当于将99赋值给一个临时变量
    101d4:        06300793        addi x15 x0 99
    //比较x15寄存器和x14寄存器的值,如果x15大于等于x14,就跳转到当前地址减去68的位置。
    //这条指令相当于执行if(j<100) goto loop;
    *101d8:        fae7dee3        bge x15 x14 -68
    //将x0寄存器的值加上0,然后存回x0寄存器。这条指令没有实际作用,只是为了占位
    101dc:        00000013        addi x0 x0 0
    //将x2寄存器加上428的内存地址的值加载到x8寄存器。这条指令是为了恢复帧指针
    101e0:        1ac12403        lw x8 428 x2
    //将x2寄存器的值加上432,然后存回x2寄存器。这条指令是为了释放栈空间
    101e4:        1b010113        addi x2 x2 432
    //跳转到x1寄存器加上0的地址,并将返回地址存储到x0寄存器。
    //因为x0寄存器是零寄存器,所以返回地址会被丢弃。这条指令是为了从main函数返回
    101e8:        00008067        jalr x0 x1 0

3.思考问题

找出循环A[i]=A[i-1]+1000;对应的汇编代码,思考以下问题:

1)指令add x15, x14, x15

问题描述:分析指令add x15, x14, x15(x是指以x开头的通用寄存器),写出该指令在流水线五个阶段(IF、ID、EX、MEM和WB)关键的控制信号(参考RISC V电路设计图),并通过分析指出数据通路

答:这条指令的作用是将x14寄存器中的值加上x15寄存器中的值存到x15寄存器中,其中x14寄存器存入的是数组A的基址地址,x15存入的是偏移量,两者相加后获得A[j-1]的地址

R-型指令funct7rs2rs1funct3rdopcode
add00000000111101110000011110110011

这条指令是一条R类型的指令

  • IF阶段

    • 数据通路
    • 根据PCF,从指令存储器中取出指令00000000111101110000011110110011
      • PC寄存器的值加4,更新为下一条指令的地址
    • 控制信号:无
  • ID阶段

    • 数据通路
    • IF/ID寄存器中译码出指令的操作码(inst[6:0])
      • 在寄存器文件中读出源寄存器地址(inst[24:20],inst[19:15])对应地址的值,送入A1A2寄存器,送往ID/EX寄存器
      • 将目的寄存器地址(inst[11:7]) 送往ID/EX寄存器
      • IF/ID中得到指令段,送往Control Unit控制单元产生控制信号
    • 控制信号
      • ImmType=3'd0(代表是R类型指令,无需生成立即数)
  • EX阶段

    • 数据通路:
      • A1A2寄存器中取出两个源操作数,送入ALU进行加法运算,得到结果,送入ALUOutE,结果送入EX/MEM寄存器。
      • 上一级传入的控制信号传入下一阶段
      • ID/EX中得到Rd(目的寄存器地址),送往EX/MEM寄存器
    • 控制信号:
      • AluContrlE=3ALU执行加法操作
      • Forward1E=2'b00,第一个操作数选择来自A1寄存器的值
      • Forward2E=2'b00,第二个操作数选择来自A2寄存器的值
      • ALUSrc1E=1ALU第一个操作数来自A1寄存器
      • ALUSrc2E=2'00ALU第二个操作数来自A2寄存器
      • RegReadE[1]=1A1对应的寄存器值被使用到了
      • RegReadE[0]=1A2对应的寄存器值被使用到了
  • MEM阶段

    • 数据通路:
      • EX/MEM寄存器中取出运算结果ALUOutM,送入数据存储器和MemData多路选择器,存入MEM/WB寄存器中。
      • 上一级控制信号传入下一阶段
      • EX/MEM中得到Rd(目的寄存器地址),送往MEM/WB寄存器
    • 控制信号:
      • LoadNpcD=1: 将下一条指令的地址存储到ResultM中,以便在WB阶段更新PC寄存器的值
      • MemWriteM=4'0,不写内存
  • WB阶段

    • 数据通路

      • MEM/WB寄存器中取出写回数据,根据RegDst信号选择目的寄存器地址,将数据写入寄存器文件。
    • 控制信号

      • MemToRegW=1,选择将ALU运算结果传入寄存器文件中
      • RegWriteW=1,写回目的寄存器
2)指令bge x15 x14 -68

问题描述:分析指令bge x15, x14, -68,写出该指令在流水线五个阶段(IF、ID、EX、MEM和WB)关键的控制信号(参考RISC V电路设计图),并通过分析指出数据通路

答:这条指令的作用是比较x15寄存器和x14寄存器的值,如果x15大于等于x14,就跳转到当前地址减去68的位置。这条指令相当于执行if(j<100) goto loop。

指令输入SB-型指令,只会执行IF,ID和EX段。

  • IF阶段
    • 数据通路
      • 根据PCF,从指令存储器中取出指令11111010111001111101111011100011。
      • PC寄存器的值加4,更新为下一条指令的地址。
    • 控制信号:无
  • ID阶段:
    • 数据通路:
      • 寄存器堆A1A2地址分别为rs1rs2,读出待比较的值RegOut1DRegOut2D
      • Immediate Generate生成立即数并传入ImmD,左移一位后与PCD相加得到JalNPC,传入段寄存器
      • 指令Inst传给Controller Decoder,生成控制信号
    • 控制信号:
      • ImmTypeD=3’b011,Imm左移两位并符号扩展,传入ImmD,结果为-224
  • EX阶段:
    • 数据通路:
      • Branch Decision单元执行Reg1-Reg2 ,如果结果大于等于0,则BrE信号应该被设置为1,表示应该跳转。
      • 否则BrE应该被设置为0,表示不跳转,指令继续按地址的顺序执行
    • 控制信号:
      • BranchTypeE=3’001,代表BEQ指令
      • BrE=1,代表跳转,
      • BrT信号应该被设置为当前指令地址加上偏移量(-68),即PC + ImmE,即-68<<2(PC是当前指令的地址,左移两位是因为指令存储器是四字节地址寻址的)
      • BrE=0,代表不跳转, 则BrT信号被设置为下一条指令的地址,即PC+4
      • Forward1E=2'b00,第一个操作数选择来自A1寄存器的值
      • Forward2E=2'b00,第二个操作数选择来自A2寄存器的值
      • ALUSrc1E=1,reg1来自A1寄存器
      • ALUSrc2E=2'00,reg2来自A2寄存器
3)指令lw x15, -20 x8

问题描述:分析指令lw x15, -20 x8,写出该指令在流水线五个阶段(IF、ID、EX、MEM和WB)关键的控制信号(参考RISC V电路设计图),并通过分析指出数据通路

答:指令的作用是将x8寄存器减去20的内存地址的值加载到x15寄存器。其中x8寄存器减去20的内存地址的值即为局部变量i的值,所以这里是将i的值赋给x15寄存器

I-型指令immediaters1funct3rdopcode
lw11111110110001000010011110000011

这是一条I-型指令:

  • IF阶段
    • 数据通路:
      • 根据PCF,从指令存储器中取出指令11111110110001000010011110000011
      • PC寄存器的值加4,更新为下一条指令的地址。
    • **控制信号:**无
  • ID阶段
    • 数据通路:
      • 指令Inst传给Controller Decoder,生成控制信号
      • A1读入源寄存器地址(inst[19:15]),将读出的值RegOut1D送入ID/EX寄存器
      • 将目的寄存器地址(inst[11:7])rd送往ID/EX寄存器
      • Immediate Generate生成立即数,将立即数扩展为32位,送入ImmD,接着送入ID/EX寄存器。
    • 控制信号:
      • ImmType=3'd1,代表是I类型指令,需要生成立即数
      • RegWriteW=1,结果写回目的寄存器x15
  • EX阶段
    • 数据通路:
      • 从A1寄存器和ImmOperandUnit中取出两个源操作数,送入ALU进行加法运算,得到内存地址,送入ALUOutE,结果送入EX/MEM寄存器。
      • 从上一级获得控制信号并传入下一级
      • ID/EX中得到Rd地址,送往EX/MEM寄存器
    • 控制信号:
      • AluContrlE=4'b0011ALU执行加法操作
      • Forward1E=2'b00,第一个操作数选择来自A1寄存器的值
      • Forward2E=2'b01,第二个操作数选择来自立即数
      • ALUSrc1E=1'b1ALU第一个操作数来自A1寄存器
      • ALUSrc2E=2'b00ALU第二个操作数来自Imm寄存器
      • RegReadE[1]=1A1对应的寄存器值被使用到了
  • MEM阶段
    • 数据通路:
      • EX/MEM中得到ALU运算结果,送往数据存储器取出对应地址内容,内容送往MEM/WB寄存器
      • 从上一级获得控制信号并传入下一级
      • EX/MEM中得到Rd地址,送往MEM/WB寄存器
    • 控制信号:
      • LoadNpcD=0,将NextPC输出到ResultM
      • MemWriteM=4'b0000,不写内存
  • WB阶段
    • 数据通路:
      • MEM/WB中得到存储器内容,送往DataExt数据扩展单元扩展后送往寄存器堆
      • MEM/WB中得到Rd写回地址,送往寄存器堆用于写回上方内容
    • 控制信号:
      • MemToRegW=0,标志WB阶段指令需要从内存读取数据到寄存器
      • RegWriteW=1,写回目的寄存器x15
      • LoadedBytesSelect=4,相当于ResultW[3:0],即选取要取的4字节数据
4)指令sw x15, -20 x8

问题描述:分析指令sw x15, -20 x8,写出该指令在流水线五个阶段(IF、ID、EX、MEM和WB)关键的控制信号(参考RISC V电路设计图),并通过分析指出数据通路

答:这是一条S-型指令,它的作用是将寄存器x15中的值存储到地址为寄存器x8中的值减去20处的内存中。这条指令相当于更新局部变量i的值

  • IF阶段
    • 数据通路:
      • 根据PCF,从指令存储器中取出指令11111110111101000010011000100011
      • PC寄存器的值加4,更新为下一条指令的地址。
    • 控制信号:无
  • ID阶段
    • 数据通路:
      • 指令Inst传给Controller Decoder,生成控制信号
      • A2读入源寄存器地址(inst[24:20]),将读出的值RegOut2D送入ID/EX寄存器
      • A1读入目的寄存器地址(inst[19:15]),将读出的值RegOut1D送入ID/EX寄存器
      • Immediate Generate生成立即数,将立即数扩展为32位,送入ImmD,接着送入ID/EX寄存器。
    • 控制信号:
      • ImmType,S类型指令,需要生成立即数
  • EX阶段
    • 数据通路:
      • A1寄存器和ImmOperandUnit中取出两个源操作数,送入ALU进行加法运算,得到要写入的内存地址,送入ALUOutE,结果送入EX/MEM寄存器。
      • 从上一级获得控制信号并传入下一级
      • ID/EX中得到A2寄存器读出的值RegOut2E,送往EX/MEM寄存器
    • 控制信号:
      • AluContrlE=3,代表ALU执行ADD运算
      • Forward1E=2'b00,第一个操作数选择来自A1寄存器的值
      • Forward2E=2'b00,将A2寄存器读出的值RegOut2E传递下去
      • AluSrc1E=1'b1,代表ALU第一个操作数来自A1寄存器
      • AluSrc2E=2'b10,代表ALU第二个操作数来自Imm寄存器
      • RegReadE[1]=1A1对应的寄存器值被使用到了
  • MEM阶段
    • 数据通路:
      • EX/MEM寄存器读出要写入内存的值,通过StoreDataM写入Data MemoryWD接口
      • EX/MEM寄存器读出要写入的内存地址,AluOutM写入A接口
      • 从上一级获得控制信号并传入下一级
    • 控制信号:
      • LoadNpcD=1,将NextPC输出到ResultM
      • MemWriteM=1,本条指令需要将数据写入内存
  • WB阶段
    • 数据通路:无需进行写回操作。
    • 控制信号:
      • MemToRegW=0,不需要从内存读取数据到寄存器
      • RegWriteW=0,不需要写回目的寄存器
5)简述BranchE信号的作用

BranchE信号是指令执行(EX)阶段的一个控制信号,用于判断是否需要进行分支跳转。在流水线的EX阶段

  • 如果指令是分支指令,例如beq、bne等,那么BranchE信号将被设置为1,表示需要进行分支跳转。同时,根据指令的操作数和ALU的计算结果,计算出是否需要跳转,即将BrT信号设置为1或0。
    • 如果需要跳转,则将跳转目标地址计算出来,并将其写入PC寄存器,以便在下一次IF阶段时取出目标指令进行执行。
    • 否则,PC寄存器继续累加4,直接取出下一条指令进行执行
6)NPC Generator

NPC Generator 中对于不同跳转 target 的选择有没有优先级?如果有,请举例并分析。如果没有,请解释原因

答:有。

JalrT、BrT 和 JalT 是 RISC-V CPU 中用于控制跳转指令的信号。

  • JalrT:Jalr Target,用于指示 CPU 是否需要跳转到 Jalr 指令中给定的目标地址。当 JalrT 信号为高电平时,CPU 将跳转到 Jalr 指令中给定的目标地址。
  • BrT:Branch Target,用于指示 CPU 是否需要跳转到分支指令中给定的目标地址。当 BrT 信号为高电平时,CPU 将跳转到分支指令中给定的目标地址。
  • JalT:Jal Target,用于指示 CPU 是否需要跳转到 Jal 指令中给定的目标地址。当 JalT 信号为高电平时,CPU 将跳转到 Jal 指令中给定的目标地址。

Jalr 指令的目标地址是通过寄存器的内容计算得到的,而 Jal 指令的目标地址则是在指令中直接给出的。

branch和jalr是EX段跳转,而jal是在ID段跳转。所以必须设置优先级,使得在后的指令先跳转。因此JalrT和BrT的优先级高于JalT

同时,若修改数据通路,使得br,jal,jalr均在EX段跳转,则不会有冲突,此时也就不需要设置优先级。

4.附加思考题:

1)插入气泡

Harzard模块中,有哪几类冲突需要插入气泡(NOP指令),分别使流水线停顿几个周期。(提示:有三类冲突)

答:

  • RAW类冲突:如Load和ALU指令,在ALU计算时,操作数还未读出来。在EX段Stall,使流水线停顿1个周期
  • 控制相关的冲突:如在跳转时,需要插入气泡,flush掉IF段取的指令,停顿1个周期
  • 条件转移的冲突:在条件转移时,需要插入气泡,flush掉IF,ID段取的指令,停顿2个周期
2)branch指令

Harzard模块中,采用静态分支预测器,即默认不跳转,遇到branch指令时,如何控制flush和stall信号?

答:

Branch指令在EX段判断。如果发生分支,则需要Flush IF/ID和ID/EX段寄存器来保证数据不被后方指令错误使用。否则不需要flush或stall。

3.实验总结

在实验中,我学习了RISC-V指令集架构的基本概念和特点,了解了RISC-V Core的基本组成和工作原理,学习了每条指令的数据流和控制信号。

总的来说,通过本实验的学习,我对RISC-V指令集架构有了更深入的理解,了解了每条指令的数据流和控制信号,同时也对RISC-V Core的组成和工作原理有了更清晰的认识。在实验中,我还了解了一些常用的数字电路和计算机体系结构的概念,例如时钟信号、寄存器、ALU等等。

计算时,操作数还未读出来。在EX段Stall,使流水线停顿1个周期

  • 控制相关的冲突:如在跳转时,需要插入气泡,flush掉IF段取的指令,停顿1个周期
  • 条件转移的冲突:在条件转移时,需要插入气泡,flush掉IF,ID段取的指令,停顿2个周期
  • 12
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值