jjzjj

【HDLBits 刷题 4】Verilog Language(4)Procedures 和 More Verilog Features 部分

Linest-5 2024-02-26 原文

目录

写在前面

Procedures

Alwaysblock1

Alwaysblock2

Always if

Always if2

Always case

Always case2

Always casez

Always nolatches

More Verilog Features

Conditional

Reduction

Gates100

Vector100r

Popcount255

Adder100i

Bcdadd100


写在前面

本篇博客对 Verilog Language 剩余两个部分的题目写完,首先对题干先读懂是关键,然后思考如何实现并验证,这里采用先对题目解读,也就是要让我们干什么,然后直接给出答案。


Procedures

Alwaysblock1

分别用 assign 语句和 always @(*) 块语句实现与门操作。

module top_module(
    input        a, 
    input        b,
    output wire  out_assign,
    output reg   out_alwaysblock
);

assign out_assign = a & b;

always @(*) begin
	out_alwaysblock = a & b;
end

endmodule

Alwaysblock2

连续赋值(assign x = y;)。不能在 always 块中使用。
过程阻塞赋值:(x = y;)。只能在过程中使用。
过程非阻塞赋值:(x <= y;)。只能在过程中使用。
在组合 always 块中,使用阻塞赋值。
在时序 always 块中,使用非阻塞赋值。

module top_module(
    input        clk,
    input        a,
    input        b,
    output wire  out_assign,
    output reg   out_always_comb,
    output reg   out_always_ff  
);

assign out_assign = a ^ b;

always @(*) begin
	out_always_comb = a ^ b;
end

always @(posedge clk) begin
	out_always_ff <= a ^ b;
end

endmodule

Always if

if 语句通常创建一个 2 对 1 多路复用器,如果条件为 ture,则选择一个输入,如果条件为 false,则选择另一个输入。这等效于使用带有条件运算符的连续赋值:       
assign out = (condition) ? x : y;
构建一个在 a 和 b 之间进行选择的 2 对 1 多路复用器。如果sel_b1和sel_b2都为真,请选择 b。否则,请选择 a。执行相同的操作两次,分别使用赋值语句和过程 if 语句。

module top_module(
    input        a,
    input        b,
    input        sel_b1,
    input        sel_b2,
    output wire  out_assign,
    output reg   out_always   
); 

assign out_assign = (sel_b1 & sel_b2) ? b : a;

always @(*) begin
	if (sel_b1 & sel_b2) begin
		out_always = b;
	end
	else begin
		out_always = a;
	end
end

endmodule

Always if2

学习如何避免产生 latch, 比如在 always 块中所列举的情况没有完全,会出现你没有列举的情况时,那输出会是什么呢?Verilog的答案是:保持输出不变。这种“保持输出不变”的行为意味着需要记住当前状态,从而产生latch。组合逻辑不能保存任何状态。组合电路必须在所有条件下为所有输出分配一个值。这通常意味着始终需要为输出分配 else 子句或默认值。

module top_module (
    input      cpu_overheated,
    output reg shut_off_computer,
    input      arrived,
    input      gas_tank_empty,
    output reg keep_driving  ); //

    always @(*) begin
        if (cpu_overheated) begin
            shut_off_computer = 1;
        end
        else begin
           	shut_off_computer = 0;
        end   
    end

    always @(*) begin
        if (~arrived) begin
            keep_driving = ~gas_tank_empty;	
        end
        else begin
        	keep_driving = 0;
        end
    end

endmodule

Always case

case语句的练习。case 语句以 case 开头,每个“case 项”都以冒号结尾。
每个事例项只能执行一条语句。这意味着,如果需要多个语句,则必须使用begin结束。允许重复(和部分重叠)案例项目。使用第一个匹配的。
在本练习中,创建一个 6 对 1 多路复用器。当 sel 介于 0 和 5 之间时,选择相应的数据输入。否则,输出 0。数据输入和输出均为4位宽。

module top_module ( 
    input      [2:0]   sel, 
    input      [3:0]   data0,
    input      [3:0]   data1,
    input      [3:0]   data2,
    input      [3:0]   data3,
    input      [3:0]   data4,
    input      [3:0]   data5,
    output reg [3:0]   out   
);

    always @(*) begin  
        case(sel)
        	0: out = data0;
        	1: out = data1;
        	2: out = data2;
        	3: out = data3;
        	4: out = data4;
        	5: out = data5;
      default: out = 0;
        endcase
    end

endmodule

Always case2

优先级编码器是一种组合电路,当给定输入位矢量时,输出矢量中第一个1位的位置。例如,给定输入 8'b100 1 0000 的 8 位优先级编码器将输出 3'd4,因为 bit[4] 是第一个高位。构建 4 位优先级编码器。对于此问题,如果输入位均为零,则输出为零。请注意,4 位数字有 16 种可能的组合。

