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

HNU计算机体系结构-实验一

  • 前言
    • 1.实验目的
    • 2.实验步骤
      • 1.安装模拟器Ripes
      • 2.生成汇编指令
      • 3.思考问题
        • 1)指令`add x15, x14, x15`
        • 2)指令`bge x15 x14 -68`
        • 3)指令`lw x15, -20 x8`
        • 4)指令`sw x15, -20 x8`
        • 5)简述BranchE信号的作用
        • 6)NPC Generator
      • 4.附加思考题:
        • 1)插入气泡
        • 2)branch指令
    • 3.实验总结

前言

体系结构的第一个实验,实际上是中科大的实验,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个周期

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/29221.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中级前端笔试面试题总结

typeof null 的结果是什么&#xff0c;为什么&#xff1f; typeof null 的结果是Object。 在 JavaScript 第一个版本中&#xff0c;所有值都存储在 32 位的单元中&#xff0c;每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的…

(浙大陈越版)数据结构 第三章 树(中) 二叉搜索树和平衡二叉树

目录 4.1.1 二叉搜索树及查找 什么是二叉搜索树 定义 二叉搜索树特殊函数集&#xff1a; 查找操作&#xff1a;Find 算法思想 代码实现 补&#xff1a;查找最大和最小元素 4.1.2 二叉搜索树的插入 插入操作&#xff1a;Insert 算法思想 代码实现 例题 4.1.3 二叉…

吴恩达老师《机器学习》课后习题1之线性回归

在学习这些内容之前&#xff0c;需要学习python数据分析相关内容&#xff1a; numpy&#xff1a;科学计算库&#xff0c;处理多维数组&#xff0c;进行数据分析 pandas&#xff1a;基于numpy的一种工具&#xff0c;该工具是为了解决数据分析任务而创建的 matplotlib&#xff1a…

如何进行微服务测试?

微服务测试是一种特殊的测试类型&#xff0c;因为它涉及到多个独立的服务。以下是进行微服务测试的一般性步骤&#xff1a; 1. 确定系统架构 了解微服务架构对成功测试至关重要。确定每个微服务的职责、接口、依赖项和通信方式。了解这些信息可以帮助您更好地规划测试用例和测…

Aop详解

AOP简介 AOP是一种编程思想&#xff0c;就如同面向对象这种编程思想一样&#xff0c;是一种编程范式&#xff0c;用来指导开发者如何组织程序更好的运行 AOP&#xff08;面向切面编程&#xff09; 作用&#xff1a;在不改变原代码的前提下&#xff0c;为其增加功能。 连接点…

Apikit 自学日记:导入第三方产品 API 数据

除了手动创建API文档&#xff0c;系统也提供了一键导入 Swagger、Postman、RAP、YAPI 等产品数据的功能。方便从其他平台进行迁移。 产品支持度导入文件的后缀名Eolinker API 研发管理完全支持.jsonPostman V2.1支持导入API基础信息&#xff0c;超过10级分组的API数据将不会被导…

git在windows及linux(源码编译)环境下安装

git在windows及linux(源码编译)环境下安装 环境信息: 系统版本:CentOS Linux release 7.9.2009 (Core) git指令安装: yum install -y git 一、git在windows下安装 下载地址:https://git-scm.com/ 默认安装即可 验证 git --version 二、git在linux下安装 下载地址…

游戏场景的转换——状态模式

状态模式 游戏比较复杂时&#xff0c;通常会设计成多个场景。 切换场景的好处 1、重复使用场景 跳转切换场景的代码有两种一种是旧版的方法 Application.LoadLevel(“SampleScene”);另一种是新版的方法 SceneManager.LoadScene(“SampleScene”); 例子1&#xff1a;通过场景…

【QT】TCP/UDP详解及实现

TCP/UDP TCP/IP模型TCP协议头部格式三次握手四次挥手 UDP协议头部格式 Socket编程tcpudp代码实现服务端&#xff1a;客户端&#xff1a; 总结 TCP/IP模型 TCP模型是一个常见的网络协议参考模型&#xff0c;也称为TCP/IP模型或互联网模型。它是指TCP/IP协议族中的一组协议&…

