https://hdlbits.01xz.net/wiki/Build a Circuit from Simulation Waveform、testbench答案

1.sim

module top_module (
    input a,
    input b,
    output q );//

    assign q = a & b; // Fix me
endmodule

2.circuit2

module top_module (
    input a,
    input b,
    input c,
    input d,
    output q );//
    assign q = ((~a) & (~b) & (~c) & (~d)) | ((~a) & (~b) & (c) & (d)) | ((~a) & (b) & (~c) & (d)) |  
       		   ((~a) & (b) & (c) & (~d)) | ((a) & (~b) & (~c) & (d)) | ((a) & (~b) & (c) & (~d))
        | ((a) & (b) & (~c) & (~d)) | ((a) & (b) & (c) & (d)); // Fix me
endmodule

一看这有一半是1我就怀疑不能化简的了。。。果然果然。
3.circuit3

module top_module (
    input a,
    input b,
    input c,
    input d,
    output q );//

    assign q = ~(((~c) & (~d)) | ((~a) & (~b))); // Fix me
endmodule

这里q等于1有九个显然是可以化简的。
4.Circuit4

module top_module (
    input a,
    input b,
    input c,
    input d,
    output q );//

    assign q = ~((~b) & (~c)); // Fix me
endmodule

等于零的只有四个量,显然应该从此处下手
5.Circuit5

module top_module (
    input [3:0] a,
    input [3:0] b,
    input [3:0] c,
    input [3:0] d,
    input [3:0] e,
    output [3:0] q );

    always@(*)begin
        case(c)
            4'd0: q = b;
            4'd1: q = e;
            4'd2: q = a;
            4'd3: q = d;
            default: q = 4'hf;
        endcase
    end
endmodule

从波形图可以看出来应该是一个四选一的MUX同时有默认输出4'b1111。组合电路必须有默认输出,否则就构成锁存器了。
6.Circuit6

module top_module (
    input [2:0] a,
    output [15:0] q ); 
	
    always@(*)begin
        case(a)
            3'd0: q = 16'h1232;
            3'd1: q = 16'haee0;
            3'd2: q = 16'h27d4;
            3'd3: q = 16'h5a0e;
            3'd4: q = 16'h2066;
            3'd5: q = 16'h64ce;
            3'd6: q = 16'hc526;
            3'd7: q = 16'h2f19;
            default: q = 16'h0;
        endcase
    end
endmodule

这理应是一个八选一MUX,默认输出是我自己加的,但是建议还是要有,这毕竟是组合电路。
7.Circuit7

module top_module (
    input clk,
    input a,
    output q );
    always@(posedge clk)begin
        if(~a)
            q <= 1'b1;
        else
            q <= 1'b0;
    end
endmodule

一个时钟控制的同步输出的反相器。
8.Circuit8

module top_module (
    input clock,
    input a,
    output p,
    output q );
	reg p0;
    reg p1;
    always@(*)begin
        if(clock)
            p1 = a;
        else
            p1 = 1'b0;
    end
    always@(negedge clock)begin
        q <= a;
        p0 <= a;
    end
    
    assign p = (clock)? p1 : p0;
endmodule

首先这里q的逻辑简单,就是下降沿时把a赋值进来,p则是clock高电平同步a,下降沿时保持此时的a(或者说是保持上一个时刻的p),所以这里p有组合的部分也有时序的部分,因而必须把两部分分开最后用一个MUX接上再输出。
9.Circuit

