HDLBits 0~117

4 digital BCD adder

module top_module( 
    input [15:0] a, b,
    input cin,
    output cout,
    output [15:0] sum );
    
    wire cout1[3:0];
    assign cout = cout1[3];
    
    bcd_fadd bcd_u1(
        .a(a[3:0]),
        .b(b[3:0]),
        .cin(cin),
        .cout(cout1[0]),
        .sum(sum[3:0]) );
    
    genvar i;
    
    generate 
        for(i = 1;i<4;i++) begin:name_u1
         	bcd_fadd bcd_u2(
                .a(a[i*4+3:i*4]),
        		.b(b[i*4+3:i*4]),
                .cin(cout1[i-1]),
                .cout(cout1[i]),
        		.sum(sum[i*4+3:i*4]) );   
        end
    endgenerate

endmodule

3-variable

module top_module(
    input a,
    input b,
    input c,
    output out  ); 
    assign out = (~a)&(~b)&(~c);
	//assign out  = a|b|c;
endmodule

4-variable -1

在这里插入图片描述

	//最小项积之和
    assign out = (~c&~b)|(~a&~d)|(a&c&d)|(b&c&d);
    //最大项和之积,原则上化简时圈的大小为1,2,2的n次方格
    //还要注意的是代码中的或是|,文本或是+,要注意转换
    assign out = (~a|~c|d)&(a|b|~c|~d)&(~b|c|~d)&(~a|~b|c);

4-variable -2

 assign out = a|(~b&c);  //最小项
 assign out = (a|c)&(a|~b);  //最大项

4-variable -3

//考虑一下只能这样写,有其他更加简便的方法请在评论区讨论
assign out = (~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);

minimum SOP and POS

module top_module (
    input a,
    input b,
    input c,
    input d,
    output out_sop,
    output out_pos
); 
    assign out_sop = ((c&d)|(~a&~b&c));
    assign out_pos = (c)&(~a|d)&(~b|d);
   	
endmodule

karnaugh map

module top_module (
    input [4:1] x, 
    output f );
    assign f = (x[1]|x[3])&(~x[1]|~x[3])&(~x[1]|x[2]);

endmodule

karnaugh map -1

module top_module (
    input [4:1] x,
    output f
); 
    assign f = (x[3]|~x[4])&(~x[2]|x[3])&(~x[1]|x[2]|~x[4])&(~x[1]|~x[2]|x[4]);
endmodule

k-map implement with a multiplexer

module top_module (
    input c,
    input d,
    output [3:0] mux_in
); 
    wire [1:0] data;
    assign data = {c,d};
    
    always@(*)begin
        case(data)
            2'b00:mux_in = 4'b0100;
            2'b01:mux_in = 4'b0001;
            2'b11:mux_in = 4'b1001;
            2'b10:mux_in = 4'b0101;
        endcase
    end
endmodule


Dff16e

module top_module (
    input clk,
    input resetn,
    input [1:0] byteena,
    input [15:0] d,
    output [15:0] q
);
    always@(posedge clk) begin
        if(~resetn)
            q <= 16'b0;
        else if(byteena[0] | byteena[1]) begin
            if(byteena[0])
                q [7:0] <= d[7:0];
            if(byteena[1])
                q [15:8] <= d[15:8];
        end
    end

endmodule

Exams/m2014 q4a

在这里插入图片描述

  上图显示的元件没有 clk 端口,取而代之的是 ena 端口,所以这是一个锁存器,有clk的是触发器。
  锁存器的特征在于,锁存器锁存的触发事件发生于使能端 ena 的电平。当使能信号有效时,输出端 Q 的值为输入端 D 的值,当门使能信号无效时,输入数据保持在锁存器中,锁存器是一种电平敏感电路。相比之下,触发器属于边沿敏感电路,数据输入 D 端的值只会在时钟信号的上下边沿才会被保存到寄存器中。
  FPGA 中使用相同的物理资源实现触发器和锁存器,在结构上有一定的不同。但锁存器会给电路的时序分析带来困扰。导通期间,锁存器会直接将输入信号的毛刺带入后级。在对触发器做时序分析时,只需要考虑时钟的上下边沿触发的时刻,即在上下边沿计算输入输出信号的建立时间和保持时间。但对于锁存器做分析时,还需要考虑使能信号上下边沿之间的持续时间。
  Xilinx 在综合出锁存器后,会提醒用户注意补全不完整的 if 语句的表达,并表示因为时序问题,在 FPGA/CPLD 设计中不推荐使用锁存器。
  总结来说就是,由于时序问题,不推荐电平触发,但若触发为电平敏感电路,要注意补全If-else的情况,电平信号不变时默认是保持,如果要为其他值(eg:0)要注意补全

