欢迎光临
我们一直在努力

探索Vortex开源GPGPU:RISC-V SIMT架构(6),Schedule

目录

前言

一、Schedule端口

二、Schedule代码分析

2.1 schedule_if

2.2 decode_sched_if

2.3 issue_sched_if

2.4 commit_sched_if

2.5 warp_ctl_if

2.6 sched_csr_if

2.7 branch_ctl_if

2.8 base_dcr

2.9 gbar_bus_if

2.10 其他功能

总结


前言

本篇重点分析Vortex RISC-V内核的6级流水线之六,Schedule部分,是SIMT的核心和总控部件。

严格的说,Schedule是Fetch的上游,应该是第0级。放在最后,当作最后一级来分析,是因为在分析其他流水线的时候,就把它们跟Schedule接口信号及其功能都了解了大部分,剩下的一些边角放在最后,同时把之前分析的功能再串讲一下,整体上更容易加深理解。

本系列"探索Vortex开源GPGPU:RISC-V SIMT架构"


一、Schedule端口

基于Schedule与其他5级流水线的接口信号,从前端到后端,如下8个端口,以下表格列出了基本信息,代码分析依此顺序展开。

Fetch schedule_if Schedule产生uuid/wid/PC送到Fetch
Decode decode_sched_if Decode通知Schedule,当前warp已经执行完毕,可以继续产生新PC
Issue issue_sched_if 通知Schedule当前warp已经开始送到下一级,执行开始
Commit commit_sched_if 通知Schedule当前warp已经处理完毕,执行结束
Execute warp_ctl_if 自定义6条指令的启动/执行/结束:wspawn/tmc/split/join/barrier/pred
Execute sched_csr_if

提供CSR要读的信息:激活的warp掩码,当前warp的线程掩码,warp执行完毕标志

Execute branch_ctl_if Execute ALU提供Branch相关的信号
DCR  base_dcr 复位期间提供内核启动地址,内核缓冲区结构体指针
gbar_bus_if 往socket/cluster传播全局barrier信息,并反向广播全局barrier清除信号

    // configuration     input base_dcrs_t       base_dcrs,                          //SFU CSR章节,复位时设置启动地址

    // inputsdecode_if     VX_warp_ctl_if.slave    warp_ctl_if,                       //SFU wctl章节,控制自定义6条

                                                                                   //指令的执行

    VX_branch_ctl_if.slave  branch_ctl_if [`NUM_ALU_BLOCKS],  //控制跳转指令执行

    VX_decode_sched_if.slave decode_sched_if,       

                                                                   //Decode章节,通知Schedule某一个warp的PC

                                                                   //已经译码,它可以开始这个warp的下一条PC

    VX_issue_sched_if.slave issue_sched_if[`ISSUE_WIDTH],

                                                                  //SFU章节,和commit_sched_if配合,用来统计

                                                                  //同一warp的pending_size(未执行完毕标志)     VX_commit_sched_if.slave commit_sched_if,         

  

    // outputs     VX_schedule_if.master   schedule_if,                      //Fetch章节,Fetch流水线的输入信号

`ifdef GBAR_ENABLE     VX_gbar_bus_if.master   gbar_bus_if,                     //SFU wctl章节,处理全局barrier,                                                                                          //要往socket和cluster传播,并且反

                                                                                      //向广播全局barrier解锁信号 `endif     VX_sched_csr_if.master  sched_csr_if,                   //SFU章节,提供CSR读数据,以及

                                                                                     //各个warp的完成标志(FPU CSR读写

                                                                                     //需要这个标志)

    // status     output wire             busy

二、Schedule代码分析

2.1 schedule_if

schedule_if的三个功能:

  • 最基本的功能是产生PC地址;
  • 其次后面的icache(Fetch流水线)/dcache(Execut流水线)总线的要求是要有一个类似AXI ID的边带信号,在Vortex这边就是uuid;
  • 对于SIMT处理器来说,功能上必然要支持warp ID(wid),线程掩码(tmask)

为了timing能做得更高,schedule和fetch之间加了一个full timing slice,全缓冲valid/ready/data。

同样的原因,从fetch的bus response直到decode译码结果送到Issue,全部路径都是组合逻辑,所以Issue的ibuffer也是起了一个timing slice的作用。