module top_module (
    input      [3:0]  in,
    output reg [1:0]  pos  
);

always @(*) begin
	case(in)
		4'b0000: pos = 0;
		4'b0001: pos = 0;
		4'b0010: pos = 1;
		4'b0100: pos = 2;
		4'b1000: pos = 3;
		4'b0011: pos = 0;
		4'b0110: pos = 1;
		4'b1100: pos = 2;
		4'b0101: pos = 0;
		4'b1010: pos = 1;
		4'b1001: pos = 0;
		4'b0111: pos = 0;
		4'b1110: pos = 1;
		4'b1011: pos = 0;
		4'b1101: pos = 0;
		4'b1111: pos = 0;
	endcase
end

endmodule

Always casez

case 语句就像是按顺序检查每个情况,这是一个很大的组合逻辑函数。请注意,某些输入(例如,4'b1111)将如何匹配多个事例项。选择第一个匹配项(因此 4'b1111 匹配第一个项目,out = 0,但后面的任何一个都不匹配)。还有一个类似的案例,它将x和z视为不在乎。我看不出在casez上使用它有多大意义。数字 ? 是 z 的同义词。所以 2'bz0 与 2'b?0 相同。

module top_module (
    input      [7:0]  in,
    output reg [2:0]  pos  
);

always @(*) begin
	casez(in)
		8'bzzzzzzz1: pos = 0;   //z表示不在乎这个是什么值。只需要满足后面位的情况
		8'bzzzzzz10: pos = 1;
		8'bzzzzz100: pos = 2;
		8'bzzzz1000: pos = 3;
		8'bzzz10000: pos = 4;
		8'bzz100000: pos = 5;
		8'bz1000000: pos = 6;
		8'b10000000: pos = 7;
	endcase
end

endmodule

Always nolatches

在使用case语句时避免产生latch的方法。
为避免产生锁存器,必须在所有可能条件下为所有输出分配一个值。仅仅有一个默认的案例是不够的。必须为所有四种情况下的所有四个输出分配一个值,并在所有默认情况下分配一个值。这可能涉及大量不必要的键入。
解决此问题的一种方法是在case语句之前为输出分配一个“默认值”:
always @(*) begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    case (scancode)
        ... // Set to 1 as necessary.
    endcase
end
这种代码样式可确保在所有可能的情况下为输出分配一个值,除非case语句覆盖赋值。
提醒:逻辑合成器生成一个组合电路,其行为与代码描述的行为等效。硬件不会按顺序“执行”代码行。

module top_module (
    input [15:0]  scancode,
    output reg    left,
    output reg    down,
    output reg    right,
    output reg    up  
); 

always @(*) begin
	up    = 1'b0;
	down  = 1'b0;
	left  = 1'b0;
	right = 1'b0;
	case(scancode)
        16'he075: up    = 1'b1;
        16'he072: down  = 1'b1;
        16'he06b: left  = 1'b1;
        16'he074: right = 1'b1;
        default: begin
        		  up    = 1'b0;
				  down  = 1'b0;
				  left  = 1'b0;
				  right = 1'b0;
        end	
	endcase
end

endmodule

More Verilog Features

Conditional

给定四个无符号数字,找到最小值。无符号数字可以与标准比较运算符(a < b)进行比较。使用条件运算符制作双向最小电路,然后组合其中的几个以创建 4 路最小电路。可能需要一些导线向量作为中间结果。

module top_module (
    input  [7:0]  a, b, c, d,
    output [7:0]  min
);
wire  [7:0]  smaller0;
wire  [7:0]  smaller1;
wire  [7:0]  smaller2;

assign smaller0 = (a > b)? b : a;
assign smaller1 = (c > d)? d : c;
assign smaller2 = (smaller0 > smaller1)? smaller1 : smaller0;
assign min = smaller2;

endmodule

注:也可以设计为流水线的形式,流水线的设计方法可以使系统的运行速率提高。

Reduction

奇偶校验通常用作通过不完美通道传输数据时检测错误的简单方法。创建一个电路,该电路将计算 8 位字节的奇偶校验位(这将向该字节添加第 9 位)。将使用“偶数”奇偶校验,奇偶校验位只是所有8个数据位的XOR。

一个简单的连续位做异或运算。

module top_module (
    input [7:0]  in,
    output       parity
); 

assign parity = ^in;

endmodule

Gates100

在[99:0]中构建具有100个输入的组合电路。
有 3 个输出:

  • out_and:输出100输入与门 &。
  • out_or:100 输入 OR 门 | 的输出。
  • out_xor:100 输入异或门 ^ 的输出。
