• OpenRisc-50-or1200的freeze模块分析


    引言

    之前,我们分析or1200的控制通路中的sprs模块和except模块,本小节,我们就分析一下or1200控制通路的最后一个模块,就是freeze模块。

    1,整体分析

    freeze模块,顾名思义,就是根据各个流水阶段的反馈信号,负责产生控制整条流水线各个阶段的暂停信号,如取指阶段的genpc_freeze和if_freeze信号,解码阶段的id_freeze信号,执行阶段的ex_freeze信号,以及写回阶段的wb_freeze信号,共5个暂停信号。

    可以这么说,freeze就好像整条流水线的监工,如果发现某一阶段出现问题,就控制那个流水阶段暂停。

    2,暂停信号产生规则

    freeze模块产生的这5个信号不是相互独立的,是有一定的规则的,那么到底有什么规则呢?关于freeze模块的5个暂停信号的产生过则,or1200_freeze.v中有如下描述:

    //
    // Pipeline freeze
    //
    // Rules how to create freeze signals:
    // 1. Not overwriting pipeline stages:
    // Freeze signals at the beginning of pipeline (such as if_freeze) can be 
    // asserted more often than freeze signals at the of pipeline (such as 
    // wb_freeze). In other words, wb_freeze must never be asserted when ex_freeze 
    // is not. ex_freeze must never be asserted when id_freeze is not etc.
    //
    // 2. Inserting NOPs in the middle of pipeline only if supported:
    // At this time, only ex_freeze (and wb_freeze) can be deassrted when id_freeze
    // (and if_freeze) are asserted.
    // This way NOP is asserted from stage ID into EX stage.
    //


    那如何理解呢?

    关于第一条:

    这一条比较容易理解,就是说流水线的某一个阶段如果想产生暂停信号,那么这个阶段的前一个流水阶段必须先产生。假如要想产生wb_freeze信号,必须先产生ex_freeze信号。

    问什么要有这条规则呢?为了便于理解,我们假设一个情景来说明一下。

    我记得我小的时候,我们家每年会种几亩地的西瓜,等西瓜成熟的时候,我爸妈会开着农用车,带着我和我的两个弟弟(老四和老五)去地里摘西瓜,为了加快速度,我们各有分工,我爸负责把西瓜从瓜藤上摘下来,并送到我妈手里,我妈负责把西瓜传到我手里,我负责把这个西瓜送到站在车旁边的老四,老四负责把西瓜递给在车上的老五,老五负责将西瓜慢慢的堆放到车上。

    上面的情景分别对应流水线的五个阶段,假如我在摘瓜的过程中突然感觉口渴了,想去喝点水,那么我妈必须先暂停下来,要不然,如果我妈把西瓜向我扔来,但我这时我在喝水,那么这个西瓜就肯定会摔碎。所以,我妈必须先停下来,同样道理,我妈要想停下来,我爸必须也停下来。

    如果处在最末端的我的老五如果想想停下来,根据这条规则,那么处在最开始的我爸爸也必须停下来,否则的话就会出问题。

    还回到流水线,这条规则保证了不会有指令丢失。设想一下,如果流水线的EX阶段暂停了,ID阶段却没暂停下来,就会出现ID阶段解码的指令,EX不会执行的情况。

    关于第二条:

    如果说第一条是规定暂定信号产生规则的话,那么第二条就是规定暂停信号如何解除了。举个例子,如果EX阶段要想解除暂停信号,那么EX阶段的前面的阶段必须不能解除,否则的话就会违背第一条规则了。

    3,代码分析

    了解了freeze模块的功能和暂停信号的产生规则之后,那rtl代码具体是如何实现的呢?

    首先是取指阶段的暂停信号,代码如下:

    assign genpc_freeze = (du_stall & !saving_if_insn) | flushpipe_r;
    assign if_freeze = id_freeze | extend_flush;



    这里需要说明的是,如果在取指阶段出现问题,比如出现指令总线的应答错误,那么就需要刷新流水线,代码如下:

    //
    // registered flushpipe
    //
    always @(posedge clk or `OR1200_RST_EVENT rst)
    	if (rst == `OR1200_RST_VALUE)
    		flushpipe_r <=  1'b0;
    	else if (icpu_ack_i | icpu_err_i)
    //	else if (!if_stall)
    		flushpipe_r <=  flushpipe;
    	else if (!flushpipe)
    		flushpipe_r <=  1'b0;



    其次是解码,执行和写回阶段的暂停信号,代码如下:

    assign id_freeze = (lsu_stall | (~lsu_unstall & if_stall) | multicycle_freeze 
    		    | (|waiting_on) | force_dslot_fetch) | du_stall;
    assign ex_freeze = wb_freeze;
    
    assign wb_freeze = (lsu_stall | (~lsu_unstall & if_stall) | multicycle_freeze 
    		    | (|waiting_on)) | du_stall | abort_ex;


    需要说明的是这三个阶段的暂停信号的产生有一个多周期的问题,和流水线等待问题。

    or1200的大部分指令都需要一个指令周期,但是有几条指令需要多个指令周期,如果需要这几条指令时,就需要暂停信号,代码如下:

    //
    // Multicycle freeze
    //
    assign multicycle_freeze = |multicycle_cnt;
    
    //
    // Multicycle counter
    //
    always @(posedge clk or `OR1200_RST_EVENT rst)
    	if (rst == `OR1200_RST_VALUE)
    		multicycle_cnt <=  `OR1200_MULTICYCLE_WIDTH'd0;
    	else if (|multicycle_cnt)
    		multicycle_cnt <=  multicycle_cnt - `OR1200_MULTICYCLE_WIDTH'd1;
    	else if (|multicycle & !ex_freeze)
    		multicycle_cnt <=  multicycle;


    那么都有哪些指令是多周期指令呢?or1200_define.v中相关代码如下:

    // Execution control which will "wait on" a module to finish
    `define OR1200_WAIT_ON_WIDTH 2
    `define OR1200_WAIT_ON_NOTHING    `OR1200_WAIT_ON_WIDTH'd0
    `define OR1200_WAIT_ON_MULTMAC    `OR1200_WAIT_ON_WIDTH'd1
    `define OR1200_WAIT_ON_FPU        `OR1200_WAIT_ON_WIDTH'd2
    `define OR1200_WAIT_ON_MTSPR      `OR1200_WAIT_ON_WIDTH'd3


    此外,在遇到一些特殊情况,流水线需要等待(wait_on),这时,也需要暂停流水线,代码如下:

    //
    // Waiting on generation
    //
    always @(posedge clk or `OR1200_RST_EVENT rst)
      if (rst == `OR1200_RST_VALUE)
        waiting_on <= 0;
      else if ((waiting_on == `OR1200_WAIT_ON_MULTMAC) & !mac_stall)
        waiting_on <= 0;   
      else if ((waiting_on == `OR1200_WAIT_ON_FPU) & fpu_done)
        waiting_on <= 0;
      else if ((waiting_on == `OR1200_WAIT_ON_MTSPR) & mtspr_done)
        waiting_on <= 0;
      else if (!ex_freeze)
        waiting_on <= wait_on;


    关于wait_on信号的产生,我们在分析ID模块(ctrl)时,已经介绍过了,如有疑问请参考: http://blog.csdn.net/rill_zhen/article/details/9816129

    4,小结

    freeze模块是整条流水线的大管家,控制着流水线的暂停和执行大权,但其代码却没有想象的那么复杂,越是深奥的道理,一般使用的语言都非常简单,freeze模块也正好证明了这一点。

    自此,我们将or1200的数据通路和控制通路都分析了一下,剩下的工作就是其它可选但却不可或缺的debug模块,负责精确定时的tick timer模块,以及负责整个CPU功耗管理的power management模块了。

    革命尚未成功,同志仍需努力。

  • 相关阅读:
    【开发者成长】喧哗的背后:Serverless 的挑战
    都在说实时数据架构,你了解多少?
    谊品生鲜:放弃传统数据库架构,全站上阿里云
    纯干货 | 一篇讲透如何理解数据库并发控制
    作为后端开发如何设计数据库系列文章(二)设计大数据量表结构
    如果千百年前有视觉AI算法,世界将会是什么样的光景呢?
    淘宝万亿级海量交易订单存储在哪?
    跬步千里 —— 阿里云Redis bitfield命令加速记
    容器环境自建数据库、中间件一键接入阿里云 Prometheus 监控
    常用Maven插件介绍(转载)
  • 原文地址:https://www.cnblogs.com/pangblog/p/3297214.html
Copyright © 2020-2023  润新知