risc-v中文社区

 找回密码
 立即注册
查看: 3194|回复: 4

[原创] chisel分频器(2)---不考虑占空比的奇偶分频

  [复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-10-8 22:53:07 | 显示全部楼层 |阅读模式
以2,3,5,8分频为例来介绍原理:
最大计数长度为3的计数器即从0计数到2,需要的bit位数是log2Ceil(3)=2,最高位为bit(1)
00 01    10 11  对于bit(1)来说,二个周期为0,原本是二个周期为1,但计数器值判断时用cnt === (3-1).U则cnt := 0.U,输出始终是out := cnt(1),
                                这样前二个时钟为0最后一个时钟为0(cnt不会计数产生11这样的值),也就是说输出时钟周期之内原时钟有三个周期,这种奇分频只在
                                最后一个时钟为1,占空比不是50%
最大计数长度为5的计器即计数从0到4,需要的bit位数是log2Ceil(5)=3,最高位为bit(2)
000~011                100~111 同样,计数器值判断用cnt ===(5-1).U则cnt:=0.U,输出也是out:=cnt(2),则前四个周期输出为0,最后一个周期100时为1(其它101,
                                110,111等cnt值不会产生)
最大计数长度为8的计数器即从0计数到7,需要的bit位数是log2Ceil(8)=3,最高位为bit(2)
000~011                100~111 对于bit(2)来说,前四个时钟周期0,后四个周期为1,但计数器值判断时用cnt === (8-1).U则cnt := 0.U,输出始终是out:=cnt(2),
                                这样前四个时钟000~011输出为0,后四个时钟100~111输出为1,占空比为50%的输出
最大计数长度为2,log2Ceil(2)=1,最高位为bit(0)
0                1                判断计数器值时cnt === 1.U则cnt:=0.U 输出也是out:=cnt(0),这样前一个时钟输出为0,后一个时钟输出为1,最终是一个输出时钟周期
                                之内原时钟有二个周期,即2分频,且占空比为50%

上面不管是偶分频还是奇分频,总的原则就是通过分频值算出所需要的bit位数,计数器的最高bit位的值当作输出值,关键是计数器的值复位判断,必须、
要cnt === (所需要的分频值 - 1)时cnt:=0.U,这样处理之后,如果是偶分频则是占空比为50%的分频,如果是奇分频则只最后一个时钟输出为1.

回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 08:18:08 | 显示全部楼层
对应的chisel代码如下:
/**
  * @Author Joe_Liang
  * @Date 2021/10/8 23:12
  * @Version 1.0
  */
import chisel3._
import chisel3.util._
class MSBDivFreq(val N:Int) extends Module{
  val io = IO(new Bundle{
    val clk_div = Output(Bool())
  })
  require(N>1,"N必须大于1")
  val cnt = RegInit(0.U(log2Ceil(N).W)) //计数范围0~N-1
  when(cnt === (N-1).U) {
    cnt := 0.U
  }.otherwise {
    cnt := cnt + 1.U
  }
  io.clk_div := cnt(log2Ceil(N) - 1) //最高bit位
}

产生3分频:Driver.execute(Array("--target-dir","generated"),()=>new MSBDivFreq(3))
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 08:18:55 | 显示全部楼层
chisel代码产生的verilog:

module MSBDivFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  reg [1:0] cnt; // @[MSBDivFreq.scala 15:20]
  reg [31:0] _RAND_0;
  wire  _T = cnt == 2'h2; // @[MSBDivFreq.scala 16:12]
  wire [1:0] _T_2 = cnt + 2'h1; // @[MSBDivFreq.scala 19:16]
  assign io_clk_div = cnt[1]; // @[MSBDivFreq.scala 21: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}};
  cnt = _RAND_0[1:0];
  `endif // RANDOMIZE_REG_INIT
  `endif // RANDOMIZE
end // initial
`endif // SYNTHESIS
  always @(posedge clock) begin
    if (reset) begin
      cnt <= 2'h0;
    end else if (_T) begin
      cnt <= 2'h0;
    end else begin
      cnt <= _T_2;
    end
  end
endmodule
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 08:56:15 | 显示全部楼层
如果想用异步复位模式的分频,则上面chisel代码修改为:
/**
  * @Author Joe_Liang
  * @Date 2021/10/8 23:12
  * @Version 1.0
  */
import chisel3._
import chisel3.util._
class MSBDivFreq(val N:Int) extends Module{
  val io = IO(new Bundle{
    val clk_div = Output(Bool())
  })
  require(N>1,"N必须大于1")
  withReset(reset.asAsyncReset()) {
    val cnt = RegInit(0.U(log2Ceil(N).W)) //计数范围0~N-1
    when(cnt === (N-1).U) {
      cnt := 0.U
    }.otherwise {
      cnt := cnt + 1.U
    }
    io.clk_div := cnt(log2Ceil(N) - 1) //最高bit位
  }
}
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-10-9 09:05:31 | 显示全部楼层
还是3分频,异步复位:
module MSBDivFreq(
  input   clock,
  input   reset,
  output  io_clk_div
);
  reg [1:0] _T_1; // @[MSBDivFreq.scala 16:22]
  reg [31:0] _RAND_0;
  wire  _T_2 = _T_1 == 2'h2; // @[MSBDivFreq.scala 17:14]
  wire [1:0] _T_4 = _T_1 + 2'h1; // @[MSBDivFreq.scala 20:18]
  assign io_clk_div = _T_1[1]; // @[MSBDivFreq.scala 22: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}};
  _T_1 = _RAND_0[1:0];
  `endif // RANDOMIZE_REG_INIT
  if (reset) begin
    _T_1 = 2'h0;
  end
  `endif // RANDOMIZE
end // initial
`endif // SYNTHESIS
  always @(posedge clock or posedge reset) begin
    if (reset) begin
      _T_1 <= 2'h0;
    end else if (_T_2) begin
      _T_1 <= 2'h0;
    end else begin
      _T_1 <= _T_4;
    end
  end
endmodule



回复

使用道具 举报

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

本版积分规则



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

GMT+8, 2024-5-1 21:28 , Processed in 0.018569 second(s), 17 queries .

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

Copyright © 2018-2021, risc-v open source

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