简析

这道题比较难,想了很久才写出满意的程序。首先,方波的周期是20,锯齿波的周期是21,三角波的周期是40,且wave的最大值是20。题目没有明确告知,我是从其他人的题解中知道的。下面分别分析一下三种波形如何产生。

方波

方波模式需注意wave在什么时候翻转。设置一个计数器cnt,计数范围是0-19。该计数器仅在方波模式也就是wave_choise==0时工作。

// 仅在方波模式工作的计数器
always@(posedge clk or negedge rst_n) begin
    if(~rst_n)
      cnt <= 0;
    else
      cnt <= wave_choise!=0 ? 0:
             cnt        ==19? 0:
             cnt + 1;
end

cnt值在0~9时,wave==20;当cnt值在10~19时,wave==0。也就是wave应在cnt==10时从0变为20。但由于非阻塞赋值,cnt==10时,wave应对cnt==9是否成立进行判断。cnt==19也是同样原因。

wave <= cnt ==9 ? 20: 
        cnt ==19? 0 :
        wave;

锯齿波

锯齿波比较简单。wave产生锯齿波时,需要从0增加到20,所以周期是21。 当wave增加到20时,清零。

wave <= wave==20? 0: wave+1;

三角波

三角波模式需要设置一个标志位flagflag仅在三角波模式也就是wave_chosie==2时工作。当flag==0时,wave减少;当flag==1时,wave增加。

wave <= flag==0 ? wave-1: wave+1;

alt
由波形图得知,刚进入三角波模式时,wave是下降的,所以flag的默认值是0。wave在最小值0和最大值20时,flag应进行翻转。同样由于是非阻塞赋值,所以wave上升到19时,flag从1到0,也就是flag <= wave==19&&flag==1? 0: flagwave下降到1时,flag从0到1,也就是flag <= wave==1&&flag==0? 1: flag

    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            flag <= 0;
        else
            flag <= wave_choise!=2 ? 0:
                    wave       ==1 ? 1:    
                    // wave==1&&flag==0 ? 1: // 等价
                    wave       ==19? 0:    
                    // wave==19&&flag==1 ? 0: // 等价
                    flag;
    end

代码

`timescale 1ns/1ns
module signal_generator(
	input clk,
	input rst_n,
	input [1:0] wave_choise,
	output reg [4:0]wave
	);

    reg [4:0] cnt;
    reg flag;
    
  	// 方波模式下,计数器控制
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            cnt <= 0;
        else
            cnt <= wave_choise!=0 ? 0:
                   cnt        ==19? 0:
                   cnt + 1;
    end
    
  	// 三角波模式下,标志位控制
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            flag <= 0;
        else
            flag <= wave_choise!=2 ? 0:
                    wave       ==1 ? 1:
                    wave       ==19? 0:
                    flag;
    end
    
  
  	// 更新wave信号
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) 
            wave <= 0;
        else 
            case(wave_choise)
                0      : wave <= cnt == 9? 20    : 
                                 cnt ==19? 0     :
                                 wave;
                1      : wave <= wave==20? 0     : wave+1;
                2      : wave <= flag==0 ? wave-1: wave+1;
                default: wave <= 0;
            endcase
    end
endmodule