module top_module (
    input clk,
    input a,
    output [3:0] q );
    
    always@(posedge clk)begin
        if(a)
            q <= 4'd4;
        else if(q==4'd6)
            q <= 4'd0;
        else
            q <= q + 4'd1;
    end
endmodule

这个的逻辑也很清晰,是一个若a为高电平则同步置位为4,若a为低电平则计数,计数为7进制即到7就置零。
10.Circuit10

module top_module (
    input clk,
    input a,
    input b,
    output q,
    output state  );
    reg next_state;
    
    always@(*)begin
        case(state)
            1'b0: next_state = a & b;
            1'b1: next_state = ~((~a) & (~b));
            default: next_state = 1'b0;
        endcase
    end
    
    always@(posedge clk)
        state <= next_state;
    
    assign q = (state)? ~(a^b) : (a^b); //异步输出
endmodule

观察波形就可以知道这里必须写异步输出。


以下是tb部分,只有五个所以写一起了
1.Clock

`timescale 1ps/1ps
module top_module ( );
    reg clock;
    initial
    begin
        clock = 0;
        forever
            #5 clock = ~clock;
    end
    dut dut_1(clock);
endmodule

在我的博客Verilog描述方法与层次的高级编程语句部分和Verilog 语言基础的编译指令部分中,已经写到了如何生成一个时钟。
读者如有兴趣可以去看一看。
2.tb1

module top_module ( output reg A, output reg B );//

    // generate input patterns here
    initial begin
        A = 1'b0;
        B = 1'b0;
        #10 A = 1'b1;
        #5  B = 1'b1;
        #5  A = 1'b0;
        #20 B = 1'b0;
    end
        /*fork
        A <= 1'b0;
        B <= 1'b0;
        #10 A <= 1'b1;
        #15 B <= 1'b1;
        #20 A <= 1'b0;
        #40 B <= 1'b0;
        这是非阻塞的写法
    join */

endmodule

这里我把顺序和并发的写法都写了出来,顺序的延时的计数的个数是针对上一个延时的时点,而并发延时则是针对整个测试的起点。
如有兴趣,读者可以看一看我的博客Verilog描述方法与层次中的语句组部分, 举例具体说明了两者的区别。
3.and Gate

module top_module();
    reg[1:0] in;
    reg out;
    reg out1;
    initial begin
        #0  in  = 2'b00;
        #0  out = 1'b0;
        #10 in  = 2'b01;
        #10 in  = 2'b10;
        #10 in  = 2'b11;
        #0  out = 1'b1;
    end
    andgate andgate1(in, out1);
endmodule

这里实际上就说明了一个tb是如何运行的,可以自己在写测试波形的时候同时写出应该得到的结果的波形,最后就将实例化结果的波形与预期波形作比较即可。
4.tb2

module top_module();
    reg clk;
    reg in;
    reg[2:0] s;
    reg out;
    initial fork
        #0 clk = 1'b0;
        #0  s  = 3'd2;
        #0  in = 1'b0;
        #10 s  = 3'd6;
        #20 s  = 3'd2;
        #20 in = 1'b1;
        #30 s  = 3'd7;
        #30 in = 1'b0;
        #40 s  = 3'd0;
        #40 in = 1'b1;
        #70 in = 1'b0;
        forever #5 clk = ~clk;
    join
    q7 q7_1(clk, in, s, out);
endmodule

实际写tb时就会发现,如果这里用顺序语句组begin...end就没法在initial块中全写出来,用并发语句组fork...join则可以避免这个问题了。主要是forever语句生成时钟带来的问题。使用并发语句组就可以避免了。
5.tb/dff

module top_module ();
    reg clk;
    reg reset;
    reg t;
    reg q;
    initial fork
        #0  clk = 1'b0;
        #0  reset = 1'b1;
        #0  t = 1'b0;
        #10 reset = 1'b0;
        #10  t = 1'b1;
        forever #5 clk = ~clk;
    join
    tff tff_1(clk, reset, t, q);
endmodule

这是最后一题了,没什么难度,没有什么特别要注意的。

习题链接
如果有错误或者有别的想法,欢迎批评和讨论。


写在最后

到这里HDLbits所有的题目我就都完成了。
刚开始时我也就是个初学者,一点也不会,前前后后两周一边看书,看完一遍后再开始做题,边做又边整理书本上的内容,在状态机那里前前后后被折磨了四五天T.T真的挺痛苦的,但是我想这也是学习的必经之路,我的正确率也不算高,因为还保留着写软件代码时那种让ide来帮忙找bug的心态,这其实在硬件代码是很不可取的。也是一种惰性思想,学习本就是多思考,能做完美的事情就不应该因为偷懒加上瑕疵。
希望我的答案对大家的学习能有所帮助。
我的答题情况

posted @ 2021-04-04 15:13  黑衣の甘铃儿  阅读(223)  评论(0)    收藏  举报