当前位置:   article > 正文

Verilog刷题

verilog刷题
  1. module data_driver(
  2. input clk_a,
  3. input rst_n,
  4. input data_ack,
  5. output reg [3:0]data,
  6. output reg data_req
  7. );
  8. reg data_ack_reg_1;
  9. reg data_ack_reg_2;
  10. reg data_ack_reg_3;
  11. reg [9:0] cnt;
  12. always @ (posedge clk_a or negedge rst_n)
  13. if (!rst_n)
  14. begin
  15. data_ack_reg_1 <= 0;
  16. data_ack_reg_2 <= 0;
  17. data_ack_reg_3 <= 0;
  18. end
  19. else
  20. begin
  21. data_ack_reg_1 <= data_ack;
  22. data_ack_reg_2 <= data_ack_reg_1;
  23. data_ack_reg_3 <= data_ack_reg_2;
  24. end
  25. always @ (posedge clk_a or negedge rst_n)
  26. if (!rst_n)
  27. begin
  28. data <= 0;
  29. end
  30. else if(data_ack_reg_2 && !data_ack_reg_3)
  31. begin
  32. data <= data+1;
  33. end
  34. else begin
  35. data <= data;
  36. end
  37. //同时在data_ack有效之后,开始计数五个时钟,之后发送新的数据,也就是再一次拉高data_req.
  38. always @ (posedge clk_a or negedge rst_n)
  39. if (!rst_n)
  40. cnt <= 0;
  41. else if (data_ack_reg_2 && !data_ack_reg_3)
  42. cnt <= 0;
  43. else if (data_req)
  44. cnt <= cnt;
  45. else
  46. cnt <= cnt+1;
  47. always @ (posedge clk_a or negedge rst_n)
  48. if (!rst_n)
  49. data_req <= 0;
  50. else if (cnt == 3'd4)
  51. data_req <= 1'b1;
  52. else if (data_ack_reg_2 && !data_ack_reg_3)
  53. data_req <= 1'b0;
  54. else
  55. data_req <= data_req;
  56. endmodule
  57. module data_receiver(
  58. input clk_b,
  59. input rst_n,
  60. output reg data_ack,
  61. input [3:0]data,
  62. input data_req
  63. );
  64. reg [3:0]data_in_reg;
  65. reg data_req_reg_1;
  66. reg data_req_reg_2;
  67. reg data_req_reg_3;
  68. always @ (posedge clk_b or negedge rst_n)
  69. if (!rst_n)
  70. begin
  71. data_req_reg_1 <= 0;
  72. data_req_reg_2 <= 0;
  73. data_req_reg_3 <= 0;
  74. end
  75. else
  76. begin
  77. data_req_reg_1 <= data_req;
  78. data_req_reg_2 <= data_req_reg_1;
  79. data_req_reg_3 <= data_req_reg_2;
  80. end
  81. always @ (posedge clk_b or negedge rst_n)
  82. if (!rst_n)
  83. data_ack <= 0;
  84. else if (data_req_reg_1)
  85. data_ack <= 1;
  86. else data_ack <=0 ;
  87. always @ (posedge clk_b or negedge rst_n)
  88. if (!rst_n)
  89. data_in_reg <= 0;
  90. else if (data_req_reg_2 && !data_req_reg_3)
  91. data_in_reg <= data;
  92. else data_in_reg <= data_in_reg ;
  93. endmodule
  • 序列产生

  1. 方法一(状态机)
  2. module sequence_generator(
  3. input clk,
  4. input rst_n,
  5. output data
  6. );
  7. parameter S0 = 3'd0;
  8. parameter S1 = 3'd1;
  9. parameter S2 = 3'd2;
  10. parameter S3 = 3'd3;
  11. parameter S4 = 3'd4;
  12. parameter S5 = 3'd5;
  13. reg [2:0] state;
  14. reg [2:0] next_state;
  15. always @ (posedge clk or negedge rst_n) begin
  16. if (rst_n == 1'b0) begin
  17. state <= S0;
  18. end
  19. else
  20. state <= next_state;
  21. end
  22. reg [3:0] data_reg;
  23. always @ (*) begin
  24. if (rst_n == 1'b0) begin
  25. next_state = S0;
  26. data_reg = 4'b0010;
  27. end
  28. else begin
  29. case (state)
  30. S0 : begin
  31. next_state = S1;
  32. data_reg = 4'b0010;
  33. end
  34. S1 : begin
  35. next_state = S2;
  36. data_reg = 4'b0101;
  37. end
  38. S2 : begin
  39. next_state = S3;
  40. data_reg = 4'b1011;
  41. end
  42. S3 : begin
  43. next_state = S4;
  44. data_reg = 4'b0110;
  45. end
  46. S4 : begin
  47. next_state = S5;
  48. data_reg = 4'b1100;
  49. end
  50. S5 : begin
  51. next_state = S0;
  52. data_reg = 4'b1001;
  53. end
  54. default : begin
  55. next_state = S0;
  56. data_reg = 4'b0010;
  57. end
  58. endcase
  59. end
  60. end
  61. assign data = data_reg[3];
  62. endmodule
  63. 方法二 移位寄存器
  64. module sequence_generator(
  65. input clk,
  66. input rst_n,
  67. output reg data
  68. );
  69. reg [5:0] q;
  70. always@(posedge clk or negedge rst_n)
  71. if (!rst_n)
  72. q <= 6'b001011;
  73. else
  74. q <= {q[4:0],q[5]};
  75. always@(posedge clk or negedge rst_n)
  76. if (!rst_n)
  77. data <= 1'd0;
  78. else
  79. data <= q[5];
  80. endmodule
  81. 方法三 计数器加case语句
  82. module sequence_generator(
  83. input clk,
  84. input rst_n,
  85. output data
  86. );
  87. reg [2:0] cnt;
  88. always@(posedge clk or negedge rst_n)begin
  89. if(!rst_n) cnt<=3'b0;
  90. else begin
  91. if(cnt==3'd5)
  92. cnt<=3'b0;
  93. else cnt<=cnt+1'b1;
  94. end
  95. end
  96. always@(posedge clk or negedge rst_n)begin
  97. if(!rst_n) data<=1'b0;
  98. else begin
  99. case(cnt)
  100. 3'd0:data<=1'b0;
  101. 3'd1:data<=1'b0;
  102. 3'd2:data<=1'b1;
  103. 3'd3:data<=1'b0;
  104. 3'd4:data<=1'b1;
  105. 3'd5:data<=1'b1;
  106.                 default : data <= 1'b0;
  107. endcase
  108. end
  109. end
  110. endmodule
  • 序列检测 本次检测序列为10010

  1. 方法:画状态转移图采用状态机实现
  2. module sequential_detector(clk, reset, d, y);
  3. //输入输出端口定义
  4. input clk, reset, d;
  5. output y;
  6. //内部寄存器及连线定义
  7. reg [2 : 0] state;
  8. wire y;
  9. //状态编码
  10. parameter idle = 3'b000, s1 = 3'b001, s2 = 3'b010, s3 = 3'b011,
  11. s4 = 3'b100, s5 = 3'b101, s6 = 3'b110, s7 = 3'b111;
  12. //状态机实现
  13. always@(posedge clk or posedge reset)
  14. begin
  15. if(reset) state <= idle;
  16. else
  17. begin
  18. casex(state)
  19. idle: begin
  20. if(d == 1) state <= s1;
  21. else state <= idle;
  22. end
  23. s1: begin
  24. if(d == 0) state <= s2;
  25. else state <= s1;
  26. end
  27. s2: begin
  28. if(d == 0) state <= s3;
  29. else state <= s7;
  30. end
  31. s3: begin
  32. if(d == 1) state <= s4;
  33. else state <= s6;
  34. end
  35. s4: begin
  36. if(d == 0) state <= s5;
  37. else state <= s1;
  38. end
  39. s5: begin
  40. if(d == 1) state <= s1;
  41. else state <= s3;
  42. end
  43. s6: begin
  44. if(d == 1) state <= s7;
  45. else state <= s6;
  46. end
  47. s7: begin
  48. if(d == 1) state <= s1;
  49. else state <= s2;
  50. end
  51. default: state <= idle;
  52. endcase
  53. end
  54. end
  55. //用组合逻辑实现输出
  56. assign y = (state == s4 && d == 0) ? 1 : 0;
  57. endmodule
  1. 串转并

  1. 方法:移位寄存器
  2. module serial2paraller(
  3. input clk,
  4. input rst_n,
  5. input d,
  6. output reg [3:0]q,
  7.     output reg q_valid
  8. );
  9. reg [3:0]data;
  10. always @(posedge clk or negedge rst_n)
  11. begin
  12. if(!rst_n)
  13. data <= 4'b0;
  14. else
  15. data <= {data[2:0],d};
  16. end
  17. reg [1:0] cnt;
  18. always @(posedge clk or negedge rst_n)
  19. begin
  20. if(!rst_n)
  21. cnt <= 2'd0;
  22. else if (cnt == 2'd3)
  23. cnt <= 2'd0;
  24.     else
  25.         cnt <= cnt + 1'b1;
  26. end
  27. always @(posedge clk or negedge rst_n)
  28. begin
  29. if(!rst_n)
  30. q <= 4'b0;
  31. else
  32. q <= data;
  33. end
  34. always @(posedge clk or negedge rst_n)
  35. begin
  36. if(!rst_n)
  37. q_valid <= 1'b0;
  38. else if (cnt == 2'd3)
  39. q_valid <= 1'b1;
  40.     else
  41.         q_valid <= 1'b0;
  42. end
  43. endmodule
  1. 并转串

  1. 方法:移位寄存器
  2. module paraller2serial(
  3. input clk,
  4. input rst_n,
  5. input [4:0]d,
  6. input en,
  7. output q
  8. );
  9. reg[4:0]data;
  10. always @(posedge clk or negedge rst_n)
  11. begin
  12. if(!rst_n)
  13. data <= 5'b0;
  14. else if(en)
  15. data <= d;
  16. else
  17. data <= data << 1;
  18. end
  19. assign q = data[4];
  20. endmodule
  • glitch-free电路

第一种:两个时钟之间有倍数关系

  1. 方法:将sel信号分别在不同时钟信号下进行打拍同步
  2. module syn_clk_glitch_free(
  3. input wire clk0 ,
  4. input wire clk1 ,
  5. input wire rst ,
  6. input wire sel ,
  7. output wire clk_out
  8. );
  9. reg q0, q1;
  10. always@(negedge clk0 or negedge rst)
  11. if(!rst)
  12. q0 <= 0;
  13. else
  14. q0 <= ~sel & ~q1;
  15. always@(negedge clk1 or negedge rst)
  16. if(!rst)
  17. q1 <= 0;
  18. else
  19. q1 <= sel & ~q0;
  20. assign clk_out = (q0 & clk0) | (q1 & clk1);
  21. endmodule

第一点:采用下降沿寄存器,下降沿寄存,可以保证下降沿到来之前输出端保持不变,这样就不会斩断当前时钟了

第二点:即使当前SELECT突然变化了,也必须等待到当前时钟的下降沿到来才能去使当前时钟无效,这一段时间就避免了毛刺

第二种:异步时钟

  1. 方法:将SEL信号与一个时钟域到另一个时钟域的反馈,进行打拍
  2. module asyn_clk_glitch_free(
  3. input wire clk0 ,
  4. input wire clk1 ,
  5. input wire rst ,
  6. input wire sel ,
  7. output wire clk_out
  8. );
  9. reg q0, q1, q2, q3;
  10. always @ (posedge clk0 or negedge rst)
  11.         if(!rst)
  12.             q0 <= 0;
  13.         else
  14.             q0 <= ~sel & ~q3;
  15.    
  16.     always@(negedge clk0 or negedge rst)
  17. if(!rst)
  18. q1 <= 0;
  19. else
  20. q1 <= q0;
  21.     always @ (posedge clk1 or negedge rst)
  22.         if(!rst)
  23.             q2 <= 0;
  24.         else
  25.             q2 <= sel & ~q1;
  26. always@(negedge clk1 or negedge rst)
  27. if(!rst)
  28. q3 <= 0;
  29. else
  30. q3 <= q2;
  31. assign clk_out = (q1 & clk0) | (q3 & clk1);
  32. endmodule

同步时钟:两个同源时钟、两个同频(倍频)且同相或者两个同频(倍频)且有固定相位差

异步时钟:不同源、同源但频率比不是整数倍、同源虽频率比为整数倍但不满足时序要求

原理:利用公式1. Pi = ai bi (可以写为ai + bi)2. Gi = aibi 3. Ci = Gi + Ci-1Pi 4. Si = Pi Ci-1

  • 无损定点化

将小数部分一直乘2直到出现小数部分小于0.5的次数,该次数即为最小位数的无损量化位数

  • 计数器设计

数字电子技术基础(阎石)P100

  • 线与逻辑

OD门

  • verilog阻塞与非阻塞的定义与区别

阻塞语句在Verilog中使用=运算符进行编码,并在创建组合逻辑时使用。该运算符阻止模拟器执行后续语句,直到完成当前求值和赋值。

非阻塞语句在 Verilog 中使用 <= 运算符进行编码,在时钟进程中对触发器进行编码时始终使用。赋值将推迟到计算完所有后续语句。 这允许并行或并发执行语句

  • 格雷码转二级制码

  1. verilog中function的使用

函数只能在模块中定义,位置任意,并在模块的任何地方引用,作用范围也局限于此模块。

特点:

1)不含有任何延迟、时序或时序控制逻辑

2)至少有一个输入变量

3)只有一个返回值,且没有输出

4)不含有非阻塞赋值语句

5)函数可以调用其他函数,但是不能调用任务

6)函数不能单独作为一条语句出现,只能放在赋值语言的右端

