【硬核】教你如何正确配置ipv6

整数转罗马数字c++

  返回  

02-chisel-tutorial代码学习之组合逻辑

2021/8/20 22:33:32 浏览:

chisel-tutorial代码学习 - 02

  • wire类型变量的声明
  • 1-bit全加器
  • 位宽推断

wire类型变量的声明

在verilog中,使用wire关键字声明一个变量是wire类型,在chisel中也非常简单,我从wiki先贴过来一段话,

Constructing combinational logic blocks in Chisel is fairly straightforward; when you declare a val in Scala, it creates a node that represents the data that it is assigned to. As long as the value is not assigned to be a register type (explained later), this tells the Chisel compiler to treat the value as wire. Thus any number of these values can be connected and manipulated to produce the value that we want.

这段话的重点就是,在chisel中,如果某个变量没有被声明为register,那么chisel编译器就会把这个变量当作wire处理。

1-bit全加器

1-bit全加器是一个非常经典的组合逻辑电路,如下图所示,

1-bit全加器
那么使用chisel来写,就如下面代码所示,我直接从chisel-tutorial中贴过来,

package examples

import chisel3._

class FullAdder extends Module {
  val io = IO(new Bundle {
    val a    = Input(UInt(1.W))
    val b    = Input(UInt(1.W))
    val cin  = Input(UInt(1.W))
    val sum  = Output(UInt(1.W))
    val cout = Output(UInt(1.W))
  })

  // Generate the sum
  val a_xor_b = io.a ^ io.b
  io.sum := a_xor_b ^ io.cin
  // Generate the carry
  val a_and_b = io.a & io.b
  val b_and_cin = io.b & io.cin
  val a_and_cin = io.a & io.cin
  io.cout := a_and_b | b_and_cin | a_and_cin
}

代码val a_xor_b = io.a ^ io.b就声明了一个wire类型的变量,该wire型变量等于两个输入ab的异或。

注意下一行的:=,其实在第一篇笔记中我也提到,因为io.sum已经在io中被定义为val不可变型变量了,在scala中,就不能给io.sum重新赋值,因此chisel定义了操作符:=用于变量的重新赋值。记住一点,如果一个变量是首次定义,就使用=赋值,而如果这个变量已经被定义为val,那么就使用:=符号给变量重赋值。

这个代码比较简单,就是描述了图片中的电路行为。

位宽推断

第一篇笔记已经提到,chisel具有很强大的位宽推断功能,1-bit全加器编译生成的verilog代码如下所示,

module FullAdder(
  input   clock,
  input   reset,
  input   io_a,
  input   io_b,
  input   io_cin,
  output  io_sum,
  output  io_cout
);
  wire  a_xor_b = io_a ^ io_b; // @[FullAdder.scala 16:22]
  wire  a_and_b = io_a & io_b; // @[FullAdder.scala 19:22]
  wire  b_and_cin = io_b & io_cin; // @[FullAdder.scala 20:24]
  wire  a_and_cin = io_a & io_cin; // @[FullAdder.scala 21:24]
  wire  _T_1 = a_and_b | b_and_cin; // @[FullAdder.scala 22:22]
  assign io_sum = a_xor_b ^ io_cin; // @[FullAdder.scala 17:10]
  assign io_cout = _T_1 | a_and_cin; // @[FullAdder.scala 22:11]
endmodule

如果我把代码改成2-bit的全加器,代码如下所示,注意我只是修改了端口的位宽,模块内比如a_xor_b等变量的位宽还是没有指定的,

package examples

import chisel3._

class FullAdder extends Module {
  val io = IO(new Bundle {
    val a    = Input(UInt(2.W))
    val b    = Input(UInt(2.W))
    val cin  = Input(UInt(2.W))
    val sum  = Output(UInt(2.W))
    val cout = Output(UInt(2.W))
  })

  // Generate the sum
  val a_xor_b = io.a ^ io.b
  io.sum := a_xor_b ^ io.cin
  // Generate the carry
  val a_and_b = io.a & io.b
  val b_and_cin = io.b & io.cin
  val a_and_cin = io.a & io.cin
  io.cout := a_and_b | b_and_cin | a_and_cin
}

这样我们再次生成verilog代码看看,模块内的变量的位宽自动推断成了2-bit,注意并不是我声明端口为2-bit,内部变量就被推断为2-bit,而是内部变量的位宽按需推断,保证计算不出错,

module FullAdder(
  input        clock,
  input        reset,
  input  [1:0] io_a,
  input  [1:0] io_b,
  input  [1:0] io_cin,
  output [1:0] io_sum,
  output [1:0] io_cout
);
  wire [1:0] a_xor_b = io_a ^ io_b; // @[FullAdder.scala 16:22]
  wire [1:0] a_and_b = io_a & io_b; // @[FullAdder.scala 19:22]
  wire [1:0] b_and_cin = io_b & io_cin; // @[FullAdder.scala 20:24]
  wire [1:0] a_and_cin = io_a & io_cin; // @[FullAdder.scala 21:24]
  wire [1:0] _T_1 = a_and_b | b_and_cin; // @[FullAdder.scala 22:22]
  assign io_sum = a_xor_b ^ io_cin; // @[FullAdder.scala 17:10]
  assign io_cout = _T_1 | a_and_cin; // @[FullAdder.scala 22:11]
endmodule

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号