函数(Function)

一、简介(Introduction)

用Scala函数产生硬件的方式与VHDL/Verilog中非常不同, 原因如下:

  • 你可以在他们内部例化寄存器、组合逻辑和模块。

  • 你不需要使用process/@always模块, 因此也不会限制你对信号声明的范围。

  • 所有事情都是通过引用传递, 这使得各种操作都便于控制。
    例如你可以把总线作为变量传递到函数中, 这样函数就可以在内部读写总线。你也可以返回一个模块, 一个总线, 或是任何来自于Scala世界的东西。

二、RGA到灰度(RGB to grey)

例如, 如果想要把红/绿/蓝颜色通过系数转化为灰度, 可以用如下函数来实现:

//输入RGB色彩
val r, g, b = UInt(8 bits)

//定义灰度系数乘的函数
def coef(value: UInt, by: Float): UInt = (value * U((255 * by).toInt, 8 bits) >> 8)

//计算灰度
val gray = coef(r, 0.3f) + coef(g, 0.4f) + coef(b, 0.3f)

Verilog:

  wire       [7:0]    _zz_gray;
  wire       [7:0]    _zz_gray_1;
  wire       [15:0]   _zz_gray_2;
  wire       [7:0]    _zz_gray_3;
  wire       [15:0]   _zz_gray_4;
  wire       [7:0]    _zz_gray_5;
  wire       [15:0]   _zz_gray_6;
  wire       [7:0]    r;
  wire       [7:0]    g;
  wire       [7:0]    b;
  wire       [7:0]    gray;

  assign _zz_gray = (_zz_gray_1 + _zz_gray_3);
  assign _zz_gray_1 = (_zz_gray_2 >>> 8);
  assign _zz_gray_2 = (r * 8'h4c);
  assign _zz_gray_3 = (_zz_gray_4 >>> 8);
  assign _zz_gray_4 = (g * 8'h66);
  assign _zz_gray_5 = (_zz_gray_6 >>> 8);
  assign _zz_gray_6 = (b * 8'h4c);
  assign gray = (_zz_gray + _zz_gray_5);

三、Valid和Ready负载总线(Valid Ready Payload bus)

例如, 如果你用valid, readypayload信号定义了一条简单的总线, 你可以在其中定义一些常用的函数。

case class MyBus(payloadWidth: Int) extends Bundle with IMasterSlave {
    val valid = Bool()
    val ready = Bool()
    val payload = Bits(payloadWidth bits)
    
    //在master模式中定义数据的方向
    override def asMaster(): Unit = {
        out(valid, payload)
        in(ready)
    }

    //把that链接到this上
    def <<(that: MyBus): Unit = {
        this.valid   := that.valid
        that.ready   := this.ready
        this.payload := that.payload
    }

    //把this连接到FIFO的输入, 返回FIFO的输出
    def queue(size: Int): MyBus = {
        val fifo = new MyBusFifo(payloadWidth, size)
        fifo.io.push << this
        return fifo.io.pop
    }
}

class MyBusFifo(payloadWidth: Int, depth: Int) extends Component {
    val io = new Bundle {
        val push = slave(MyBus(payloadWidth))
        val pop  = master(MyBus(payloadWidth))
    }
    
    val mem = Mem(Bits(payloadWidth bits), depth)

    //...
}

Verilog:(有问题,this和that的作用还没搞懂)

  wire                test_io_push_valid;
  wire       [15:0]   test_io_push_payload;
  wire                test_io_pop_ready;
  wire                test_io_push_ready;
  wire                test_io_pop_valid;
  wire       [15:0]   test_io_pop_payload;

  MyBusFifo test (
    .io_push_valid   (test_io_push_valid        ), //i
    .io_push_ready   (test_io_push_ready        ), //o
    .io_push_payload (test_io_push_payload[15:0]), //i
    .io_pop_valid    (test_io_pop_valid         ), //o
    .io_pop_ready    (test_io_pop_ready         ), //i
    .io_pop_payload  (test_io_pop_payload[15:0] )  //o
  );

module MyBusFifo (
  input               io_push_valid,
  output              io_push_ready,
  input      [15:0]   io_push_payload,
  output              io_pop_valid,
  input               io_pop_ready,
  output     [15:0]   io_pop_payload
);

  reg [15:0] mem [0:7];

endmodule