函数在声明时,会隐式的声明一个宽度为 range、 名字为 function_id 的寄存器变量,函数的返回值通过这个变量进行传递。当该寄存器变量没有指定位宽时,默认位宽为 1。

在 Verilog 中,一般函数的局部变量是静态的,即函数的每次调用,函数的局部变量都会使用同一个存储空间。若某个函数在两个不同的地方同时并发的调用,那么两个函数调用行为同时对同一块地址进行操作,会导致不确定的函数结果。

Verilog 用关键字 automatic 来对函数进行说明,此类函数在调用时是可以自动分配新的内存空间的,也可以理解为是可递归的。因此,automatic 函数中声明的局部变量不能通过层次命名进行访问,但是 automatic 函数本身可以通过层次名进行调用。

阶乘例子:

  1. wire [31:0] results3 = factorial(4);
  2. function automatic integer factorial ;
  3. input integer data ;
  4. integer i ;
  5. begin
  6. factorial = (data>=2)? data * factorial(data-1) : 1 ;
  7. end
  8. endfunction // factorial
  1. verilog中task的使用

任务更像一个过程,不仅能完成函数的功能,还可以包含时序控制逻辑。

特点

a)任务可以没有或者有多个输入,且端口声明可以为 inout 型

b)任务可以没有或者有多个输出