module top_module( 
    input  [99:0]  in,
    output         out_and,
    output         out_or,
    output         out_xor 
);

assign out_and = & in;
assign out_or = | in;
assign out_xor = ^ in;

endmodule

Vector100r

给定一个 100 位输入向量 [99:0],反转其位排序。

module top_module( 
    input  [99:0]  in,
    output [99:0]  out
);
	integer i;
	always @(*) begin
		for (i=0;i<100;i=i+1) begin
			out[i] = in[99-i];
		end		
	end
endmodule

Popcount255

对输入位宽为255的数计算其各个位为 1 的个数并输出

module top_module( 
    input  [254:0]  in,
    output [7:0]    out 
);

reg [7:0] cnt;
integer i;
always @(*) begin
	cnt = 'd0;
	for (i=0;i<255;i=i+1) begin
		cnt = (in[i])? (cnt+1'b1):cnt;
	end
end
assign out = cnt;

endmodule

Adder100i

通过实例化 100 个全加器来创建一个 100 位二进制行波进位加法器。加法器将两个 100 位数字和一个随身数字相加,以产生 100 位总和并执行。实际实例化全加器,还要从行波进位加法器中的每个全加器输出执行。cout[99]是最后一个全加器的最终执行。

注意对第一个全加器计算时的特殊情况。

module top_module( 
    input  [99:0]  a, b,
    input          cin,
    output [99:0]  cout,
    output [99:0]  sum 
);
	genvar i;
    generate
        for(i=0;i<100;i=i+1) begin:adder
            if(i==0)
                assign{cout[0],sum[0]}=a[0]+b[0]+cin;
            else
                assign{cout[i],sum[i]}=a[i]+b[i]+cout[i-1];
        end           
    endgenerate
    
endmodule

Bcdadd100

以一个四位的全加器模块,计算两个输入数据的相加,其位宽为400。

在这里吐槽一下 HDLBits 自带的编译器有点神经质,有些没必要的细节过度把控,而有些带有技巧性的语法又不支持...

module top_module( 
    input  [399:0]  a,b,
    input           cin,
    output          cout,
    output [399:0]  sum 
);

wire [99:0]  cin_cnt;
genvar i;
generate
	for (i=0;i<100;i=i+1) begin:test
		if (i == 0) begin
			bcd_fadd bcd_fadd_inst(a[3:0],b[3:0],cin,cin_cnt[0],sum[3:0]);
		end
		else begin
			bcd_fadd bcd_fadd_inst(a[4*(i+1)-1:4*i],b[4*(i+1)-1:4*i],cin_cnt[i-1],cin_cnt[i],sum[4*(i+1)-1:4*i]);
		end
		
	end
	assign cout = cin_cnt[99];
endgenerate

endmodule

有关【HDLBits 刷题 4】Verilog Language(4)Procedures 和 More Verilog Features 部分的更多相关文章

  1. ruby - 如何使用部分字符串搜索数组并返回索引? - 2

    我想使用部分字符串搜索数组,然后获取找到该字符串的索引。例如:a=["Thisisline1","Wehaveline2here","andfinallyline3","potato"]a.index("potato")#thisreturns3a.index("Wehave")#thisreturnsnil使用a.grep将返回完整的字符串,使用a.any?将返回正确的true/false语句,但都不会返回匹配的索引找到了,或者至少我不知道该怎么做。我正在编写一段代码,该代码读取文件、查找特定header,然后返回该header的索引,以便它可以将其用作future搜索的偏移量。如果

  2. ruby-on-rails - 如何将数据传递给部分? - 2

    K伙计们,所以我创建了这个赞成/反对的投票脚本(基本上就像stackoverflow上的那个),我试图向其中添加一些Ajax,这样页面就不会在您每次投票时都重新加载。我有两个Controller,一个叫grinder,一个叫votes。(磨床基本都是帖子)所以这是所有研磨机的索引(看起来像这样)这是该页面的代码。Listinggrinders"grinders/grinders")%>这就是我在views/grinders/_grinders.erb中的内容true)do|u|%>grinder.id%>"up"%>'create')%>true)do|d|%>grinder.id%>

  3. ruby-on-rails - 将 restclient 与多部分帖子一起使用 - 2

    我将restclient用于多部分表单,以将数据发送到restfulweb服务(它是Panda视频编码服务)。不过,诀窍在于我传递给restclient(Technoweenie分支)的文件来自用户提交的我自己的表单。那么,让我们来看看这个。用户将文件发布到我的Rails应用程序。在我的Controller中,它从params[:file]接收文件。然后我想使用RestClient将params[:file]传递给Panda。我在Panda服务器上遇到的错误如下。我注意到堆栈跟踪中的文件参数也在一个字符串中(我假设Panda将其转换为字符串以获得更好的堆栈跟踪)。~Startedreq

  4. ruby-on-rails - 独立测试 Rails 部分 View - 2

    我在标准rails2.1项目中使用Test/Unit。我希望能够独立于任何特定的Controller/操作来测试分部View。好像ZenTest'sTest::Rails::ViewTestCase会有所帮助,但我无法让它工作,与view_testhttp://www.continuousthinking.com/tags/view_test类似Google出现的大部分内容似乎都已经过时了,所以我猜它并不真正适用于Rails2.1非常感谢任何帮助。谢谢,罗兰 最佳答案 我们正在使用RSpec在我们的Rails2.1项目中,我们可以做

  5. ruby - 如何在 ruby​​ 中实现 curry(部分函数) - 2

    我需要一些在ruby​​(1.8.6或1.8.7而不是1.9)中实现curry函数的示例。 最佳答案 下面是如何用block而不是方法来柯里化(Currying):defcurry(&block)arity=(block.arity>=0)?block.arity:-(block.arity+1)#returnanimmediatevalueiftheblockhasonereturnblock[]ifarity==0#otherwise,curryitargumentbyargumentargs=[]innermost=lambd

  6. ruby-on-rails - Rails 4 通过渲染部分传递多个变量 - 2

    这个问题已经被问过很多次了,但我无法让它工作。我想像这样将多个变量传递给我的部分...这是部分material_fields.html.erb中的一行,我希望f.select预先填充Yes选项或“true”值。(有些情况下我希望它是假的)f可用并且有效,而feed不可用......我不知道为什么这不起作用。我在select语句之外尝试了,但它仍然不起作用。在这两种情况下,我都得到未定义的局部变量或方法“feed”。有人知道我的语法有什么问题吗? 最佳答案 我想通了是什么问题。我有后来我在同一个View中显然,当从一个文件渲染相同的部

  7. ruby-on-rails - 是否可以在部分中只放置一个 rails 表单元素? - 2

    我的应用有一个选择框供用户选择“地点”。如您所料,此选择框位于一个表单中。我还在页面上的某处执行了一个操作,该操作通过AJAX创建了一个新场所。创建新field后,我想更新field选择框以反射(reflect)这一点。我的解决方案是将选择框放在局部中,并从Controller中的创建操作中呈现局部。'venue/venue_select_box'%>局部看起来像这样:'Selectavenue'%>其中f是表单引用:问题是f在部分中未定义,所以我得到一个错误。一种解决方案是包括整个表格,但我觉得没有必要这样做,因为我没有更新整个表格。关于如何解决这个问题有什么想法吗?

  8. ruby-on-rails - 在这部分代码中设置 klass = self 的动机是什么 - 2

    我正在查看讨论中的一些代码并偶然发现了这个并且想知道为什么klass=self.据我所知,他们是比我更好的ruby​​开发人员,这一定是有充分理由的。他们为什么不调用self.remove_from_cache!(message["key"],false)?该block是否正在创建一个新范围,其中self引用MessageBus类?是否有其他示例说明您需要在Ruby中创建此类构造,或者这是主要示例?如果MessageBus.subscribe是MessageBus的一个实例(比如说m_bus.subscribe)会自己引用block中的m_bus吗?ensure_class_liste

  9. ruby-on-rails - 缓存特定的部分 rails 3.0.x - 2

    我有一个主页,整个页面都呈现了一些部分。它也有sessionheader(登录)。部分包含已分页的书籍集。现在我想缓存这个部分,因为它每周更新一次。问题1:如何缓存特定的部分(不命中分贝)?问题2:更新时如何删除(过期)缓存内容那个书本模型? 最佳答案 您正在寻找fragmentcaching这里,发生在View层。片段缓存和存储内容的过期非常容易做到。您有一个图书list,假设您的View看起来有点像这样:要为这一位启用缓存,只需将其包装在cache中:当然,这不会为缓存命名或对它做任何特别的事情...虽然Rails会自动为这个缓

  10. ruby-on-rails - Ruby On Rails - 重用错误消息部分 View - 2

    问题我试图在我的View中重用错误消息block。下面是positions/_error_messages.html.erb中写的blockTheformcontains.*问题是我必须在每个模型中创建类似的部分View,这有点像用不同的对象重复相同的代码,即@user、@client等。补救措施我在共享文件夹shared/_error_messages.html.erb中创建了一个erb并编写了以下代码。Theformcontains.*然后在查看文件中。positions/new.html.erb我写了下面的代码这意味着现在我可以在所有创建和更新操作中使用相同的代码。我想知道,这样

随机推荐