risc-v中文社区

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

[原创] chisel分频器(4)---50占空比的任意分频

  [复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-10-9 14:08:39 | 显示全部楼层 |阅读模式
前面帖子中介绍了偶数50%占空比分频(核心思想就是计数到N/2 -1时翻转),这个帖子中也介绍了奇数50%占空比分频(核心思想就是二个计数器,各自
的输出在小于N/2和N-1时翻转,最后将二个输出进行相“或”,则能得到50%占空比的奇分频。根据这二种50%占空比的分频做法,可以实现任意分频占空比为50%,代码如下:
/**
  * @Author Joe_Liang
  * @Date 2021/10/9 14:06
  * @Version 1.0
  */
import chisel3._
import chisel3.util._
class ArbitraryScaleFreq (val N:Int) extends Module { //任意比例分频
  val io = IO(new Bundle{
    val clk_div = Output(Bool())
  })
  require(N>0,"分频数N必须要大于0")
  if(N == 1) {
    io.clk_div := clock.asUInt().asBool()
  }
  else {
    //偶分频 50%占空比  采用最高bit位输出法
    val cntReg = RegInit(0.U(log2Ceil(N).W))
    when(cntReg === (N-1).U) {
      cntReg := 0.U
    }.otherwise {
      cntReg := cntReg + 1.U
    }
    //上面偶分频输出时:cntReg(log2Ceil(N))表示取N个计数器的bit位中的最高位的值作为输出值,从而达到50%占空比

    //奇分频 50%占空比 采用两计数器时钟上下沿采样再相“或”法
    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
      }
      //最终输出50%占空比的分频
      io.clk_div := Mux((N%2 == 0).asBool(),cntReg(log2Ceil(N)-1),clk_div_pos | clk_div_neg)
    }
  }
}




回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 14:11:03 | 显示全部楼层
通过让N=1,2,3分别产生1分频,2分频,3分频,可以查看产生的verilog代码如下:
Driver.execute(Array("--target-dir","generated"),()=>new ArbitraryScaleFreq(1))  //1分频
module ArbitraryScaleFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  assign io_clk_div = clock; // @[ArbitraryScaleFreq.scala 19:16]
endmodule
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 14:11:49 | 显示全部楼层
Driver.execute(Array("--target-dir","generated"),()=>new ArbitraryScaleFreq(2)) //2分频
module ArbitraryScaleFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  reg  _T; // @[ArbitraryScaleFreq.scala 20:25]
  reg [31:0] _RAND_0;
  wire  _T_3 = _T + 1'h1; // @[ArbitraryScaleFreq.scala 24:24]
  assign io_clk_div = _T; // @[ArbitraryScaleFreq.scala 55:18]
`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}};
  _T = _RAND_0[0:0];
  `endif // RANDOMIZE_REG_INIT
  `endif // RANDOMIZE
end // initial
`endif // SYNTHESIS
  always @(posedge clock) begin
    if (reset) begin
      _T <= 1'h0;
    end else if (_T) begin
      _T <= 1'h0;
    end else begin
      _T <= _T_3;
    end
  end
endmodule
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 14:12:28 | 显示全部楼层
Driver.execute(Array("--target-dir","generated"),()=>new ArbitraryScaleFreq(3)) //3分频
module ArbitraryScaleFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  reg [1:0] _T_4; // @[ArbitraryScaleFreq.scala 29:23]
  reg [31:0] _RAND_0;
  reg  _T_5; // @[ArbitraryScaleFreq.scala 30:30]
  reg [31:0] _RAND_1;
  wire  _T_9 = ~clock; // @[ArbitraryScaleFreq.scala 31:49]
  reg [1:0] _T_10; // @[ArbitraryScaleFreq.scala 32:25]
  reg [31:0] _RAND_2;
  reg  _T_11; // @[ArbitraryScaleFreq.scala 33:30]
  reg [31:0] _RAND_3;
  wire  _T_12 = _T_10 == 2'h2; // @[ArbitraryScaleFreq.scala 34:17]
  wire [1:0] _T_14 = _T_10 + 2'h1; // @[ArbitraryScaleFreq.scala 37:22]
  wire  _T_15 = _T_10 < 2'h1; // @[ArbitraryScaleFreq.scala 39:17]
  wire  _T_16 = _T_4 == 2'h2; // @[ArbitraryScaleFreq.scala 44:17]
  wire [1:0] _T_18 = _T_4 + 2'h1; // @[ArbitraryScaleFreq.scala 47:22]
  wire  _T_19 = _T_4 < 2'h1; // @[ArbitraryScaleFreq.scala 49:17]
  assign io_clk_div = _T_5 | _T_11; // @[ArbitraryScaleFreq.scala 55:18]
`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}};
  _T_4 = _RAND_0[1:0];
  `endif // RANDOMIZE_REG_INIT
  `ifdef RANDOMIZE_REG_INIT
  _RAND_1 = {1{`RANDOM}};
  _T_5 = _RAND_1[0:0];
  `endif // RANDOMIZE_REG_INIT
  `ifdef RANDOMIZE_REG_INIT
  _RAND_2 = {1{`RANDOM}};
  _T_10 = _RAND_2[1:0];
  `endif // RANDOMIZE_REG_INIT
  `ifdef RANDOMIZE_REG_INIT
  _RAND_3 = {1{`RANDOM}};
  _T_11 = _RAND_3[0:0];
  `endif // RANDOMIZE_REG_INIT
  `endif // RANDOMIZE
end // initial
`endif // SYNTHESIS
  always @(posedge clock) begin
    if (reset) begin
      _T_4 <= 2'h0;
    end else if (_T_16) begin
      _T_4 <= 2'h0;
    end else begin
      _T_4 <= _T_18;
    end
    if (reset) begin
      _T_5 <= 1'h0;
    end else if (_T_19) begin
      _T_5 <= 1'h0;
    end else begin
      _T_5 <= 1'h1;
    end
  end
  always @(posedge _T_9) begin
    if (reset) begin
      _T_10 <= 2'h0;
    end else if (_T_12) begin
      _T_10 <= 2'h0;
    end else begin
      _T_10 <= _T_14;
    end
    if (reset) begin
      _T_11 <= 1'h0;
    end else if (_T_15) begin
      _T_11 <= 1'h0;
    end else begin
      _T_11 <= 1'h1;
    end
  end
endmodule



回复

使用道具 举报

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

本版积分规则



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

GMT+8, 2024-4-26 21:53 , Processed in 0.015298 second(s), 17 queries .

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

Copyright © 2018-2021, risc-v open source

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