c)任务没有返回值

d)任务可以在非零时刻执行

e)任务不能出现 always 语句,但可以包含其他时序控制,如延时语句

f)任务可以调用函数和任务

g)任务可以作为一条单独的语句出现语句块中

进行任务的逻辑设计时,可以把 input 声明的端口变量看做 wire 型,把 output 声明的端口变量看做 reg 型。但是不需要用 reg 对 output 端口再次说明。

  1. task xor_oper_iner;
  2. input [N-1:0] numa;
  3. input [N-1:0] numb;
  4. output [N-1:0] numco ;
  5. //output reg [N-1:0] numco ; //无需再注明 reg 类型,虽然注明也可能没错
  6. #3 numco = numa ^ numb ;
  7. //assign #3 numco = numa ^ numb ; //不用assign,因为输出默认是reg
  8. endtask

输入端连接的模块内信号可以是 wire 型,也可以是 reg 型。输出端连接的模块内信号要求一定是 reg 型,这点需要注意。

  1. G = B ^ (B >>1)
  2. B[i-1] = G[i-1] ^ B[i]
  3. // 用function封装起来的gray to bin
  4. function [5:0] gray2bin;
  5. input [5:0]gray_in;
  6. reg [5:0]gray_code;
  7. reg [5:0]bin_code;
  8. integer i,j;
  9. reg tmp;
  10. begin
  11. gray_code=gray_in;
  12. for(i=0;i<=5;i=i+1)
  13. begin
  14. tmp=1’b0;
  15. for(j=i;j<=5;j=j+1)
  16. tmp=gray_code^tmp;
  17. bin_code[i]=tmp;
  18. end
  19. gray2bin=bin_code;
  20. end
  21. endfunction
  22. assign data=gray2bin(gray_bin); //调用
  23. // 一种参数化格雷码转二进制码的方法
  24. module gray2bin (bin, gray);
  25. parameter SIZE = 4;
  26. output [SIZE-1:0] bin;
  27. input [SIZE-1:0] gray;
  28. reg [SIZE-1:0] bin;
  29. integer i;
  30. always @(gray)
  31. for (i=0; i<SIZE; i=i+1)
  32. bin[i] = ^(gray>>i);
  33. endmodule
  • 同步fifo

  1. `timescale 1ns/1ns
  2. module syn_fifo#(
  3. parameter WIDTH = 8,
  4. parameter DEPTH = 16
  5. )(
  6. input clk ,
  7. input rst_n ,
  8. input winc ,
  9. input rinc ,
  10. input [WIDTH-1:0] wdata ,
  11. output reg wfull ,
  12. output reg rempty ,
  13. output wire [WIDTH-1:0] rdata
  14. );
  15. // 用localparam定义一个参数,可以在文件内使用
  16. localparam ADDR_WIDTH = $clog2(DEPTH);
  17. reg [ADDR_WIDTH:0] waddr;
  18. reg [ADDR_WIDTH:0] raddr;
  19.     //第一部分---写地址产生逻辑
  20. always @ (posedge clk or negedge rst_n) begin
  21. if(~rst_n) begin
  22. waddr <= 'b0;
  23. end
  24. else begin
  25. if( winc && ~wfull ) begin
  26. waddr <= waddr + 1'b1;
  27. end
  28. else begin
  29. waddr <= waddr;
  30. end
  31. end
  32. end
  33.     // 第二部分---读地址产生逻辑
  34. always @ (posedge clk or negedge rst_n) begin
  35. if(~rst_n) begin
  36. raddr <= 'b0;
  37. end
  38. else begin
  39. if( rinc && ~rempty ) begin
  40. raddr <= raddr + 1'b1;
  41. end
  42. else begin
  43. raddr <= raddr;
  44. end
  45. end
  46. end
  47.    
  48.     // 第三部分---读空以及写满信号产生
  49. always @ (posedge clk or negedge rst_n) begin
  50. if(~rst_n) begin
  51. wfull <= 'b0;
  52. rempty <= 'b0;
  53. end
  54. else begin
  55. wfull <= (raddr == {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH-1:0]});
  56. rempty <= (raddr == waddr);
  57. end
  58. end
  59. // 带有 parameter 参数的例化格式
  60. dual_port_RAM
  61. #(
  62. .DEPTH(DEPTH),
  63. .WIDTH(WIDTH)
  64. )
  65. dual_port_RAM_U0
  66. (
  67. .wclk(clk),
  68. .wenc(winc && ~wfull),
  69. .waddr(waddr[ADDR_WIDTH-1:0]),
  70. .wdata(wdata),
  71. .rclk(clk),
  72. .renc(rinc && ~rempty),
  73. .raddr(raddr[ADDR_WIDTH-1:0]),
  74. .rdata(rdata)
  75. );
  76. endmodule
  77. /**************RAM 子模块*************/
  78. // 该模块是一个简单双端口ram
  79. module dual_port_RAM #(parameter DEPTH = 16,
  80. parameter WIDTH = 8)(
  81. input wclk
  82. ,input wenc
  83. ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
  84. ,input [WIDTH-1:0] wdata //数据写入
  85. ,input rclk
  86. ,input renc
  87. ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
  88. ,output reg [WIDTH-1:0] rdata //数据输出
  89. );
  90. reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
  91. always @(posedge wclk) begin
  92. if(wenc)
  93. RAM_MEM[waddr] <= wdata;
  94. end
  95. always @(posedge rclk) begin
  96. if(renc)
  97. rdata <= RAM_MEM[raddr];
  98. end
  99. endmodule
  • RCA(行波进位加法器)

  • CSR(进位保存加法器)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/494133
推荐阅读
  

闽ICP备14008679号