十二 · 2021年10月20日

SpinalHDL——switch

前言       

在RTL设计里,case是一个常用的综合语法,用于根据变量值来选择适当的逻辑电路,语法很简单:

case(Value)
  XXXA:
  XXXB:
  XXXC:
  default:
endcase

想象一个场景,在标准的AXI4-Stream接口中,tkeep信号每一个bit表示一个字节的数据是否有效,当我们需要根据tkeep信号来计算这一拍有多少有效数据时这里的代码会是什么样子……

case(tkeep)
  64'h1:byteCnt='d1;
  64'h3:byteCnt='d2;
  ……
  64'hffffffffffffffff:byteCnt='d64;
  default:byteCnt='d64;
endcase

这种代码写的手有点儿累(又没啥技术含量)……

在SpinalHDL里该如何做呢?

switch

SpinalHDL提供了switch方法用于实现Verilog里case语句的实现:

switch(x){
  is(value1){
    //execute when x === value1
  }
  is(value2){
    //execute when x === value2
  }
  default{
    //execute if none of precedent condition meet
  }
}

看起来似乎和Verilog里的差不多,但SpinalHDL基于Scala语言,可借助高级语言进行方便的代码构建:

在SpinalHDL里,我们可以更快速高效的实现tkeep到byteCnt的转换:

 val keepIndex=for(index<-1 to 64) yield (BigInt(1)<<index)-1
    switch(io.qdma_st_c2h_tkeep){
      for(index<-1 to 64){
        is(B((BigInt(1)<<index)-1,64 bits)){
          io.cnt:=U(index,log2Up(64+1) bits)
        }
      }
      default{
        io.cnt:=U(64,log2Up(64+1) bits)
      }
    }

SpinalHDL在生成RTL时,仅SpinalHDL提供的语法会生成RTL电路,而其他代码则是起指导生成电路的作用,在上面代码里,keepIndex记录了tkeep需要匹配的值,第三行代码则是指定规则,为index从1到64的取值,均生成"is"综合语句,而在真正生成RTL电路时,只有switch、is这些SpinalHDL提供的语句才会生成电路。生成的RTL语句如下:

always @ (*) begin
    case(qdma_st_c2h_tkeep)
      64'h0000000000000001 : begin
        cnt = 7'h01;
      end
      64'h0000000000000003 : begin
        cnt = 7'h02;
      end
      64'h0000000000000007 : begin
        cnt = 7'h03;
      end
      64'h000000000000000f : begin
        cnt = 7'h04;
      end
      64'h000000000000001f : begin
        cnt = 7'h05;
      end
      64'h000000000000003f : begin
        cnt = 7'h06;
      end
      64'h000000000000007f : begin
        cnt = 7'h07;
      end
      64'h00000000000000ff : begin
        cnt = 7'h08;
      end
      64'h00000000000001ff : begin
        cnt = 7'h09;
      end
      64'h00000000000003ff : begin
        cnt = 7'h0a;
      end
      64'h00000000000007ff : begin
        cnt = 7'h0b;
      end
      64'h0000000000000fff : begin
        cnt = 7'h0c;
      end
      64'h0000000000001fff : begin
        cnt = 7'h0d;
      end
      64'h0000000000003fff : begin
        cnt = 7'h0e;
      end
      64'h0000000000007fff : begin
        cnt = 7'h0f;
      end
      64'h000000000000ffff : begin
        cnt = 7'h10;
      end
      64'h000000000001ffff : begin
        cnt = 7'h11;
      end
      64'h000000000003ffff : begin
        cnt = 7'h12;
      end
      64'h000000000007ffff : begin
        cnt = 7'h13;
      end
      64'h00000000000fffff : begin
        cnt = 7'h14;
      end
      64'h00000000001fffff : begin
        cnt = 7'h15;
      end
      64'h00000000003fffff : begin
        cnt = 7'h16;
      end
      64'h00000000007fffff : begin
        cnt = 7'h17;
      end
      64'h0000000000ffffff : begin
        cnt = 7'h18;
      end
      64'h0000000001ffffff : begin
        cnt = 7'h19;
      end
      64'h0000000003ffffff : begin
        cnt = 7'h1a;
      end
      64'h0000000007ffffff : begin
        cnt = 7'h1b;
      end
      64'h000000000fffffff : begin
        cnt = 7'h1c;
      end
      64'h000000001fffffff : begin
        cnt = 7'h1d;
      end
      64'h000000003fffffff : begin
        cnt = 7'h1e;
      end
      64'h000000007fffffff : begin
        cnt = 7'h1f;
      end
      64'h00000000ffffffff : begin
        cnt = 7'h20;
      end
      64'h00000001ffffffff : begin
        cnt = 7'h21;
      end
      64'h00000003ffffffff : begin
        cnt = 7'h22;
      end
      64'h00000007ffffffff : begin
        cnt = 7'h23;
      end
      64'h0000000fffffffff : begin
        cnt = 7'h24;
      end
      64'h0000001fffffffff : begin
        cnt = 7'h25;
      end
      64'h0000003fffffffff : begin
        cnt = 7'h26;
      end
      64'h0000007fffffffff : begin
        cnt = 7'h27;
      end
      64'h000000ffffffffff : begin
        cnt = 7'h28;
      end
      64'h000001ffffffffff : begin
        cnt = 7'h29;
      end
      64'h000003ffffffffff : begin
        cnt = 7'h2a;
      end
      64'h000007ffffffffff : begin
        cnt = 7'h2b;
      end
      64'h00000fffffffffff : begin
        cnt = 7'h2c;
      end
      64'h00001fffffffffff : begin
        cnt = 7'h2d;
      end
      64'h00003fffffffffff : begin
        cnt = 7'h2e;
      end
      64'h00007fffffffffff : begin
        cnt = 7'h2f;
      end
      64'h0000ffffffffffff : begin
        cnt = 7'h30;
      end
      64'h0001ffffffffffff : begin
        cnt = 7'h31;
      end
      64'h0003ffffffffffff : begin
        cnt = 7'h32;
      end
      64'h0007ffffffffffff : begin
        cnt = 7'h33;
      end
      64'h000fffffffffffff : begin
        cnt = 7'h34;
      end
      64'h001fffffffffffff : begin
        cnt = 7'h35;
      end
      64'h003fffffffffffff : begin
        cnt = 7'h36;
      end
      64'h007fffffffffffff : begin
        cnt = 7'h37;
      end
      64'h00ffffffffffffff : begin
        cnt = 7'h38;
      end
      64'h01ffffffffffffff : begin
        cnt = 7'h39;
      end
      64'h03ffffffffffffff : begin
        cnt = 7'h3a;
      end
      64'h07ffffffffffffff : begin
        cnt = 7'h3b;
      end
      64'h0fffffffffffffff : begin
        cnt = 7'h3c;
      end
      64'h1fffffffffffffff : begin
        cnt = 7'h3d;
      end
      64'h3fffffffffffffff : begin
        cnt = 7'h3e;
      end
      64'h7fffffffffffffff : begin
        cnt = 7'h3f;
      end
      64'hffffffffffffffff : begin
        cnt = 7'h40;
      end
      default : begin
        cnt = 7'h40;
      end
    endcase
  end

倘若我不告诉你,焉知我这段代码不是手写的呢(你先手写着,我去刷会儿手机~)?

同样,针对case多个匹配执行相同操作,switch也同样支持,实例如下:

switch(io.dataIn){
      is(1,2) {
        io.dataOut:=3
      }
      is(0){
        io.dataOut:=2
      }
      default{
        io.dataOut:=0
      }
    }

对应的RTL同样和手写RTL无二:

always @ (*) begin
    case(dataIn)
      4'b0001, 4'b0010 : begin
        dataOut = 2'b11;
      end
      4'b0000 : begin
        dataOut = 2'b10;
      end
      default : begin
        dataOut = 2'b00;
      end
    endcase
  end

SpinalHDL本质上还是不同于HLS仍需要硬件设计思维,但对于Verilog/SystemVerilog来讲,依旧有鸟枪换炮的优势!

END

作者:玉骐
原文链接:https://mp.weixin.qq.com/s/xE-0sw5DJMn3QVCyFcUYUA
微信公众号:
Spinal FPGA二维码.jpg

推荐阅读

推荐阅读
关注数
1578
内容数
128
用SpinalHDL提升生产力
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息