相关PC/uuid/wid/tmask代码如下:

  

  VX_elastic_buffer #(         .DATAW (`NUM_THREADS + PC_BITS + NW_WIDTH + UUID_WIDTH),         .SIZE  (2),          .OUT_REG (1)      ) out_buf (        //配置成full timing slice, 隔离schedule和fetch之间的valid/read/data         .clk       (clk),         .reset     (reset),         .valid_in  (schedule_valid),         .ready_in  (schedule_ready),         .data_in   ({schedule_tmask, schedule_pc, schedule_wid, instr_uuid}),         .data_out  ({schedule_if.data.tmask, schedule_if.data.PC, schedule_if.data.wid, schedule_if.data.uuid}),         .valid_out (schedule_if.valid),         .ready_out (schedule_if.ready)     );     wire schedule_fire = schedule_valid && schedule_ready;     wire schedule_if_fire = schedule_if.valid && schedule_if.ready;  

      if (schedule_if_fire) begin            //在schedule_if_fire,warp的PC值自增

                                                          //实际上也可以用schedule_fire

                                                          //用schedule_if_fire更好一点,路径短             warp_pcs_n[schedule_if.data.wid] = schedule_if.data.PC + from_fullPC(`XLEN'(4));       end                                              //还有3种情况改变PC:wspawn/join/branch

    VX_uuid_gen #(         .CORE_ID (CORE_ID)     ) uuid_gen (                                    //产生uuid         .clk   (clk),         .reset (reset),         .incr  (schedule_fire),         .wid   (schedule_wid),         .uuid  (instr_uuid)   //uuid[43:0]={core_id, wid, incremental_counter[31:0]}     );   

       if (schedule_fire) begin                //送出uuid/wid/PC时,锁住当前warp

                                                           //stalled_warps是stalled_warps_n的寄存器信号             stalled_warps_n[schedule_wid] = 1;        end

   wire [`NUM_WARPS-1:0] ready_warps = active_warps & ~stalled_warps;     VX_priority_encoder #(         .N (`NUM_WARPS)     ) wid_select (                                    //优先级编码产生warp ID(wid)         .data_in   (ready_warps),             //active_warps是当前激活的warp掩码

                                                             //受wspaw/tmc/pred影响

                                                             //stalled_warps是当前停止的warp掩码

                                                             //指令发到Fetch,就lock住,两个条件解锁

                                                             //a) 一般指令在Decode阶段解锁  

                                                             //b) 特别指令由相应的后级流水线解锁

                                                             //详细3种特例见Decode章节描述         .index_out (schedule_wid),         .valid_out (schedule_valid),         `UNUSED_PIN (onehot_out)     );

           //线程掩码tmask的逻辑比较分散,它的置位受4个指令控制

           //tmc/pred/split/join, 它的清0受tmc/pred/barrier控制

           //split/join还引入了ipdom_stack来处理条件分支和汇聚,参见SFU第2个章节

           //总的来说,wid和tmask的执行顺序:

           //Execute流水线的wctl_unit发出6种自定义指令的有效请求,送到Shedule

           //Execute流水线的csr_unit发出FPU CSR解锁warp请求,送到Schedule

           //详细过程,代码分析见Execute SFU的4个章节,这里略过

           //Execute流水线的alu_int发出branch请求,送到Schedule

2.2 decode_sched_if

        //对于一般指令,当Decode流水线数据流被Issue流水线接收时,解锁schedule的warp         if (decode_sched_if.valid && decode_sched_if.unlock) begin             stalled_warps_n[decode_sched_if.wid] = 0;         end

2.3 issue_sched_if

2.4 commit_sched_if

issue_sched_if/commit_sched_if关联在一起,用来产生每个warp的待处理计数器

  //每个warp待处理计数器 

  for (genvar i = 0; i < `NUM_WARPS; ++i) begin : g_pending_sizes

        localparam isw = wid_to_isw(i);  //issue width         localparam wis = wid_to_wis(i);  //warp index

        VX_pending_size #(             .SIZE      (4096),             .ALM_EMPTY (1)         ) counter (             .clk       (clk),             .reset     (reset),         //Issue operands_if 输出端有效握手,计数器自增             .incr      (issue_sched_if[isw].valid && (issue_sched_if[isw].wis == wis)),             .decr      (commit_sched_if.committed_warps[i]),

                                               //Commit WB有效握手,延迟一拍,计数器再自增             .empty     (pending_warp_empty[i]),              //zero pending,warp全部处理完             .alm_empty (pending_warp_alm_empty[i]),   // 1 pending, 只剩一个warp,还未传到

                                                                                   // Commit流水线             `UNUSED_PIN (full),             `UNUSED_PIN (alm_full),             `UNUSED_PIN (size)         );   //counter for each WARP     end

2.5 warp_ctl_if

6个自定义指令的处理通过warp_ctl_if来传递,方向是从Execute SFU的wctl_unit到Schedule。这个接口涉及了SIMT最基本也是最重要的功能:

  • warp的启动和停止
  • 线程的启动和停止
  • 条件判断的分支聚合,原因是SIMT架构下,同一warp的线程要共享PC
  • 同步功能,core内,和core之间,既本地barrier和全局barrier的设置

具体细节见SFU  4个章节, 第3点用了ipdom_stack,是一个比较巧妙的动态分组解决办法。

2.6 sched_csr_if

    assign sched_csr_if.alm_empty = pending_warp_alm_empty[sched_csr_if.alm_empty_wid];

                                                                                    //通知csr_unit,当前的warp ID是

                                                                                    //流水线中同ID的最后一个待处理                                                                                     //在csr_unit中处理FPU CSR读写

                                                                                    //时,要等待这个信号,具体原因

                                                                                    //不清楚,暂且记下来

    assign sched_csr_if.active_warps = active_warps;    //激活warp和允许线程送到csr_unit     assign sched_csr_if.thread_masks = thread_masks; //CSR指令可以读取这些信息

2.7 branch_ctl_if

Execute ALU中分支相关指令的处理信息也要送到Schedule,解锁warp和跳转。

注意的是它不是放到Commit流水线来做这一步,这和Execute SFU wctl_unit类似,越早解锁warp意味着core可以处理更多事情。

  • JAL(UJ类型,20位正负偏移跳转,16b对齐), JALR(I类型,11位正负偏移跳转)
  • SB类型所有指令(12位正负偏移跳转,16b对齐)
  • I类型中的INST_SYS,处理ECALL/EBREAK/URET/SRET/MRET

指令信息详细见Decode章节

             //NUM_ALU_BLOCKS跟ISSUE_WIDTH相等,等于NUM_WARPS/16

        for (integer i = 0; i < `NUM_ALU_BLOCKS; ++i) begin             if (branch_valid[i]) begin                 if (branch_taken[i]) begin                     warp_pcs_n[branch_wid[i]] = branch_dest[i];   //设定warp新PC                 end                 stalled_warps_n[branch_wid[i]] = 0; //解锁warp             end         end

2.8 base_dcr

base_dcr功能很简单,提供第一个warp的启动地址

            // activate first warp             warp_pcs[0]     <= from_fullPC(base_dcrs.startup_addr);

2.9 gbar_bus_if

处理全局barrier的接口,从下往上逐级传播全局同步请求,在socket/cluster内仲裁,最后由cluster的gbar_unit返回全局barrier清除信号,同时广播到各个core清除全局barrier请求,详见SFU第3章节

2.10 其他功能

  • busy信号,busy信号送到Vortex的IO PIN作为观察信号。这个busy有点不合理,因为某个指令流可能在Decode之后,Issue Operands之前,而pending_size计数器在Issue Operands才开始自增计数,这样漏掉了中间的流水线逻辑,它们实际上是busy的状态。

    `BUFFER_EX(busy, (active_warps != 0 || ~no_pending_instr), 1'b1, 1, 1);                        //有激活的warp,或者warp全部都禁掉,但是有待处理的warp还在流水线上

            if (busy) begin                 cycles <= cycles + 1;             end     //忙周期统计信息

    always @(posedge clk) begin //debug手段,用来动态监测是否有长时间死锁的情况         if (reset) begin             timeout_ctr    <= '0;             timeout_enable <= 0;         end else begin             if (decode_sched_if.valid && decode_sched_if.unlock) begin                 timeout_enable <= 1;             end                                 //有激活的warp并且全部都锁住,timeout计数器自增             if (timeout_enable && active_warps !=0 && active_warps == stalled_warps) begin                 timeout_ctr <= timeout_ctr + 1;             end else if (active_warps == 0 || active_warps != stalled_warps) begin                 timeout_ctr <= '0;        //warp都禁掉,或者warp有解锁的情况,计数器清0             end         end     end

    `RUNTIME_ASSERT(timeout_ctr < STALL_TIMEOUT, ("%t: *** %s timeout: stalled_warps=%b", $time, INSTANCE_ID, stalled_warps))

Schedule章节到此结束,剩下Execute ALU/LSU/FPU/TCU没有时间分析,留待以后。接下来要开始OpenCL这一部分的内容,可能要多花一点时间,希望理清的时间越快越好:)


总结

本文详细分析了Vortex RISC-V内核6级流水线中的Schedule模块。作为Fetch的上游模块,Schedule负责产生PC地址、uuid和warp ID,并通过8个端口与其他流水线交互。重点包括:1) schedule_if接口生成PC/uuid/wid/tmask;2) decode_sched_if/issue_sched_if/commit_sched_if实现warp状态管理;3) warp_ctl_if处理6个自定义指令;4) branch_ctl_if处理分支跳转。此外还介绍了全局barrier同步(base_dcr/gbar_bus_if)和CSR接口(sched_csr_if)等功能。Schedule模块通过优先级编码选择就绪warp,使用pending计数器跟踪warp执行状态,总控SIMT的执行和多核间同步,是SIMT架构实现线程调度的核心部件。

赞(0)
未经允许不得转载:171主机测评 » 探索Vortex开源GPGPU:RISC-V SIMT架构(6),Schedule
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址