risc-v中文社区

 找回密码
 立即注册
查看: 2973|回复: 1

[原创] chisel withClock(时钟下降沿触发)用法

[复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-10-8 22:29:07 | 显示全部楼层 |阅读模式
chisel模块的默认时钟是上升沿有效,高电平有效,复位是同步复位,也是高电平有效。但有时候,我们需要用到下降沿触发,这个时候就可以用到withClock或withReset或withClockAndReset,
withClock是针对调整时钟,withReset是针对复位,withClockAndReset是同时针对时钟和复位。另外,还要注意,因为withClock等方法后的语句块中定义的各种val寄存器或Wire等变量作用
范围只能是在语句块中,出了语句块是无法使用的,而我们出了语句块之后很有可能需要用到语句块中的变量,这时可以有二种方法,一种方法就是在外面定义一个中转的变量,这个变量在语句
块中被赋值为相应的寄存器或Wire变量的值,这样在语句块外面就相当于可以用语句块内变量,这种做法在下面的实验中可以看到;另一种做法就是在语句块中将原来语句块外面要用的逻辑放到
语句块内,这种做法我目前还没有做实验,可以在后面的帖子中做做实验。本帖下面的实验不需要分析逻辑,只需要看红色注释理解withClock和中转变量即可:
/**
  * @Author Joe_Liang
  * @Date 2021/10/5 9:29
  * @Version 1.0
  */
import chisel3._
import chisel3.util._
class OddFreq(val N:Int) extends Module { //奇分频
  val io = IO(new Bundle{
    val clk_div = Output(Bool())
  })
  require(N>1 && (N % 2 == 1),"N必须大于1且N是奇数")
  val cnt = RegInit(0.U(log2Ceil(N).W))
  val cnt1 = RegInit(0.U(log2Ceil(N).W))
  val clk_div_pos = RegInit(false.B)
  val cnt2wire = Wire(UInt(log2Ceil(N).W))
  val clk_div_neg_wire = Wire(UInt(1.W))
  withClock((~clock.asUInt()).asBool().asClock()){ //默认用时钟上升沿和高有效复位,此处用时钟下降沿,复位还是高有效
    val cnt2 = RegInit(0.U(log2Ceil(N).W))
    val clk_div_neg = RegInit(false.B)
    when(cnt2 === (N-1).U) {
      cnt2 := 0.U
    }.otherwise{
      cnt2 := cnt2 + 1.U
    }
    cnt2wire := cnt2
    clk_div_neg_wire := clk_div_neg
    when(cnt2 < (N/2).U) {
      clk_div_neg := false.B
    }.otherwise {
      clk_div_neg := true.B
    }
  }
  when(cnt === (N-1).U) {
    cnt := 0.U
  }.otherwise{
    cnt := cnt + 1.U
  }
  when(cnt1 === (N-1).U) {
    cnt1 := 0.U
  }.otherwise{
    cnt1 := cnt1 + 1.U
  }
  when(cnt1 < (N/2).U) {
    clk_div_pos := false.B
  }.otherwise {
    clk_div_pos := true.B
  }

  io.clk_div := clk_div_pos | clk_div_neg_wire
}

回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-8 22:32:57 | 显示全部楼层
生成的verilog文件内容如下:
module OddFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  reg [2:0] cnt1; // @[OddFreq.scala 16:21]
  reg [31:0] _RAND_0;
  reg  clk_div_pos; // @[OddFreq.scala 17:28]
  reg [31:0] _RAND_1;
  wire _T_3 = ~clock; // @[OddFreq.scala 20:47]
  reg [2:0] cnt2wire; // @[OddFreq.scala 21:23]
  reg [31:0] _RAND_2;
  reg  clk_div_neg_wire; // @[OddFreq.scala 22:30]
  reg [31:0] _RAND_3;
  wire  _T_6 = cnt2wire == 3'h4; // @[OddFreq.scala 23:15]
  wire [2:0] _T_8 = cnt2wire + 3'h1; // @[OddFreq.scala 26:20]
  wire  _T_9 = cnt2wire < 3'h2; // @[OddFreq.scala 30:15]
  wire  _T_13 = cnt1 == 3'h4; // @[OddFreq.scala 41:13]
  wire [2:0] _T_15 = cnt1 + 3'h1; // @[OddFreq.scala 44:18]
  wire  _T_16 = cnt1 < 3'h2; // @[OddFreq.scala 46:13]
  assign io_clk_div = clk_div_pos | clk_div_neg_wire; // @[OddFreq.scala 52:14]
`ifdef RANDOMIZE_GARBAGE_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_INVALID_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_REG_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_MEM_INIT
`define RANDOMIZE
`endif
`ifndef RANDOM
`define RANDOM $random
`endif
`ifdef RANDOMIZE_MEM_INIT
  integer initvar;
`endif
`ifndef SYNTHESIS
initial begin
  `ifdef RANDOMIZE
    `ifdef INIT_RANDOM
      `INIT_RANDOM
    `endif
    `ifndef VERILATOR
      `ifdef RANDOMIZE_DELAY
        #`RANDOMIZE_DELAY begin end
      `else
        #0.002 begin end
      `endif
    `endif
  `ifdef RANDOMIZE_REG_INIT
  _RAND_0 = {1{`RANDOM}};
  cnt1 = _RAND_0[2:0];
  `endif // RANDOMIZE_REG_INIT
  `ifdef RANDOMIZE_REG_INIT
  _RAND_1 = {1{`RANDOM}};
  clk_div_pos = _RAND_1[0:0];
  `endif // RANDOMIZE_REG_INIT
  `ifdef RANDOMIZE_REG_INIT
  _RAND_2 = {1{`RANDOM}};
  cnt2wire = _RAND_2[2:0];
  `endif // RANDOMIZE_REG_INIT
  `ifdef RANDOMIZE_REG_INIT
  _RAND_3 = {1{`RANDOM}};
  clk_div_neg_wire = _RAND_3[0:0];
  `endif // RANDOMIZE_REG_INIT
  `endif // RANDOMIZE
end // initial
`endif // SYNTHESIS
  always @(posedge clock) begin
    if (reset) begin
      cnt1 <= 3'h0;
    end else if (_T_13) begin
      cnt1 <= 3'h0;
    end else begin
      cnt1 <= _T_15;
    end
    if (reset) begin
      clk_div_pos <= 1'h0;
    end else if (_T_16) begin
      clk_div_pos <= 1'h0;
    end else begin
      clk_div_pos <= 1'h1;
    end
  end
  always @(posedge _T_3) begin
    if (reset) begin
      cnt2wire <= 3'h0;
    end else if (_T_6) begin
      cnt2wire <= 3'h0;
    end else begin
      cnt2wire <= _T_8;
    end
    if (reset) begin
      clk_div_neg_wire <= 1'h0;
    end else if (_T_9) begin
      clk_div_neg_wire <= 1'h0;
    end else begin
      clk_div_neg_wire <= 1'h1;
    end
  end
endmodule

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



Archiver|手机版|小黑屋|risc-v中文社区

GMT+8, 2024-5-5 07:53 , Processed in 0.014763 second(s), 17 queries .

risc-v中文社区论坛 官方网站

Copyright © 2018-2021, risc-v open source

快速回复 返回顶部 返回列表