Creating Add-in Hooks (C#)

本文介绍如何使一个文件在添加、检入、检出到库时&#xff0c;让add-in 程序在SOLIDWORKS PDM Professional 中通知到你。 注意&#xff1a; 因为 SOLIDWORKS PDM Professional 无法强制重新加载Add-in程序 &#xff0c;必须重新启动所有客户端计算机&#xff0c;以确保使用最…

【Python开发】FastAPI 09:middleware 中间件及跨域

FastAPI 提供了一些中间件来增强它的功能&#xff0c;类似于 Spring 的切面编程&#xff0c;中间件可以在请求处理前或处理后执行一些操作&#xff0c;例如记录日志、添加请求头、鉴权等&#xff0c;跨域也是 FastAPI 中间件的一部分。 目录 1 中间件 1.1 创建中间件 1.2 使…

MySQL常见问题

优化慢查询 慢查询可能出现的情况&#xff1a; 聚合查询多表查询表数据量过大深度分页查询 表象&#xff1a;页面加载过慢&#xff0c;接口压测响应时间过长&#xff08;超过1s&#xff09; 如何定位慢查询&#xff1f; 方案一&#xff1a;开源工具 可以使用相应的调试工具&a…

EMC学习笔记(三)滤波

滤波 1.概述2.滤波器件2.1 电阻2.2 电感2.3 电容2.4 铁氧体磁珠2.5 共模电感 3.滤波电路3.1 滤波电路的形式3.2 滤波电路的布局与布线 4.电容在PCB的EMC设计中的应用4.1 滤波电容的种类4.2 电容自谐振问题4.3 ESR对并联电容幅频特性的影响4.4 ESL对并联电容幅频特性的影响4.5 电…

LarkXR知识库 | 开发者社区FAQ合集(二)

LarkXR是一套基于GPU云化、图形容器、音视频实时编解码、网络传输优化等核心技术的通用型实时云渲染解决方案&#xff0c;帮助XR领域企业级用户及开发者快速搭建XR应用上云通道&#xff0c;使其在各类智能终端上流畅的运行、使用及传播。 平行云开发者社区上线以来&#xff0c…

【计算机网络复习之路】运输层(谢希仁第八版)万字详解 主打基础

专栏&#xff1a;计算机网络复习之路 运输层是OSI七层模型中最重要最关键的一层&#xff0c;是唯一负责总体数据传输和控制的一层。运输层要达到两个主要目的&#xff1a;第一&#xff0c;提供可靠的端到端的通信&#xff08;“端到端的通信” 是应用进程之间的通信&#xff09…

HTML type=“radio“ 不显示按钮

问题 HTML中type&#xff1d;"radio" 但是在界面中不显示按钮。 详细问题 HTML中type&#xff1d;"radio" 但是在界面中不显示按钮。 笔者html核心代码 <div>性别<input type"radio" id"male" name"gender" va…

Jmeter HTTP Cookie管理器的使用

目录 前言&#xff1a; 1、在HTTP信息头管理器组件中添加Cookie信息 &#xff08;1&#xff09;测试计划内包含的元件 &#xff08;2&#xff09;请求取样器内容 &#xff08;3&#xff09;HTTP信息头管理器内容 &#xff08;4&#xff09;查看结果 2、使用HTTP Cookie管…

年度创新企业奖!移远通信成推动AIoT融合落地关键力量

6月8日&#xff0c;由ASPENCORE主办的2023国际AIoT生态发展大会在深圳召开&#xff0c;移远通信受邀出席大会并发表演讲&#xff0c;同时凭借在5G、AIoT等领域的持续创新荣获“年度创新企业”奖&#xff01; 5GAIoT“双引擎” 重塑物联产业 近些年&#xff0c;从互联网、物联网…

Git->分支

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Git ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&#x…

11.vue3医疗在线问诊项目 - _药品订单 ==> 支付页面、支付详情、支付结果、订单详情、物流信息、高德地图工具

11.vue3医疗在线问诊项目 - _药品订单 &#xff1e; 支付页面、支付详情、支付结果、订单详情、物流信息、高德地图工具 药品订单-支付页面-路由 目标&#xff1a;配置路由&#xff0c;分析药品支付组件结构 1&#xff09;路由与组件 {path: /medicine/pay,component: () >…