2023北航计组P7课下部分

(异常不和中断一起出现时指代总称异常)

任务清单

顶层模块篇

本次顶层模块,最终实例化四个部件:cpu、bridge、timer1、timer2,外界(tb)中实现DM、IFU和外界中断(外设)。你可能会对如何连接这些东西感到困惑,我只能说,反复看,反复感受。

新增元件篇

CP0

功能:识别异常/中断,并根据异常/中断记录下种类和EPC(受害者PC)
建议放到M级,这么做的人比较多,方便对拍
注:

  1. 退出异常的条件是发生eret指令
  2. 哪怕你采用分布式译码,BD信号和EPC也是需要流水的,这是因为延迟槽异常要求把EPC指向延迟槽所属的跳转指令,而分布式译码并直接连接M段控制信号在阻塞时发生延迟槽异常就会出现问题(同时,对于放到M级的CP0,宏观PC(就是M段PC也会出问题,因为阻塞插入的nop在不处理的情况下PC是0)。这些问题如何解决,信号如何流水见后。
  3. reset 与 EXLClr 的操作是不一样的

    if(reset)begin
        SR<=0;
        Cause<=0;
        EPC<=0;
    end
    else
    if(EXLClr==1'b1)
    begin
        SR[1]<=1'b0;
    end
    else
    begin
        if(en)begin
        	//tackle with mtc0
        end
        else;

        if(Req)begin
        	//tackle with req
        end
        else;
        
        Cause[15:10] <= HWInt;
    end
end
  1. 每个周期都需要更新存储中断信号,哪怕当前不能发生中断。
  2. addr、CP0In和CP0Out是用于处理mfc0和mtc0指令的

功能:连接cpu和DM、timer1、timer2,将正确的数据传回cpu、传给timer1、timer2和外部部件。实现起来并不困难。

计时器

给了现成的代码,重点是理解其功能模式和如何工作。在顶层电路中,实例化举例如下:
德
TCDout即对应的中断信号,传递给桥,由桥将外部中断信号、两个timer中断信号拼成完整的中断信号,并传递回cpu,传递给CP0供其比较允许发生的中断类型和是否能发生中断,最终决定是否中断。

已有元件修改篇(因人而异)

识别新异常

枫丹
最终采取如上的异常识别顺序。
F段识别取指异常,D段识别未知指令,E段识别算数溢出、存数/取数地址计算溢出,M段处理取数/存数地址不对齐等各种异常。中断直接提交给CP0特殊处理。

其他异常都好理解,M段的异常可能有些不好理解,因为我的实现过于丑陋,贴一段学长的代码。他是将溢出信号流水了,我觉得太麻烦,所以将溢出放在E段处理。

wire ErrAlign = ((DMType == `DM_w) && (|addr[1:0])) ||
                (((DMType == `DM_h) || (DMType == `DM_hu)) && (addr[0]));
wire ErrOutOfRange = !( ((addr >= `StartAddrDM) && (addr <= `EndAddrDM)) ||
                        ((addr >= `StartAddrTC1) && (addr <= `EndAddrTC1)) ||
                        ((addr >= `StartAddrTC2) && (addr <= `EndAddrTC2)));
wire ErrTimer = (DMType != `DM_w) && (addr >= `StartAddrTC1);
wire ErrSaveTimer = (addr >= 32'h0000_7f08 && addr <= 32'h0000_7f0b) ||
                    (addr >= 32'h0000_7f18 && addr <= 32'h0000_7f1b); // cannot access count of timer
assign excAdEL = load && (ErrAlign || ErrOutOfRange || ErrTimer || excOvDM);
assign excAdES = store && (ErrAlign || ErrOutOfRange || ErrTimer || ErrSaveTimer || excOvDM);

在ALU中,溢出的判断方法是(举例加法,减法同理):
海薇玛夫人

需要注意:

  1. 对于同一条指令,越靠近F段的异常,优先级越高。表现为第三条
  2. 对于不同的指令,越靠近M段的异常,优先级越高。表现为第四条
  3. 为实现以上效果,每一段的异常是需要流水的,举例如下(E段):谢贝蕾妲小姐
    也就是说,如果流水的异常信号已经不为0,即在之前的段中已经发生了异常,那么已经发生的异常优先级更高,否则就判断新的异常。
空泡问题

当发生异常时,需要清空寄存器,修改PC,并通过CP0确保不会接受新的异常。但是该过程的“清空”与reset是不一样的,为了保证宏观PC的正确输出,当因异常而清空寄存器时,需要修改PC的值为异常进入程序的PC(这也是为什么要流水PC和BD)。
还有一个问题,因阻塞而插入的nop指令,其对应的PC值是0,因此在因阻塞而清空寄存器时,注意PC需要更新为输入的PC(这么做意味着nop的PC等同于下一条指令的PC,想一想为什么可以这么做)。举例D/E寄存器清空如下(每个寄存器的实现都不一样,不能照搬):

if(CLR==1'b1||reset==1'b1||req)//D->E register
    begin
        InstrTemp<=32'h00000000;
        PCPlus4Temp<= stall ? PCPlus4D : (req ? 32'h0000_4184 : 0);
        
        if(stall==1'b1)
            BD_Temp<=BD_D;
        else
            BD_Temp<=0;
        GPR_rsTemp<=0;
        GPR_rtTemp<=0;
        ImmTemp<=0;
        excTemp<=0;
    end
实现新指令
冲突处理单元

自行更新冲突控制单元的内容,根据你采用谨慎转发法(AT法)和懒惰转发法,实现方法不一样。我提供谨慎转发法的一个思路:

注意!以下讨论中省略不提mfc0/mtc0与mflo/mfhi/mtlo/mthi的rs、rt、rd区别!但两种指令目标寄存器地址差别很大,需要着重注意!!!!!

首先,在冲突处理中mfc0和mflo很相似,Tnew取值可以等同。而mfc0并不会用到32个通用寄存器的值,所以把Tuse设为inf(我的处理中是设成2’b11)即可。

而mtc0,虽然会写寄存器,但是写的是CP0里的寄存器,一般情况下并不会因为这个引发冲突。可以把这个指令和mtlo做类比,来设置它的Tuse。试想,如果mtc0指令后紧跟一条mfc0,会怎么样呢?答案显然,因为两个都是在M段才发挥真正的作用,因此无需做任何处理,只需要把mfc0的Tnew设置到M段以后才得到正确结果即可。

然后就是eret。在什么情况下eret会需要阻塞呢?在用mtc0写EPC的值时。(我的设计中NPC在D段)然而eret在D段发挥作用,mtc0在M段发挥作用,这种情况下就需要阻塞到mtc0完成功能以后。为了方便,我只写了相对应的阻塞,即新设置一Tuse_EPC,只有eret指令设为2,其他指令设为3,然后在阻塞判断时,新增对应的逻辑。举例如下:

    stall_CP0=((Tuse_EPC==2'b10)&&(TnewE==2'b10)&&(A3E==14))||
                ((Tuse_EPC==2'b10)&&(TnewM==2'b01)&&(A3M==14));

    Stall=Stall_RT|Stall_RS|stall_HILO|stall_CP0;//暂停处理完毕

我这种做法难以避免会出现误阻塞的情况,但是因此导致的额外周期可以忽略不计。

mfc0/mtc0

这两条指令的实现过程和乘除模块的mf/mt很像,完全可以照抄,但是需要注意的是,mfc0写入的是rt寄存器,而mfhimflo写入的是rd寄存器,mtc0rt的数据写进去,但是mthimtlo是将rs的数据写进去

eret

需要注意两点:

  1. 该指令代表退出异常状态,需要注意
  2. 该指令无延迟槽。我的解决办法是通过根据D段控制信号控制F/D寄存器输入来人为插入一个nop指令,抵消掉延迟槽,该方法不会受阻塞影响,可靠。

乌瑟勋爵

细节

1、
异常发生时,乘除槽除了reset以外的行为要被冻结

2、
如何编写mars程序?
分成两段编写,分别是正常的测试程序和异常处理程序。测试程序就是正常的测试,试探能否正确识别异常和中断,异常处理程序不用教程弄得那么麻烦,就简单粗暴的
取EPC->取BD->根据BD将EPC加4或加8->放回EPC->响应中断(用教程给的sb指令)->eret退出异常
然后分别导出十六进制代码,并将测试程序代码补全到(从1开始数)1121行,用00000000补全,然后再把异常处理程序粘贴上去,就可以了。而在Mars里,异常处理程序粘贴到测试程序文件尾部,并在前面加上.ktext 0x4180即可

注意!mars可能有部分行为是错误的!和同学对拍更保险!
比如,mars的计时器存在很大问题,因为mars内置cpu采用单周期实现,和我们的五段全速转发流水线cpu有很大区别。

3、
芙宁娜世界第一可爱

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
北航计组Verilog是指北京航空航天大学计算机学院的计算机组成原理课程设计中使用的Verilog HDL语言。Verilog HDL是一种硬件描述语言,用于设计和建模数字电路。在北航计算机学院的计算机组成原理课程设计中,学生需要使用Verilog HDL来实现一些具体的题目和实例,如课程设计中的PreProject-Verilog HDL与ISE Verilog题目实例与分析以及PreProject-Verilog HDL与ISE的获取和使用。通过这些实践,学生可以学习和理解Verilog HDL的基本语法和使用方式,以及时序电路的建模与分析。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [北航计算机组成原理课程设计-2020秋 PreProject-Verilog HDL与ISE-Verilog题目实例与分析](https://blog.csdn.net/JeremyZhao1998/article/details/113569664)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [北航计算机组成原理课程设计-2020秋 PreProject-Verilog HDL与ISE-ISE的获取和使用](https://blog.csdn.net/JeremyZhao1998/article/details/109180170)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰雾与红

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值