Exams/m2014 q4d

//输出可以出现在运算符的右边
module top_module (
    input clk,
    input in, 
    output out);
    always@(posedge clk) begin
        out <= in^out;
    end

endmodule

Mt2015 muxdff

module top_module (
	input clk,
	input L,
	input r_in,
	input q_in,
	output reg Q);
    
    wire D;
    assign  D = (L)?r_in:q_in;
    
    always@(posedge clk) begin
        Q <= D;
    end

endmodule

Exams/2014 q4a

module top_module (
    input clk,
    input w, R, E, L,
    output Q
);
    wire d1,d2;
    assign d1 = (E)?w:Q;
    assign d2 = (L)?R:d1;
    
    always@(posedge clk) begin
        Q <= d2;
    end

endmodule

Exams/ece241 2014 q4

这里写的代码仿真出现的错误改正方法如下链接添加链接描述

module top_module (
    input clk,
    input x,
    output z
); 
    reg Q1,Q2,Q3;
   	initial z = 1;
    
    always@(posedge clk) begin
        Q1 = x^Q1;
        Q2 = x&(~Q2);
        Q3 = x|(~Q3);
        z = ~(Q1|Q2|Q3);
    end
    
endmodule

Exams/ece241 2013 q7

module top_module (
    input clk,
    input j,
    input k,
    output Q); 
    
    initial Q = 0;
    
    always@(posedge clk) begin
        if(j^k)
             Q = (j)?1:0;
        else if(j&k)
             Q = ~Q;
        else
           	 Q = Q;
    end

endmodule

Edgedetect

//这题和下题不同处在于上升沿检测
//关于上升沿检测,我的理解是这里相当与把输入信号打一拍,相对于原输入信号有一定的编译,然后在上升沿进行判断
//我第一次写的是阻塞符号,这是错误的,这里注意要非阻塞符号,只有这样才能达到,判断新旧值得同时,用新值覆盖旧值。
module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    reg [7:0] temp;
    always@(posedge clk) begin
        temp <= in;
        pedge <= ~temp&in;
    end
endmodule


Edgedetect2

//这里就可以使用异或进行全检测
module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    reg [7:0] temp;
    always@(posedge clk) begin
        temp <= in;
        pedge <= temp^in;
    end
endmodule

Edgecapture

  下面的代码得思路是,检测到输入为0时,说明发生了32b矢量减少的事件,然后或运算计算输出,单仿真出来有部分不正确,在这里插入图片描述

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    reg [31:0] temp;
    always@(posedge clk)begin
            temp <= in;
    end
	always@(posedge clk)begin
        if(reset)
            out <= 32'b0;
       // 错误 else if(in == 32'b0)
       // 错误 out <= temp|out;
       else 
            out <= ~in&temp|out;
            //修改为前面~in&temp检测下降沿,后面是输出时序图的逻辑就正确通过了
    end
endmodule

Dualedge

//该题还是有点难度,这种思路挺好的,需要学习
module top_module (
    input clk,
    input d,
    output q
);

    reg q1,q2;
    assign q = clk?q1:q2;
    
    always@(posedge clk) begin  
        q1 <= d;
    end
    always@(negedge clk) begin  
        q2 <= d;
    end
endmodule

Count15/10

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);
    always@(posedge clk) begin
        if(reset) 
            q <= 0;
        else
      		q <= q + 1;
    end

