risc-v中文社区

 找回密码
 立即注册
查看: 4936|回复: 3

[原创] chisel分频器(3)---占空比为50%奇分频

  [复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-10-9 10:18:25 | 显示全部楼层 |阅读模式
奇分频还有二种情况,一种是占空比为50%,另一种情况是占空比接近50%,本例介绍占空比为50%:
计数器cnt1上升沿计数,对应定义一个寄存器clk_div_pos,在小于N/2时翻转,N-1时再次翻转,计数器cnt2下降沿计数,对应定义一个寄存器clk_div_neg,也是在N/2时翻转,N-1时再次翻转。
关键是输出clk_div需要将clk_div_pos | clk_div_neg  这样就能获得占空比为50%的分步。
/**
  * @Author Joe_Liang
  * @Date 2021/10/9 10:06
  * @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 cnt1 = RegInit(0.U(log2Ceil(N).W)) //计数器cnt1在时钟上升沿加1,cnt1计数值为0到N/2时clk_div_pos为0,cnt1计数值为N/2+1到N-1时clk_div_pos为1
  val clk_div_pos = RegInit(false.B)
  val cnt2wire = Wire(UInt(log2Ceil(N).W)) //用wire连接withClock块中的信号,纯粹满足语法作用, 要不然不能在块外引用块内信号
  val clk_div_neg_wire = Wire(UInt(1.W))//同上
  //万一,复位信号是在clock上升沿之后下降沿之前上拉的话????,所以,必须要注意到这种情况
  withClock((~clock.asUInt()).asBool().asClock()){ //默认用时钟上升沿和高有效复位,此处用时钟下降沿,复位还是高有效
    val cnt2 = RegInit(0.U(log2Ceil(N).W)) //cnt2计数器也在时钟下降沿加1,cnt2计数值为0到N/2时clk_div_neg为0,cnt2计数值为N/2+1到N-1时clk_div_neg为1
    val clk_div_neg = RegInit(false.B)
    when(cnt2 === (N-1).U) { //计数范围0~N-1
      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(cnt1 === (N-1).U) { //计数范围0~N-1
    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
}

因为withClock语句块中定义的cnt2变量,在语句块外无法使用,有二种使用方法,一种是上面例子中的做法,在语句块外面定义中间变量,通过中间变量中转;另一种做法就是将语句块外后面的逻辑代码放在语句块内(以后再做实验)。




回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 10:22:05 | 显示全部楼层
3分频占空比50%产生的verilog代码如下:
module OddFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  reg [1:0] cnt1; // @[OddFreq.scala 15:21]
  reg [31:0] _RAND_0;
  reg  clk_div_pos; // @[OddFreq.scala 16:28]
  reg [31:0] _RAND_1;
  wire  _T_3 = ~clock; // @[OddFreq.scala 20:47]
  reg [1: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 == 2'h2; // @[OddFreq.scala 23:15]
  wire [1:0] _T_8 = cnt2wire + 2'h1; // @[OddFreq.scala 26:20]
  wire  _T_9 = cnt2wire < 2'h1; // @[OddFreq.scala 30:15]
  wire  _T_10 = cnt1 == 2'h2; // @[OddFreq.scala 36:13]
  wire [1:0] _T_12 = cnt1 + 2'h1; // @[OddFreq.scala 39:18]
  wire  _T_13 = cnt1 < 2'h1; // @[OddFreq.scala 41:13]
  assign io_clk_div = clk_div_pos | clk_div_neg_wire; // @[OddFreq.scala 47: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[1: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[1: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 <= 2'h0;
    end else if (_T_10) begin
      cnt1 <= 2'h0;
    end else begin
      cnt1 <= _T_12;
    end
    if (reset) begin
      clk_div_pos <= 1'h0;
    end else if (_T_13) 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 <= 2'h0;
    end else if (_T_6) begin
      cnt2wire <= 2'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
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 10:38:31 | 显示全部楼层
前面说了,因为withClock语句块中定义的cnt2变量,在语句块外无法使用,有二种使用方法,一种是上面例子中的做法,在语句块外面定义中间变量,通过中间变量中转;另一种做法就是将语句块外后面的逻辑代码放在语句块内,在此实验这种想法:/**
  * @Author Joe_Liang
  * @Date 2021/10/9 10:37
  * @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 cnt1 = RegInit(0.U(log2Ceil(N).W)) //计数器cnt1在时钟上升沿加1,cnt1计数值为0到N/2时clk_div_pos为0,cnt1计数值为N/2+1到N-1时clk_div_pos为1
  val clk_div_pos = RegInit(false.B)
  withClock((~clock.asUInt()).asBool().asClock()){ //默认用时钟上升沿和高有效复位,此处用时钟下降沿,复位还是高有效
    val cnt2 = RegInit(0.U(log2Ceil(N).W)) //cnt2计数器也在时钟下降沿加1,cnt2计数值为0到N/2时clk_div_neg为0,cnt2计数值为N/2+1到N-1时clk_div_neg为1
  val clk_div_neg = RegInit(false.B)
    when(cnt2 === (N-1).U) { //计数范围0~N-1
      cnt2 := 0.U
    }.otherwise{
      cnt2 := cnt2 + 1.U
    }
    when(cnt2 < (N/2).U) {
      clk_div_neg := false.B
    }.otherwise {
      clk_div_neg := true.B
    }

    when(cnt1 === (N-1).U) { //计数范围0~N-1
      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
  }

}




回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 10:41:16 | 显示全部楼层
产生的verilog代码如下,可以看到实验是成功的,所以二种做法都是可行的:
module OddFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  reg [1:0] cnt1; // @[OddFreq.scala 54:21]
  reg [31:0] _RAND_0;
  reg  clk_div_pos; // @[OddFreq.scala 55:28]
  reg [31:0] _RAND_1;
  wire  _T_3 = ~clock; // @[OddFreq.scala 56:47]
  reg [1:0] _T_4; // @[OddFreq.scala 57:23]
  reg [31:0] _RAND_2;
  reg  _T_5; // @[OddFreq.scala 58:28]
  reg [31:0] _RAND_3;
  wire  _T_6 = _T_4 == 2'h2; // @[OddFreq.scala 59:15]
  wire [1:0] _T_8 = _T_4 + 2'h1; // @[OddFreq.scala 62:20]
  wire  _T_9 = _T_4 < 2'h1; // @[OddFreq.scala 64:15]
  wire  _T_10 = cnt1 == 2'h2; // @[OddFreq.scala 70:15]
  wire [1:0] _T_12 = cnt1 + 2'h1; // @[OddFreq.scala 73:20]
  wire  _T_13 = cnt1 < 2'h1; // @[OddFreq.scala 75:15]
  assign io_clk_div = clk_div_pos | _T_5; // @[OddFreq.scala 80:16]
`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[1: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}};
  _T_4 = _RAND_2[1:0];
  `endif // RANDOMIZE_REG_INIT
  `ifdef RANDOMIZE_REG_INIT
  _RAND_3 = {1{`RANDOM}};
  _T_5 = _RAND_3[0:0];
  `endif // RANDOMIZE_REG_INIT
  `endif // RANDOMIZE
end // initial
`endif // SYNTHESIS
  always @(posedge clock) begin
    if (reset) begin
      cnt1 <= 2'h0;
    end else if (_T_10) begin
      cnt1 <= 2'h0;
    end else begin
      cnt1 <= _T_12;
    end
    if (reset) begin
      clk_div_pos <= 1'h0;
    end else if (_T_13) begin
      clk_div_pos <= 1'h0;
    end else begin
      clk_div_pos <= 1'h1;
    end
  end
  always @(posedge _T_3) begin
    if (reset) begin
      _T_4 <= 2'h0;
    end else if (_T_6) begin
      _T_4 <= 2'h0;
    end else begin
      _T_4 <= _T_8;
    end
    if (reset) begin
      _T_5 <= 1'h0;
    end else if (_T_9) begin
      _T_5 <= 1'h0;
    end else begin
      _T_5 <= 1'h1;
    end
  end
endmodule
回复

使用道具 举报

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

本版积分规则



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

GMT+8, 2024-4-25 23:09 , Processed in 0.015236 second(s), 17 queries .

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

Copyright © 2018-2021, risc-v open source

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