endmodule
//count10//
module top_module (
    input clk,
    input reset,        // Synchronous active-high reset
    output [3:0] q);
    always@(posedge clk) begin
        if(reset)
            q <= 0;
        else if(q == 4'b1001)
            q <= 0;
        else
            q <= q +1;
    end

endmodule
//count1to10/
module top_module (
    input clk,
    input reset,
    output [3:0] q);
    always@(posedge clk) begin
        if(reset)
            q <= 1;
        else if(q == 4'b1010)
            q <= 1;
        else
            q <= q + 1;
    end

endmodule
//Countslow
module top_module (
    input clk,
    input slowena,
    input reset,
    output [3:0] q);

    reg [3:0] cnt; //这是自己要注意的点
    //period is 10 
    always @ (posedge clk)
        begin
            if(reset)
                cnt <= 4'b0;
            else if(slowena == 1'b1)
                //slowena 为高,计数器才能正常运行
                begin
                    if(cnt == 4'd9)
                        cnt <= 4'b0;
      //因为题目要求周期为10,所以0~9之后下一个为0;
                    else 
                        cnt <= cnt + 4'd1;
                end
        end
    assign q = cnt;

endmodule


Exams/ece241 2014 q7a

在这里插入图片描述
c_enable在上升沿有效时,计数器计数,但是c_load结合了复位和重置两种功能,所以该控制信号在复位信号或者输出为12时有效(因为是连续赋值语句,所以信号是同步变化,自己要区分好),但是通过分析波形图可知,c_load在置数时还要满足enable信号同样有效,其实这个逻辑是我没考虑到的逻辑,及只有加法器被使能的情况下,才能够加载数值,不然如果在enable之前正好空出一个上升沿,会提早加载数值,同时题目还提到,load的优先级高于enable,两者信号同时有效时,优先数值置数。

//这段代码,仿真出来又部分错误,在代码中给出错误前后分析
module top_module (
    input clk,
    input reset,
    input enable,
    output [3:0] Q,
    output c_enable,
    output c_load,
    output [3:0] c_d
); //
	assign c_enable = enable;
	//这种是错误的 assign c_load = reset | Q == 4'b1100
    assign c_load = reset | (Q == 4'b1100 & enable) ;
    assign c_d = 4'b0001;
    
    count4 the_counter(
        .clk(clk),
        .load(c_load),
        .enable(enable),
        .d(c_d),
        .Q(Q));
    
endmodule


Exams/ece241 2014 q7b

这个题需要注意的点有:
1.给出的BCD码是一个模10的计数器,所以本题的考察希望用101010,利用三个计数器来完成1000的计数,我们只需要考虑下一个计数器的使能问题,而不需要考虑置数的问题,我刚开始被这个问题困扰了一会。
2.整理的思路就是计数快的计数器是个位,然后是十位,百位,所以OneHerz判断的时候要三位都进行考虑,我这个刚开始认为只需要判断最高位count[2]就可以了,这就会导致990之后OneHerz信号都是有效的,是错误的,必须三位同时满足,OneHerz才能正确表达状态。

module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); 
    reg [3:0] cout0,cout1,cout2;
    
    assign  c_enable[0] = 1;
    assign  c_enable[1]= (cout0 == 4'b1001)?1:0;
    assign  c_enable[2] = (cout1 == 4'b1001&&cout0 == 4'b1001)?1:0;
    
    assign 	OneHertz = (cout2 == 4'b1001 && cout1 == 4'b1001 && cout0 == 4'b1001);
    
    bcdcount counter0 (
        .clk(clk),
        .reset(reset), 
        .enable(c_enable[0]),
        .Q(cout0));
    
    bcdcount counter1 (
     	.clk(clk),
        .reset(reset), 
    	.enable(c_enable[1]),
    	.Q(cout1));
    
    bcdcount counter2 (
 		.clk(clk),
        .reset(reset), 
    	.enable(c_enable[2]),
    	.Q(cout2));
endmodule

Countbcd

这个题就是4个模10的BCD计数器组成4位的计数器,需要自己书写模10的BCD代码,然后进行例化,其中的ena[3:1]波形图上看起来是每位计数器的一个计数为9的flag计数器,相应的也作为下一位计数器的一个使能信号,这是这个题的关键,要注意的点和上一个类似,就是ena的判断信号要考虑低位的情况。

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    
    reg [15:0] Q;
    
    
    assign ena[1] = (Q[3:0] == 4'b1001);
    assign ena[2] = (Q[7:4] == 4'b1001&&Q[3:0] == 4'b1001);
    assign ena[3] = (Q[11:8] == 4'b1001&&Q[7:4] == 4'b1001&&Q[3:0] == 4'b1001);
    
    BCD BCD_inst0(clk,reset,1,Q[3:0]);
 	BCD BCD_inst1(clk,reset,ena[1],Q[7:4]);
    BCD BCD_inst2(clk,reset,ena[2],Q[11:8]);
    BCD BCD_inst3(clk,reset,ena[3],Q[15:12]);
    assign q = Q;

endmodule
                
module BCD(
    input clk,
    input reset,
    input enable,
    output [3:0] Q);
    
    always@(posedge clk)begin
        if(reset)
            Q <= 4'b0;
        else if(enable) begin
        	if(Q == 4'b1001)
            	Q <= 4'b0;
        	else
           	 	Q <= Q + 1;
        end
    end
endmodule

Count clock(12小时制时钟计数器)

  12小时制时钟计数器,接下来记录一下我对这部分代码的一个理解,我考虑的时候是每次从12:00开始计数,然后计12个小时后,11.59.59分重新计数,其中有几个难点了,记录如下:
  1.代码的逻辑顺序是优先考虑秒,分,时,因为高位时间是以低位时间的信号作为使能信号,所以先写秒,再写分,每个变量的改变使用一个always块,这样足够清晰。
  2.低位给高位的使能信号要叠加考虑,通过前面练习题,可以掌握该知识点,eg:时,改变时要结合判断分和秒都计数到59,而12点归为01时,在增加使能信号的基础上加上判断是否为12的判断逻辑即可
  3.同时还要考虑的点是,因为是16进制计数但是要显示为十进制,所以在自增时还要增加一些判断条件,我的方法是分高四位和第四位来进行自增,低位进行0~9的自增,高位判断低位达到9时自增,同时置低位为0。
在这里插入图片描述

//今天在图书馆完成了这部分代码,很有成就感,还是要坚持联系
module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    wire [3:1] flag;
    
    always@(posedge clk) begin
        if(reset)
            pm <= 0;
        else if(hh == 8'h11 && mm == 8'h59 && ss == 8'h59)
            pm <= ~pm;  
    end
    
    always@(posedge clk) begin
        if(reset) begin
            hh <= 8'h12;
        end
        else if(ena) begin
            if(hh == 8'h12 && mm == 8'h59 && ss  == 8'h59) 
                hh <= 8'h1; 
            else if(mm == 8'h59 && ss  == 8'h59)
                if (hh[3:0] == 4'b1001) begin  
                    hh[3:0] <= 4'h0;
                    hh[7:4] <= hh[7:4] + 1;
                end
                else
                    hh[3:0] <= hh[3:0] + 1;
        end 
    end

    always@(posedge clk) begin
        if(reset) begin
            mm <= 8'h00;
        end
         else if(ena) begin
             if(mm == 8'h59 && ss == 8'h59)
               mm <= 8'h0;
             else if(ss == 8'h59) begin
                 if (mm[3:0] == 4'b1001) begin 
                    mm[3:0] <= 4'h0;
                    mm[7:4] <= mm[7:4] + 1;
                 end
                 else
                    mm[3:0] <= mm[3:0] + 1;
             end
             
                      
        end 
    end
    
    always@(posedge clk) begin
        if(reset) begin
            ss <= 8'h00;
        end
        else if(ena) begin
            if(ss == 8'h59)
                ss <= 8'h0;
            else begin
                if (ss[3:0] == 4'b1001) begin
                    ss[3:0] <= 4'h0;
                    ss[7:4] <= ss[7:4] + 1;
                end
                else
                    ss[3:0] <= ss[3:0] + 1;
            end
        end
    end
    
endmodule

3-bit LFSR

module top_module (
	input [2:0] SW,      // R
	input [1:0] KEY,     // L and clk
	output reg [2:0] LEDR);  // Q

    wire clk = KEY[0];
    wire l = KEY[1];
    wire [2:0] d = l?SW:{LEDR[1]^LEDR[2],LEDR[0],LEDR[2]};
    
    always @(posedge clk)begin
            LEDR <=	d;
    end

endmodule

cLfsr32 and Exams/m2014 q4k

module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 32'h1
    output [31:0] q
); 
    wire [31:0] temp;
    assign temp = {q[0],q[31:23],q[22]^q[0],q[21:3],q[2]^q[0],q[1]^q[0]};
    
    always@(posedge clk) begin
        if(reset)
            q <= 32'h1;
        else begin
            q <= temp;
        end
    end
endmodule

Exams/m2014 q4k
module top_module (
    input clk,
    input resetn,   // synchronous reset
    input in,
    output reg out);
    
    reg q0,q1,q2;
    always@(posedge clk ) begin
        if(~resetn)	begin
            q0 <= 1'b0;
        	q1 <= 1'b0;
        	q2 <= 1'b0;
            out <= 1'b0;
        end
        else begin
            q0 <= in;
            q1 <= q0;
            q2 <= q1;
            out <= q2;
        end
    end

endmodule


Exams/2014 q4b

  找到的思路都是要通过例化模块来完成,这道题做的时候就不想例化,这里要注意几点:
  1.两个MUX级联,后面的选择器的优先级大于前面的选择器,后面一旦不选择前面送过来的信号,那么第一级的选择就是无用的
  2.在对于信号的判断的时候要用当下的信号,也就是LEDR而不能是q,这个问题卡了好久。


module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
); //
    wire clk;
    wire [3:0] q;
    reg [3:0] temp;
    assign LEDR = temp;
    
    assign q[0] = KEY[2]?
        				  SW[0]:
        				  KEY[1]?LEDR[1]:LEDR[0];
    		assign  q[1] = KEY[2]?
       					  SW[1]:
        				  KEY[1]?LEDR[2]:LEDR[1];
   			assign  q[2] = KEY[2]?
        				  SW[2]:
                          KEY[1]?LEDR[3]:LEDR[2];
    		assign  q[3] = KEY[2]?
                          SW[3]:
                          KEY[1]?KEY[3]:LEDR[3];
    /*这是错误的,会导致闩锁问题
    		assign q[0] = KEY[2]?
        				  SW[0]:
        				  KEY[1]?q[1]:q[0];
    		assign  q[1] = KEY[2]?
       					  SW[1]:
        				  KEY[1]?q[2]:q[1];
   			assign  q[2] = KEY[2]?
        				  SW[2]:
                          KEY[1]?q[3]:q[2];
    		assign  q[3] = KEY[2]?
                          SW[3]:
                          KEY[1]?KEY[3]:q[3];*/
    
    always@(posedge KEY[0]) begin	
    	temp <= q;    
    end
endmodule

  这是参考代码

module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
); //

MUXDFF ins3_MUXDFF(.clk(KEY[0]), .R(SW[3]),.E(KEY[1]),.L(KEY[2]),.w(KEY[3]), .Q(LEDR[3]));

MUXDFF ins2_MUXDFF(.clk(KEY[0]),.R(SW[2]),.E(KEY[1]),.L(KEY[2]),.w(LEDR[3]),.Q(LEDR[2]));

MUXDFF ins1_MUXDFF(.clk(KEY[0]),.R(SW[1]),.E(KEY[1]),.L(KEY[2]),.w(LEDR[2]),.Q(LEDR[1]));

MUXDFF ins0_MUXDFF(.clk(KEY[0]),.R(SW[0]),.E(KEY[1]),.L(KEY[2]),.w(LEDR[1]),.Q(LEDR[0]));

endmodule

module MUXDFF (
    input clk,
    input w, R, E, L,
    output reg Q
);

wire D_i;
assign D_i = L?R:(E?w:Q);
always @(posedge clk) begin
    Q <= D_i;  
end

endmodule

Exams/ece241 2013 q12

//这里要注意的问题是在做case的匹配如果使用拼接运算符,要主要先是括号然后再是拼接运算符。
module top_module (
    input clk,
    input enable,
    input S,
    input A, B, C,
    output Z ); 
    
    reg [7:0] NUM;
    
    always@(posedge clk) begin
        if(enable) begin
            NUM <= {NUM[6:0],S};
        end
        else
            NUM <= NUM;
    end
    
    always@(*) begin
        case({A,B,C}) 
            3'b000: Z = NUM[0]; 
            3'b001: Z = NUM[1];
            3'b010: Z = NUM[2];
            3'b011: Z = NUM[3];
            3'b100: Z = NUM[4];
            3'b101: Z = NUM[5];
            3'b110: Z = NUM[6];
            3'b111: Z = NUM[7];
        endcase
    end
      

endmodule

Rule90

//这道题我卡了好久,题目的描述让我刚开始考虑偏了,导致思路一直没有在正确的道路上,题目的意思就是计算一位的结果需要左右两边的值异或得到,这就意味着三位数只能输出一位结果,如果想要两位结果,那么就需要前后补零来计算,所以我的思路是,将数值向后移动^数值向前移动,相当当前位的结果由自己的前后决定。当然也可以循环来计算每一位。
module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 
    always@(posedge clk) begin
        if(load) begin
            q <= data;
        end
        else
            q <= ({1'b0,q[511:1]}^{q[510:0],1'b0});
    end

endmodule

rule 110

在这里插入图片描述

//这种移动的方法的好吃是每一位都是一致的逻辑,不需要分开讨论,只需要根据化简得逻辑进行运算即可。
//这里我刚开始犯的错误是,left和right得取值都是来自输入data,没有考虑周全
//通过这一点体会到了Verilog代码虽然在等式得前后都是相同变量,但是有先后之分,后面代码得书写一定要注意。
module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 
    
    wire [511:0] left,right;
    integer i;
    
    assign right = {q[510:0],1'b0};
    assign left = {1'b0,q[511:1]};
    
    always@(posedge clk) begin
        if(load) begin
            q <= data;
        end
        else begin
            q <= (q&~right)|(right&~left)|(right&~q);
        end                 
    end

endmodule

Conwaylife

  这道题我做的时间也有点长,刚开始用添加patch的方法,变换为18*18的矩阵,应为verilog截取向量比较方便,所以这种相对比较简单,实现代码在下面。

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 
    
    reg  [2:0] sum [255:0];//[2:0]表示位宽,256表示的是个数
    reg [17:0] q_temp [17:0];
    integer i,j;
    integer up,down,left,right;
    
    always@(*) begin
        q_temp[0][17:0] = {q[240], q[255:240], q[255]};  ///这里要注意,第一次拼接我有点写反了
        q_temp[17][17:0] = {q[0], q[15:0],q[15]};
        for(i=1;i<17;i=i+1)begin
            q_temp[i][17:0] = {q[16*i-16], q[(i*16-1)-:16], q[16*i-1]};
        end
    end
    
    always@(*) begin
        for(i = 1;i<17;i++) begin
            for (j = 1;j<17;j++) begin
                up    = i-1;
                down  = i+1;
                left  = j-1;
                right = j+1;
                sum[16*(i-1) + (j-1)] = q_temp[up][left] + q_temp[up][j] + q_temp[up][right]+
                                        q_temp[i][left] +                  q_temp[i][right]+
                                        q_temp[down][left] + q_temp[down][j] + q_temp[down][right];  //这种写法非常好理解
            end
        end
    end
    
                             
    always@(posedge clk) begin
       if(load) begin
           q <= data;
       end
       else begin
           for(i = 0;i<256;i++) begin
                   case(sum[i])    //case的判断要注意:在关注长度的同时也要注意位宽,8个数的相加至少位宽应该为3bit
                        //
                       	//这是我改掉的最后一个bug,
                       	//因为q的变化是受时钟控制的,所以虽然等式两边都是q变量,
                       	//但是之间有一个时钟误差,而如果是q[i] <= q_temp[x][x];q_temp刚开始确实里面的16*16和q没有区别
                       	//但是因为不受时钟控制,所以,内部再任意时刻取值是一个错误的值。
                       	3'b010:q[i] = q[i];  
                        3'b011:q[i] = 1'b1;
                        default:q[i] = 1'b0;
                   endcase
            end  
       end
    end
endmodule

  第二种思路:参考知乎上给出的答案,我觉得我的思维容易直接从输入得到输出,不善于使用中间变量的使用,从而导致时序的混乱。答案中巧妙的借助了二位数组,使得输入输出依据clk的变化。

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 
    
    reg [15:0] q_temp [15:0] ;
    int up,down,left ,right;
    wire [2:0] sum [255:0];
    
    integer i,j;
    
    always@(posedge clk) begin
        if(load)begin
        	for(i = 0;i<16;i++) begin
                for (j = 0;j<16;j++) begin
                    q_temp[i][j] <= data[i*16+j];
            	end
        	end     
        end
        else  begin
            for(i = 0;i < 16;i++) begin
                for(j = 0;j < 16;j++) begin
            		case(sum[16*i + j])  
                        3'b010:q_temp[i][j] = q_temp[i][j];
                        3'b011:q_temp[i][j] = 1'b1;
                        default:q_temp[i][j] = 1'b0;
            		endcase
                end
            end
        end        
    end
            
    always@(*) begin
        for(i = 0;i<16;i++) begin
            for (j = 0;j<16;j++) begin
                up    = (i == 0)? 15:i-1;
                down  = (i == 15)? 0:i+1;
                left  = (j == 0)? 15:j-1;
                right = (j == 15)? 0:j+1;
                sum[16*i + j] = q_temp[up][left] + q_temp[up][j] + q_temp[up][right]+
                                q_temp[i][left] +                  q_temp[i][right]+
                				q_temp[down][left] + q_temp[down][j] + q_temp[down][right];
                
            end
        end
    end
    
    always@(*) begin
		for(i = 0;i<16;i++) begin
        	for (j = 0;j<16;j++) begin
                q[16*i +j] <= q_temp[i][j];
            end
        end  
    end
    
endmodule



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值