成熟的打火机 · 9款必备下载神器推荐,提升你的下载效率!_办 ...· 4 周前 · |
年轻有为的茄子 · win10自带的远程桌面无法区分、记住同IP ...· 11 月前 · |
深沉的菠菜 · javascript中的标签属性 ...· 1 年前 · |
含蓄的罐头 · 用于PHP托管的AWS CloudFront· 1 年前 · |
当你把代码写完然后编译之后,会给出相应的提示:
见下图即可。
意思:创建一个没有输入只有一个输出的电路,且输出总是为1。
解题代码如下:
module top_module( output one ); // Insert your code here assign one = 1'b1; endmodule
1.2Output Zero
网站相关介绍也在第一节介绍之后将主要进行问题的翻译与解答。
1.2.1题目与解答
意思:创建一个没有输入,一个输出且输出为0的电路。
代码如下:module top_module( output zero );// Module body starts after semicolon assign zero=1'b0; endmodule
二 、Verilog Language
2.1 Basics
2.1.1 Simple wire
题目:创建一个模块,将输入与输出像一根线一样连接起来。
代码如下:module top_module( input in, output out ); assign out = in ; endmodule
2.1.2 Four wires
题目:创建一个3输入4输出的模块,用线实现如图所示的连接。
代码如下:module top_module( input a,b,c, output w,x,y,z ); assign w=a,x=b,y=b,z=c; endmodule
2.1.3 Inverter
题目:创建一个实现非门的模块。
代码如下:module top_module( input in, output out ); assign out = ~in; endmodule
2.1.4 AND gate
题目:创建一个实现与门的模块。
代码如下:module top_module( input a, input b, output out ); assign out = a & b; endmodule
2.1.5 NOR gate
题目:创建一个实现或非门的模块。
代码如下:module top_module( input a, input b, output out ); assign out = ~(a|b); endmodule
2.1.6 XNOR gate
题目:创建一个实现同或门的模块。
代码如下:module top_module( input a, input b, output out ); assign out = ~(a^b); endmodule
2.1.7 Declaring wires
这个小节出现了线网数据类型wire,当内部结构越来越复杂时,一个模块的输入输出并非直接连接时,声明一个线网数据类型的变量(相当于中间变量)。
题目:实现如图所示的电路。创建两条中间线网(取任何你想取的名字)去连接与门和或门,
代码如下:module top_module( input a, input b, input c, input d, output out, output out_n ); //这两个线网类型的变量,在没有器件连接时为高阻态Z wire temp1,temp2; assign temp1 = a&b; assign temp2 = c&d; assign out = temp1|temp2; assign out_n = ~out; endmodule
2.1.8 7458 chip
代码如下:module top_module ( input p1a, p1b, p1c, p1d, p1e, p1f, output p1y, input p2a, p2b, p2c, p2d, output p2y ); assign p1y = (p1a&p1c&p1b) | (p1d&p1f&p1e); assign p2y = (p2a&p2b) | (p2c&p2d); endmodule
2.2 Vectors
2.2.1 Vectors
可以一次性初始化许多条线,注意维度应该在变量名字的前面。
规则:type [upper:lower] vector_name;
eg. wire [99:0] my_vector;
代码如下:module top_module ( input wire [2:0] vec, output wire [2:0] outv, output wire o2, output wire o1, output wire o0 ); // Module body starts after module declaration assign outv[2:0]= vec[2:0]; assign o0 = vec[0],o1 = vec[1],o2 = vec[2]; endmodule
2.2.2 Vectors in more detail
题目:构建一个组合电路,将输入的16位分割成低8位和高8位。
代码如下:module top_module( input wire [15:0] in, output wire [7:0] out_hi, output wire [7:0] out_lo ); assign out_hi[7:0] = in[15:8]; assign out_lo[7:0] = in[7:0]; endmodule
2.2.3 Vector part select
题目:就是把四个字节的容器里的每个字节调换位置。
代码如下:module top_module( input [31:0] in, output [31:0] out ); assign out[31:24] = in[7:0]; assign out[23:16] = in[15:8]; assign out[15:8] = in[23:16]; assign out[7:0] = in[31:24]; endmodule
2.2.4 Bitwise operators
题目:如图所示,注out_not[5:0]]高3位是b。
代码如下:module top_module( input [2:0] a, input [2:0] b, output [2:0] out_or_bitwise, output out_or_logical, output [5:0] out_not assign out_or_bitwise[2:0] = a[2:0]|b[2:0]; //a[2:0]和b[2:0]可以直接写成a和b assign out_or_logical = a[2:0]||b[2:0]; //assign out_not[5:3] = ~b[2:0]; 这种方法也可以 //assign out_not[2:0] = ~a[2:0]; assign out_not[5:0] = {{~b[2:0]},{~a[2:0]}}; endmodule
2.2.5 Four-input gates
代码如下:module top_module( input [3:0] in, output out_and, output out_or, output out_xor assign out_and = ∈ //每一位相与 assign out_or = |in; assign out_xor = ^in; endmodule
2.2.6 Vector concatenation operator
拼接符{}
用法:{3’b111, 3’b000} => 6’b111000
{1’b1, 1’b0, 3’b101} => 5’b10101
{4’ha, 4’d10} => 8’b10101010题目:如图所示。
代码如下:module top_module ( input [4:0] a, b, c, d, e, f, output [7:0] w, x, y, z ); assign {w,x,y,z} = {a,b,c,d,e,f,{2'b11}}; endmodule
2.2.7 Vector reversal 1
题目:将输入的每个位翻转。
代码如下:
方法一:module top_module( input [7:0] in, output [7:0] out always @(*) begin //组合逻辑电路 for (integer i=0; i<8; i++) out[i] = in[8-i-1]; endmodule
module top_module( input [7:0] in, output [7:0] out assign out[7:0]={ in[0],in[1],in[2],in[3], in[4],in[5],in[6],in[7] }; endmodule
2.2.8 Replication operator
题目:将8位的一个数据扩展成32位的数据,要求复制符号位来增加数据的位数
代码如下:module top_module ( input [7:0] in, output [31:0] out ); assign out[31:0] ={{24{in[7]}} ,{in[7:0]}}; endmodule
2.2.9 More replication
题目:(XNOR 为同或的意思)将图示数据全部同或,再并入到一个25位的容器里。
代码如下:module top_module ( input a, b, c, d, e, output [24:0] out );// assign out = { {~{5{a}}^{a,b,c,d,e}}, {~{5{b}}^{a,b,c,d,e}}, {~{5{c}}^{a,b,c,d,e}}, {~{5{d}}^{a,b,c,d,e}}, {~{5{e}}^{a,b,c,d,e}} }; endmodule
2.3 Modules:Hierarchy
本小节就进入了模块化设计,也就是模块的例化。例化的方式有两种,按照位置例化或名字例化。为了代码的可读性一般使用名字例化。具体如何使用看下面的练习。
2.3.1 Modules
题目:mod_a模块已经给出,把他按上图所示,与顶层模块进行例化。
代码如下:
一、按名字的方式例化。(更加推荐)module top_module ( input a, input b, output out ); mod_a temp_mod( //这里的temp_mod模块名字随便取,主要是为了区分多个不同的例化。 .in1(a), //in1是mod_a模块的输入,a是top_module的输入 .in2(b), .out(out) //这种例化的方式可以清晰的看到与引脚之间的连接。 endmodule
二、按位置的方式例化。
module top_module ( input a, input b, output out ); mod_a temp_mod(a,b,out); //这种例化的方式看不出引脚之间的连接,但是他更加简便 endmodule
2.3.2 Connecting ports by position
题目:mod_a 模块已经给出,要求使用位置例化
代码如下:module top_module ( input a, input b, input c, input d, output out1, output out2 mod_a temp_mod (out1,out2,a,b,c,d); endmodule
2.3.3 Connecting ports by name
题目:mod_a 模块已经给出,要求使用名字例化
代码如下:module top_module ( input a, input b, input c, input d, output out1, output out2 mod_a temp_mod .in1(a), .in2(b), .in3(c), .in4(d), .out1(out1), .out2(out2) ); //注意括号内的是顶层模块引脚 endmodule
2.3.4 Three modules
题目:my_dff 模块已经给出,该模块具有两个输入和一个输出(它实现了 D 触发器)。将它例化出三个模块,然后将它们连接在一起,形成一个3位的移位寄存器。clk 端口需要连接到所有例化出来的模块。my_diff 模块如图红线已经框出
代码如下:module top_module ( input clk, input d, output q ); wire temp_wire_left; //线网类型数据,作为第一,二个模块连接的线。 wire temp_wire_right;//线网类型数据,作为第二,三个模块连接的线。 my_dff mod_1 //例化出模块1 .clk(clk), .d(d), .q(temp_wire_left) my_dff mod_2 //例化出模块2 .clk(clk), .d(temp_wire_left), .q(temp_wire_right) my_dff mod_3 //例化出模块3 .clk(clk), .d(temp_wire_right), .q(q) endmodule
2.3.5 Module and vectors
题目:提供的模块如图所示。
代码如下(详解看注释):module top_module ( input clk, input [7:0] d, input [1:0] sel, output [7:0] q //module my_dff8 ( input clk, input [7:0] d, output [7:0] q ); //线网类型数据,作为第一,二个模块连接的线。 wire [7:0] temp_wire_left; //线网类型数据,作为第二,三个模块连接的线。 wire [7:0] temp_wire_right; //线网类型数据,作为第三个模块输出。 wire [7:0] temp_mod_out; //下面是三个例化 my_dff8 mod_1 .clk(clk), .d(d), .q(temp_wire_left) my_dff8 mod_2 .clk(clk), .d(temp_wire_left), .q(temp_wire_right) my_dff8 mod_3 .clk(clk), .d(temp_wire_right), .q(temp_mod_out) //这里是一个数据选择器 always @(*) begin case (sel) //组合逻辑所以阻塞赋值(=),注意不要用连续赋值关键词assign 2'b00: q = d; 2'b01: q = temp_wire_left; 2'b10: q = temp_wire_right; 2'b11: q = temp_mod_out; default:; endcase endmodule
注意阻塞赋值与非阻塞赋值的不同(具体可以去看仿真的波形):
(1) 阻塞赋值(=) : 写在前面的语句先执行,写在后面的语句后执行,也就是说,它是顺序执行的,一般用于组合逻辑电路。
(2) 非阻塞赋值(<=) :写在前面的语句与后面的语句同时执行,也就是说,它是并行执行的,跟书写顺序没有关系,一般用于时序逻辑电路。
2.3.6 Adder 1
题目:提供了一个16位加法器模块名为add16,创建一个32位的加法器。
代码如下(详解看注释):module top_module( input [31:0] a, input [31:0] b, output [31:0] sum //题目中摆放在上面模块的sum输出连接的线 wire [15:0] sum_up_out; //题目中摆放在上面模块的cout输出连接的线 wire [15:0] cout_up_out; //题目中摆放在下面模块的cout输出连接的线 wire [15:0] sum_down_out; //实例化 add16 add16_up .a(a[15:0]), .b(b[15:0]), .cin(0), .sum(sum_up_out), .cout(cout_up_out) add16 add16_down .a(a[31:16]), .b(b[31:16]), .cin(cout_up_out), .sum(sum_down_out), //输出没有连接则直接不写 .cout() //注意题目中摆放再下面模块的sum输出是高位 assign sum = {sum_down_out,sum_up_out}; endmodule
2.3.7 Adder 2
题目:这里要求我们自己写出1位全加器的模块,16为加法器就是通过例化这个1位全加器得来,因此不写就会报错。注意:不要求我们自己写出16位加法器模块,题目已经提供。
代码如下:module top_module ( input [31:0] a, input [31:0] b, output [31:0] sum //这部分与2.3.6小结一样 wire [15:0] mod_2_sum,mod_1_sum; wire [15:0] mod_1_cout; add16 mod_1 .a(a[15:0]), .b(b[15:0]), .cin(0), .cout(mod_1_cout), .sum(mod_1_sum) add16 mod_2 .a(a[31:16]), .b(b[31:16]), .cin(mod_1_cout), .cout(), .sum(mod_2_sum) assign sum = {mod_2_sum,mod_1_sum}; endmodule module add1 ( input a, input b, input cin, output sum, output cout ); //根据真值表和卡诺图得来,过程见下图。 assign sum = (~cin&a&(~b))|(cin&(~a)&(~b)) |(~cin&(~a)&b)|(cin&a&b); assign cout =(a&b)|(cin&b)|(cin&a); endmodule
真值表与卡诺图如下:
2.3.8 Carry-select adder
前几个小节练习的进位加法器,只有前一个加法器加完之后才能进行后续的相加,这样使得数据相加很慢,可以用进位选择加法器来加快加法运算的速度。
题目:已经提供了模块add16 模块。数据选择器并不是要算出一位选择一位,而是把高位全部算好了,低位的进位一算出,则数据相加的结果就直接出来了。
代码如下:module top_module( input [31:0] a, input [31:0] b, output [31:0] sum wire [15:0] mod_1_cout; wire [15:0] mod_up_sum,mod_mid_sum,mod_down_sum; wire [15:0] mod_mid_down_sum; add16 mod_up .a(a[15:0]), .b(b[15:0]), .cin(0), .cout(mod_1_cout), .sum(mod_up_sum) add16 mod_mid .a(a[31:16]), .b(b[31:16]), .cin(0), .cout(), .sum(mod_mid_sum) add16 mod_down .a(a[31:16]), .b(b[31:16]), .cin(1), .cout(), .sum(mod_down_sum) always @(*) begin case(mod_1_cout) 1'b0: mod_mid_down_sum = mod_mid_sum; 1'b1: mod_mid_down_sum = mod_down_sum; default:; endcase; assign sum={mod_mid_down_sum,mod_up_sum}; endmodule
2.3.9 Adder-subtractor
加/减法器,当sub为0时为为加法器,为1时为减法器。这个也比较好理解,二进制的减法就是加上补码(一个数的补码就是,取反再低位加1)
一个数异或0就是本身,异或1就是取反。
代码如下:module top_module( input [31:0] a, input [31:0] b, input sub, output [31:0] sum wire [15:0] mod_1_cout; add16 mod_up .a(a[15:0]), //一个16位的数和一个1位的数无法进行异或,因此用拼接符增加数据位数到16位 .b(b[15:0]^{16{sub}}), .cin(sub), .cout(mod_1_cout), .sum(sum[15:0]) add16 mod_mid .a(a[31:16]), .b(b[31:16]^{16{sub}}), .cin(mod_1_cout), .cout(), .sum(sum[31:16]) endmodule
2.4 Procedures
2.4.1 Always blocks(combination)
组合逻辑always块是等价于assign的,但是语法上有不同。
注意:
always 是过程赋值语句,数据类型一定要是 寄存器(reg)类型。
assign 是连续赋值语句,数据类型一定要是线网(wire)类型。
代码如下: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; endmodule
2.4.2 Always blocks(clocked)
组合逻辑中,使用阻塞赋值,时序逻辑中使用非阻塞赋值。
题目:用三种当时构建异或门。
代码如下: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; always @(posedge clk) begin out_always_ff <= a^b; endmodule
2.4.3 If statement
终于来到了我们熟悉的if else了0.0!!!!安排。
代码如下: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; else begin out_always = a; endmodule
2.4.4 If statement latches
(1)在组合逻辑中,我们要防止锁存器的产生。因为我们组合逻辑不花里胡哨输入变,输出直接跟着变,不保存状态。那怎么避免呢,就是把所有情况都写出来,if else 还有 case default 成双成对出现。
(2)在时序逻辑中,即使不把所有情况都列出,也不会产生锁存器。代码如下:
module top_module ( input cpu_overheated, output reg shut_off_computer, input arrived, input gas_tank_empty, output reg keep_driving ); // always @(*) begin //cpu过热 if (cpu_overheated) shut_off_computer = 1; shut_off_computer = 0; always @(*) begin if (~arrived) //还没到达目的地,油箱没空就保持行驶 keep_driving = ~gas_tank_empty; //到了就不行驶了 keep_driving = 0; endmodule
2.4.5 Case statement
case 很熟悉了,不多说,注意case语法即可。
代码如下: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 // This is a combinational circuit case(sel) //注意这里不需要begin 3'b000: out=data0; 3'b001: out=data1; 3'b010: out=data2; 3'b011: out=data3; 3'b100: out=data4; 3'b101: out=data5; default:out=0; endcase endmodule
2.4.6 Priority encoder
优先编码器,使用case语句即可。
代码如下:module top_module ( input [3:0] in, output reg [1:0] pos ); always@(*) begin case (in) 4'b0000:pos=2'b00; 4'b0001:pos=2'b00; 4'b0010:pos=2'b01; 4'b0011:pos=2'b00; 4'b0100:pos=2'b10; 4'b0101:pos=2'b00; 4'b0110:pos=2'b01; 4'b0111:pos=2'b00; 4'b1000:pos=2'b11; 4'b1001:pos=2'b00; 4'b1010:pos=2'b01; 4'b1011:pos=2'b00; 4'b1100:pos=2'b10; 4'b1101:pos=2'b00; 4'b1110:pos=2'b01; 4'b1111:pos=2'b00; default:pos=2'b00; endcase endmodule
2.4.7 Priority encoder with casez
(1)假如case语句中想要使用z来表示,不在乎这一位数据是什么的话,就要使用casez语句。
(2)casex也是类似的使用,把z换成x即可,在casex语句下可以使用z,但是casez下不可以使用x**
(3)通常情况下用casez比用casex更好一些,因为×的存在可能会导致仿真出现令人误解和混乱的结果。
(4)在casex和 casez声明的标号中用?来代替z比较好,因为这样做比较清楚,是一个无关项,而不是一个高阻项。题目:8位优先编码器。
代码如下:
方法一、casezmodule top_module ( input [7:0] in, output reg [2:0] pos ); always @(*) begin casez(in) 8'b0000_0000:pos=3'd0; 8'bzzzz_zzz1:pos=3'd0; 8'bzzzz_zz10:pos=3'd1; 8'bzzzz_z100:pos=3'd2; 8'bzzzz_1000:pos=3'd3; 8'bzzz1_0000:pos=3'd4; 8'bzz10_0000:pos=3'd5; 8'bz100_0000:pos=3'd6; 8'b1000_0000:pos=3'd7; default:pos=0; endcase endmodule
方法二、casex
module top_module ( input [7:0] in, output reg [2:0] pos ); always @(*) begin casex(in) //使用casex 8'b0000_0000:pos=3'd0; 8'bzzzz_zzz1:pos=3'd0; 8'bzzzz_zz10:pos=3'd1; 8'bzzzz_z100:pos=3'd2; 8'bzzzz_1000:pos=3'd3; 8'bzzz1_0000:pos=3'd4; 8'bzz10_0000:pos=3'd5; 8'bz100_0000:pos=3'd6; 8'b1000_0000:pos=3'd7; default:pos=0; endcase //都是endcase endmodule
方法三、用问号来替代z或x
module top_module ( input [7:0] in, output reg [2:0] pos ); always @(*) begin casez(in) 8'b0000_0000:pos=3'd0; 8'b????_???1:pos=3'd0; 8'b????_??10:pos=3'd1; 8'b????_?100:pos=3'd2; 8'b????_1000:pos=3'd3; 8'b???1_0000:pos=3'd4; 8'b??10_0000:pos=3'd5; 8'b?100_0000:pos=3'd6; 8'b1000_0000:pos=3'd7; default:pos=0; endcase endmodule
2.4.8 Avoiding laches
还是那句话,case语句中default不能少!!!
代码如下: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'he06b:left = 1'b1; 16'he072:down = 1'b1; 16'he074:right= 1'b1; 16'he075:up = 1'b1; default:begin up = 1'b0;down = 1'b0; left = 1'b0;right = 1'b0; endcase endmodule
2.5 More Verilog Features
2.5.1 Conditional ternary operator
题目:使用条件运算符从四个无符号数据中找到最小的数据。
代码如下:module top_module ( input [7:0] a, b, c, d, output [7:0] min);// wire [7:0] temp_min1,temp_min2; assign temp_min1=(a<b)?a:b; assign temp_min2=(c<d)?c:d; assign min =(temp_min1<temp_min2)?temp_min1:temp_min2; endmodule
2.5.2 Reduction operators
使用方式如下图所示:
题目:用精简算子,给一个8位的数据,做一个偶校验。
代码如下:module top_module ( input [7:0] in, output parity); assign parity = ^in; endmodule
2.5.3 Reduction:Even wider gates
代码如下:module top_module( input [99:0] in, output out_and, output out_or, output out_xor assign out_and=∈ assign out_or =|in; assign out_xor=^in; endmodule
2.5.4 Vector 100r
题目:翻转一下所给数据位的顺序。
代码如下:module top_module( input [99:0] in, output [99:0] out always @(*) begin for(int i=0;i<100;i=i+1) begin out[i] =in[99-i]; endmodule
2.5.5 Combination for-loop:255-bit population count
题目:统计一个255位的数据,有多少个位是1。
代码如下:module top_module( input [254:0] in, output [7:0] out ); always @ ( * ) begin //初始化 out=0; for(int i=0;i<255;i=i+1) begin if(in[i]==1'b1)begin out=out+1; out=out; endmodule
2.5.6 Generate for-loop:100-bit binary adder 2
这里使用了generate 关键词注意语法,具体看代码注释。
题目:创建一个100位的二进制加法器
代码如下:module top_module( input [99:0] a, b, input cin, output [99:0] cout, output [99:0] sum ); //generate 用于循环例化,用法如下 generate //generate 专用数据类型 //!!!!!这里不可以给i赋值,如i=0 是错误的 genvar i ; for(i=0;i<100;i=i+1) begin:add_100 //整个循环例化出整体模块的名称 if(i==0) begin //第一个例化的cin用于接顶层模块cin adder_full add100( .a(a[i]), .b(b[i]), .cin(cin), .cout(cout[i]), .sum(sum[i]) else begin adder_full add100( .a(a[i]), .b(b[i]), .cin(cout[i-1]), .cout(cout[i]), .sum(sum[i]) endgenerate endmodule //全加器模块的设计 module adder_full( input a,b,cin, output cout,sum //用真值表和卡诺图做的 //方法一 //assign sum = (~cin&a&(~b))|(cin&(~a)&(~b)) // |(~cin&(~a)&b)|(cin&a&b); //assign cout =(a&b)|(cin&b)|(cin&a); //方法二 //更加简便 assign {cout,sum}=a+b+cin; endmodule
2.5.7 Generate for-loop:100-bit BCD adder
BCD加法器就是用4个二进制表示一个十进制数的加法器。
代码如下:module top_module( input [399:0] a, b, input cin, output cout, output [399:0] sum ); wire [99:0] cout_temp; generate genvar i; for(i=0;i<100;i++)begin:add10 if(i==0) begin bcd_fadd add(a[4*i+3:4*i],b[4*i+3:4*i],cin,cout_temp[i],sum[4*i+3:4*i]); else begin bcd_fadd add(a[4*i+3:4*i],b[4*i+3:4*i],cout_temp[i-1],cout_temp[i],sum[4*i+3:4*i]); endgenerate assign cout = cout_temp[99]; endmodule
三、Circuits
3.1 Combinational Logic
3.1.1Basic Gates
3.1.1.1 Wire
代码如下:
module top_module ( input in, output out); assign out = in; endmodule
3.1.1.2 GND
代码如下:
module top_module ( output out); assign out=1'b0; endmodule
3.1.1.3 NOR
代码如下:
module top_module ( input in1, input in2, output out); assign out = ~( in1|in2 ); endmodule
3.1.1.4 Another gate
代码如下:module top_module ( input in1, input in2, output out); assign out = in1 & (~in2); endmodule
3.1.1.5 Two gate
module top_module ( input in1, input in2, input in3, output out); wire temp_one; assign temp_one=~(in1^in2); assign out = temp_one ^ in3; endmodule
3.1.1.6 More logic gates
代码如下:
module top_module( input a, b, output out_and, output out_or, output out_xor, output out_nand, output out_nor, output out_xnor, output out_anotb assign out_and = a&b; assign out_or = a|b; assign out_xor = a^b; //异或 assign out_nand = ~(a&b); assign out_nor = ~(a|b); assign out_xnor = ~(a^b); //同或 assign out_anotb = a&~b; endmodule
3.1.1.7 7420 chip
代码如下:module top_module ( input p1a, p1b, p1c, p1d, output p1y, input p2a, p2b, p2c, p2d, output p2y ); assign p1y = ~(p1a & p1b & p1c & p1d); assign p2y = ~(p2a & p2b & p2c & p2d); endmodule
3.1.1.8 Truth tables
真值表如图所示:
利用真值表画卡诺图即可。
代码如下:module top_module( input x3, input x2, input x1, // three inputs output f // one output assign f= ~x3&x2 | x3&x1; endmodule
3.1.1.9Two-bit equality
代码如下:module top_module ( input [1:0] A, input [1:0] B, output z ); assign z =(A==B)?1:0; endmodule
3.1.1.10 Simple circut A
module top_module (input x, input y, output z); assign z = (x^y) & x; endmodule
3.1.1.11 Simple circut B
列出真值表即可得出答案。
代码如下:module top_module ( input x, input y, output z ); assign z=~(x^y); endmodule
3.1.1.12 Combine circuts A and B
注意他这里的AB模块没有提供。
代码如下:module top_module (input x, input y, output z); wire temp1,temp2,temp3,temp4; wire temp_12,temp_34; A IA1(x,y,temp1); B IB1(x,y,temp2); A IA2(x,y,temp3); B IB2(x,y,temp4); assign temp_12 = temp1 | temp2; assign temp_34 = temp3 & temp4; assign z = temp_12^temp_34; endmodule module A (input x, input y, output z); assign z = (x^y) & x; endmodule module B ( input x, input y, output z ); assign z=~(x^y); endmodule
3.1.1.13 Ring or vibrate
题目:如果ring=1的情况下,要么闹铃要么震动,但是两者不会同时发生。当vibrate_mode=1 时,震动否则闹铃。
代码如下:module top_module ( input ring, input vibrate_mode, output ringer, // Make sound output motor // Vibrate assign motor = ring & vibrate_mode; assign ringer= ring & ~vibrate_mode ; endmodule
3.1.1.14 Thermostat
列出真值表,如下:
卡诺图如下:
代码如下:module top_module ( input too_cold, input too_hot, input mode, input fan_on, output heater, output aircon, output fan assign heater = mode & too_cold; assign aircon = ~mode & too_hot; assign fan =( ~mode&too_hot )|fan_on|(mode&too_cold); endmodule
3.1.1.15 3-bit population count
题目:计一个Vector里1的个数。
代码如下:module top_module( input [2:0] in, output [1:0] out ); reg [1:0] temp; always @(*) begin temp=0; for(int i=0;i<3;i=i+1) begin if(in[i]==1'b1)begin temp=temp+1; else begin temp=temp; out=temp; endmodule
3.1.1.16 Gates and vexctors
直接见代码:
module top_module( input [3:0] in, output [2:0] out_both, output [3:1] out_any, output [3:0] out_different ); assign out_both =in[2:0]&in[3:1]; //与左边的位进行与运算 assign out_any =in[3:1]|in[2:0]; //与右边的位进行或运算 assign out_different =in ^{in[0],in[3:1]};//与左边的位进行异或 endmodule
3.1.1.17 Even longer vectors
与上一题一样,注意使用verctor的移位即可。
代码如下:module top_module( input [99:0] in, output [98:0] out_both, output [99:1] out_any, output [99:0] out_different ); assign out_both =in[98:0]&in[99:1]; //与左边的位进行与运算 assign out_any =in[99:1]|in[98:0]; //与右边的位进行或运算 assign out_different =in ^{in[0],in[99:1]};//与左边的位进行异或 endmodule
3.1.2 Multiplexer
3.1.2.1 2-to-1 multiplexer
代码如下:module top_module( input a, b, sel, output out ); assign out = (sel==0)? a:b ; endmodule
3.1.2.2 2-to-1 bus multiplexer
代码如下:module top_module( input [99:0] a, b, input sel, output [99:0] out ); assign out = (sel==0)? a:b ; endmodule
3.1.2.3 9-to-1 multiplexer
代码如下:module top_module( input [15:0] a, b, c, d, e, f, g, h, i, input [3:0] sel, output [15:0] out ); always @(*) begin case (sel) 4'b0000:out=a; 4'b0001:out=b; 4'b0010:out=c; 4'b0011:out=d; 4'b0100:out=e; 4'b0101:out=f; 4'b0110:out=g; 4'b0111:out=h; 4'b1000:out=i; default:out=16'b1111_1111_1111_1111; endcase endmodule
3.1.2.4 256-to-1 multiplexer
代码如下:module top_module( input [255:0] in, input [7:0] sel, output out ); assign out=in[sel]; endmodule
3.1.2.5 256-to-1 4-bit multiplexer
代码如下:module top_module( input [1023:0] in, input [7:0] sel, output [3:0] out ); //经典的错误标准的零分,因为verilog没有这个语法 //assign out = in[sel*4+3:sel*4]; //正确的做法 assign out = in[sel*4+3-:4]; endmodule
3.1.3 Arithmetic Circuit
3.1.3.1 Half adder
代码如下:
module top_module( input a, b, output cout, sum ); assign {cout,sum} = a+b; endmodule
3.1.3.2 Full adder
module top_module( input a, b, cin, output cout, sum ); assign {cout ,sum } = a+b+cin; endmodule
3.1.3.3 3-bit binary adder
module top_module( input [2:0] a, b, input cin, output [2:0] cout, output [2:0] sum ); full_add add1(a[0],b[0],cin, cout[0],sum[0]); full_add add2(a[1],b[1],cout[0],cout[1],sum[1]); full_add add3(a[2],b[2],cout[1],cout[2],sum[2]); endmodule module full_add( input a, b, cin, output cout, sum ); assign {cout ,sum } = a+b+cin; endmodule
3.1.3.4 Adder
module top_module ( input [3:0] x, input [3:0] y, output [4:0] sum); wire [3:0] temp; full_add add1(x[0],y[0], ,temp[0],sum[0]); full_add add2(x[1],y[1],temp[0],temp[1],sum[1]); full_add add3(x[2],y[2],temp[1],temp[2],sum[2]); full_add add4(x[3],y[3],temp[2],temp[3],sum[3]); assign sum[4]=temp[3]; //还可以直接 sum = x + y; endmodule module full_add( input a, b, cin, output cout, sum ); assign {cout ,sum } = a+b+cin; endmodule
3.1.3.5 Signed addition overflow
有符号的运算,考虑溢出情况(见下图);
代码如下:module top_module ( input [7:0] a, input [7:0] b, output [7:0] s, output overflow ); // assign s = a+b; assign overflow = (a[7]&b[7]&~s[7]) | (~a[7]&~b[7]&s[7]) ; endmodule
3.1.3.6 100-bit binary adder
前面有写过需要例化很多模块时可以使用generate关键字来解决,这里我们有一个更加简单的方法来解决,那就是行为描述。
代码如下:module top_module( input [99:0] a, b, input cin, output cout, output [99:0] sum ); assign {cout,sum}=a+b+cin; endmodule
3.1.3.7 4-digit BCD adder
module top_module ( input [15:0] a, b, input cin, output cout, output [15:0] sum ); wire [3:0] temp; generate genvar i; for(i=0;i<4;i=i+1)begin :add_bcd if(i==0) bcd_fadd add10(a[4*i+3:4*i],b[4*i+3:4*i],cin, temp[i],sum[4*i+3:4*i]); bcd_fadd add10(a[4*i+3:4*i],b[4*i+3:4*i],temp[i-1],temp[i],sum[4*i+3:4*i]); endgenerate assign cout=temp[3]; endmodule
3.1.4 Karnaugh Map to Circuit
卡诺图走起!!!!!
3.1.4.1 3-variable
module top_module( input a, input b, input c, output out ); assign out= a | c | b; endmodule
3.1.4.2 4-variable
代码如下:module top_module( input a, input b, input c, input d, output out ); // 1 2 3 4 assign out = (~d & ~a) | (~c & ~b) | (c&d&b) | (d&a&~b); endmodule
3.1.4.3 4-variable
代码如下:
注意其中的d代表不在乎他为1还是0。module top_module( input a, input b, input c, input d, output out ); assign out = a | (c & ~b ); endmodule
3.1.4.4 4-variable
直接硬刚吧!!!没法化简。
代码如下:module top_module( input a, input b, input c, input d, output out ); 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 ); endmodule
3.1.4.5 Minimum SOP and POS
SOP (与或),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 & (~b|d) & (~a|b); endmodule
3.1.4.6 Karnaugh map
代码如下:module top_module ( input [4:1] x, output f ); assign f=(~x[1]&x[3]) | (x[2]&x[4]); endmodule
3.1.4.7 Karnaugh map
代码如下:module top_module ( input [4:1] x, output f assign f = (~x[4]&~x[2]) | (&x[4:2]) | (~x[1]&x[3]); endmodule
3.1.4.8 K-map implemented with a multiplexer
代码如下:module top_module ( input c, input d, output [3:0] mux_in //注意不能用逻辑门 //只能用选择器 //ab=2'b00; assign mux_in[0]=c?1:(d?1:0); //ab=2'b01; assign mux_in[1]=0; //ab=2'b11; assign mux_in[3]=c?(d?1:0):0; //ab=2'b10; assign mux_in[2]=c?(d?0:1):(d?0:1); endmodule
3.2 Sequential Logic
3.2.1 Latches and Flip-Flops
(1) D flip-flop
代码如下:module top_module ( input clk, // Clocks are used in sequential circuits input d, output reg q );// //D 触发器 上升沿有效 always @(posedge clk) begin q<=d; endmodule
(2) D flip-flops
8位的D触发器,与单个触发器设计一样。
代码如下:
module top_module ( input clk, input [7:0] d, output [7:0] q always @(posedge clk) begin q<=d; endmodule
(3) DFF with reset
代码如下:
module top_module ( input clk, input reset, // Synchronous reset input [7:0] d, output [7:0] q //同步复位 always @(posedge clk) begin //注意这里是高电平有效 if(reset) q<=8'b0; q<=d; endmodule
(4) DFF with reset value
代码如下:
module top_module ( input clk, input reset, input [7:0] d, output [7:0] q //时钟下降沿有效 always @(negedge clk) begin //注意这里是高电平有效 if(reset) q<=8'h34; q<=d; endmodule
(5) DFF with asynchronous reset
代码如下:
module top_module ( input clk, input areset, // active high asynchronous reset input [7:0] d, output [7:0] q //时钟上升沿有效 always @(posedge clk or posedge areset ) begin if(areset) q<=8'b0; q<=d; endmodule
(6) DFF with byte enable
代码如下:
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 begin q[15:8] <= byteena[1]?d[15:8]:q[15:8]; q[7:0] <= byteena[0]?d[7:0] :q[7:0 ]; endmodule
(7) D Latch
module top_module ( input d, input ena, output q); always @ (*) begin if(ena) q=d; q=q; endmodule
(8) DFF
异步复位
代码如下:
module top_module ( input clk, input d, input ar, // asynchronous reset output q); always @ (posedge clk or posedge ar) begin if(ar) q<=0; q<=d; endmodule
(9) DFF
代码如下:module top_module ( input clk, input d, input r, // synchronous reset output q); always @ (posedge clk) begin if(r) q<=0; q<=d; endmodule
(10) DFF + gate
代码如下:module top_module ( input clk, input in, output out); always @ (posedge clk) begin out<=in^out; endmodule
(11) MUX and DFF
注意这里一定要审题:不要把整个图都给他搞出来了
代码如下:module top_module ( input clk, input L, input r_in, input q_in, output reg Q); always @(posedge clk) begin Q<=L?r_in:q_in; endmodule
(12) MUX and DFF
代码如下:module top_module ( input clk, input w, R, E, L, output Q always @(posedge clk) begin Q<=L?R:(E?w:Q); endmodule
(13) DFFs and gates
//正确代码module top_module ( input clk, input x, output z reg [2:0] Q; always@(posedge clk)begin Q[0] <= Q[0] ^ x; Q[1] <= ~Q[1] & x; Q[2] <= ~Q[2] | x; assign z = ~(| Q); endmodule
错误代码:
提交之后一直显示错误,目前没有发现错误原因module top_module ( input clk, input x, output z wire D0,D1,D2; wire Q0,Q1,Q2; assign D0 = x ^ Q0; assign D1 = x & !Q1; assign D2 = x | !Q2; DFF aff1(clk,D0,Q0); DFF aff2(clk,D1,Q1); DFF aff3(clk,D2,Q2); assign z = !(Q0 | Q1 | Q2); endmodule module DFF ( input clk, input d, output reg q); always@(posedge clk) q <= d; endmodule
(14) Creat circuit from trurh table
代码如下:module top_module ( input clk, input j, input k, output Q); always @(posedge clk) begin Q <=j? (k?~Q:1):(k?0:Q); endmodule
(15) Detect an egde
题目:检测上升沿
代码如下:module top_module ( input clk, input [7:0] in, output [7:0] pedge //in_temp为in上一个cycle的值!!!! //假如in=1,in_temp=0;则为检测到了一个上升沿 reg [7:0] in_temp; //检测in的上升沿,检测到之后给pedge一个脉冲 always @ (posedge clk) begin in_temp <= in; pedge <= in & ~in_temp; endmodule
(15) Detect both egde
module top_module ( input clk, input [7:0] in, output [7:0] anyedge //in_temp为in上一个cycle的值!!!! //假如in=1,in_temp=0;则为检测到了一个上升沿 //in=0,in_temp=1;则为下降沿,都符合本题意 reg [7:0] in_temp; always @ (posedge clk) begin in_temp <= in; //便于理解写出了两种情况 // pedge <= (in & ~in_temp) & (~in & in_temp); //更加简洁的写法 anyedge <= in ^ in_temp; endmodule
(16) Egde capture register
module top_module ( input clk, input reset, input [31:0] in, output [31:0] out //捕获下降沿 reg [31:0] in_temp; always @(posedge clk) begin in_temp <= in; //每一位都要检测 for(int i=0;i<32;i=i+1) begin //这里的case条件用到了拼接运算符 //当然这里使用if语句也完全ok case ({in_temp[i] & ~in[i] ,reset}) 2'b01:out[i] = 1'b0; 2'b10:out[i] = 1'b1; //reset的优先级更加高一些 2'b11:out[i] = 1'b0; default : out[i]=out[i]; endcase endmodule
(17) Dual-edge rtiggered flip-flop
双沿触发器
module top_module ( input clk, input d, output q reg P_q,N_q; always @ (posedge clk) begin P_q<=d; always @ (negedge clk) begin N_q<=d; assign q = clk ? P_q:N_q; endmodule
3.2.2 Counters
(1)Four-bit binnary counter
代码如下:module top_module ( input clk, input reset, // Synchronous active-high reset output [3:0] q); always @ (posedge clk) begin if(reset) q<=4'b0; else if(q==4'b1111) q<=4'b0; q<=q+1'b1; endmodule
(2)Decade counter
代码如下:
module top_module ( input clk, input reset, // Synchronous active-high reset output [3:0] q); always @ (posedge clk) begin if(reset) q<=4'b0; else if(q>=4'b1001) q<=4'b0; q<=q+1'b1; endmodule
(3)Decade counter again
代码如下:module top_module ( input clk, input reset, output [3:0] q); always @ (posedge clk) begin if(reset) q<=4'b0001; else if(q>=4'b1010) q<=4'b1; q<=q+1'b1; endmodule
**(4)Slow decade counter **
注意这里在普通的计数器加了一个控制(slowena),当他为1时计数器才加1;
代码如下:
module top_module ( input clk, input slowena, input reset, output [3:0] q); always @ (posedge clk) begin if(reset) q<=4'b0; else if (slowena)begin if(q>=4'b1001) q<=4'b0; q<=q+1'b1; q<=q; endmodule
(5)Counter 1-12
已给4位计数器模块:
题目:用所给模块例化一个1~12 的计数器。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; //重新装载值 //当复位或者工作状态下计数值到达12时,装载值设为1 assign c_load = reset | ((Q==4'd12) && (enable == 1'b1)); assign c_d = c_load; count4 the_counter (clk, c_enable, c_load, c_d ,Q ); endmodule
(6)Counter 1000
题目:1000Hz分频成1Hz
module top_module ( input clk, input reset, output OneHertz, output [2:0] c_enable ); // //one: 个位 ten: 十位 hundred:百位 wire [3:0] one, ten, hundred; // [2] [1] [0] assign c_enable = {one == 4'd9 && ten == 4'd9 ,one == 4'd9 , 1'b1}; //1000hz 计数1000次时为1秒即1hz assign OneHertz = (one == 4'd9 && ten == 4'd9 && hundred == 4'd9); bcdcount counter0 (clk, reset, c_enable[0],one); bcdcount counter1 (clk, reset, c_enable[1],ten); bcdcount counter2 (clk, reset, c_enable[2],hundred); endmodule
(7)4-digit decimal counter
题目:构建4个十进制计数器,每个十进制数用四位表示module top_module ( input clk, input reset, // Synchronous active-high reset output [3:1] ena, output [15:0] q); reg [3:0] one,ten,hundred,thousand; //个位递增 always @(posedge clk) begin if(reset || one == 4'd9) begin one <= 4'd0; end else begin one<= one + 1'b1; //十位递增 always @(posedge clk) begin if(reset || ((one==4'd9) && (ten==4'd9))) begin ten <= 4'd0; end else if(ena[1]) begin ten <= ten +1'b1; //百位递增 always @(posedge clk) begin if(reset || ((one==4'd9) && (ten ==4'd9) && (hundred==4'd9))) begin hundred <= 4'd0; end else if (ena[2])begin hundred <= hundred +1'b1; //千位递增 always @(posedge clk) begin if(reset || ((one==4'd9)&& (ten ==4'd9) && (hundred==4'd9) && (thousand == 4'd9))) begin thousand <= 4'd0; end else if (ena[3])begin thousand <= thousand + 1'b1; assign q = {thousand,hundred,ten,one}; //十位应该增加 assign ena[1] = (one == 4'd9)?1'b1:1'b0; //百位应该增加 assign ena[2] = ((one == 4'd9) && (ten == 4'd9))?1'b1:1'b0; //千位应该增加 assign ena[3] = ((one == 4'd9) && (ten == 4'd9) && (hundred == 4'd9))?1'b1:1'b0; endmodule
(8)12-hour counter
难点在各种繁杂临界点判断
module top_module( input clk, input reset, input ena, output pm, output [7:0] hh, output [7:0] mm, output [7:0] ss); *组合逻辑用wire变量类型 *时序逻辑用reg 变量类型 wire ss_en,ss_60_en;/*秒个位进十位的进位脉冲;秒计满60秒的进位脉冲*/ reg [3:0] ss_one,ss_ten;/*秒的个位和十位*/ wire mm_en,mm_60_en;/*分个位进十位的进位脉冲;分计满60分钟的进位脉冲*/ reg [3:0] mm_one,mm_ten;/*分的个位和十位*/ wire hh_en,pm_en;/*时个位进十位的进位脉冲;产生AM PM转换脉冲*/ reg [3:0] hh_one,hh_ten;/*时的个位和十位*/ * 真实的输出 assign ss = {ss_ten,ss_one}; assign mm = {mm_ten,mm_one}; assign hh = {hh_ten,hh_one}; * 秒的个位 always @(posedge clk) begin if(reset) begin/*reset的优先级高于enable,并且复位后时钟为12:00 AM*/ ss_one <= 4'b0; else if(ena) begin if(ss_one == 4'd9) begin ss_one <= 4'b0; ss_one <= ss_one +1'b1; * 秒的十位 assign ss_en = (ss_one==4'd9 && ena) ? 1'b1:1'b0; /*秒个位进十位的脉冲信号*/ always @(posedge clk) begin if(reset) begin/*reset的优先级高于enable,并且复位后时钟为12:00:00 AM*/ ss_ten <= 4'b0; else if(ss_en) begin if(ss_one == 4'd9 && ss_ten == 4'd5) begin ss_ten <= 4'b0; ss_ten <= ss_ten + 1'b1; * 分的个位 assign ss_60_en = (ss_one==4'd9 && ss_ten == 4'd5 && ena) ? 1'b1:1'b0; /*秒计时60秒时,向分进位的脉冲*/ always @(posedge clk) begin if(reset) begin/*reset的优先级高于enable,并且复位后时钟为12:00 :00 AM*/ mm_one <= 4'b0; else if(ss_60_en) begin if(mm_one==4'd9) begin mm_one <= 4'b0; mm_one <= mm_one + 1'b1; * 分的十位 assign mm_en = (mm_one == 4'd9 && ena && ss_one == 4'd9 && ss_ten ==4'd5)? 1'b1:1'b0; always @(posedge clk) begin if(reset) begin/*reset的优先级高于enable,并且复位后时钟为12:00:00 AM*/ mm_ten <= 4'b0; else if(mm_en) begin if(mm_one == 4'd9 && mm_ten == 4'd5 && ss_one == 4'd9 && ss_ten == 4'd5) begin mm_ten <= 4'b0; mm_ten <= mm_ten + 1'b1; * 时的个位 assign mm_60_en = (mm_one == 4'd9 && mm_ten == 4'd5 && ss_one == 4'd9 && ss_ten == 4'd5)?1'b1:1'b0; always @(posedge clk) begin if(reset) begin/*reset的优先级高于enable,并且复位后时钟为12:00:00 AM*/ hh_one <= 4'd2; else if(mm_60_en) begin /*注意判断0点和9点这两个临界条件*/ //12:59:59 if(hh_one==4'd2 && hh_ten==4'd1 && mm_one == 4'd9 && mm_ten == 4'd5 && ss_one == 4'd9 && ss_ten == 4'd5) begin hh_one <= 4'b1; /*12点过后就是1点了*/ //9:59:59 else if(hh_one==4'd9 && hh_ten==4'd0 && mm_one == 4'd9 && mm_ten == 4'd5 && ss_one == 4'd9 && ss_ten == 4'd5)begin hh_one <=4'b0; /*9点之后是10点*/ hh_one <= hh_one + 1'b1; * 时的十位 assign hh_en = (hh_one==4'd9 && hh_ten==4'd0 && mm_one == 4'd9 && mm_ten == 4'd5 && ss_one == 4'd9 && ss_ten == 4'd5)?1'b1:1'b0; always @(posedge clk) begin if (reset) begin hh_ten <= 4'b1; else if ((hh_one == 4'd2) && (hh_ten == 4'd1) && (mm_one == 4'd9) && (mm_ten == 4'd5) && ena && (ss_one == 4'd9) && (ss_ten == 4'd5)) begin hh_ten <= 4'd0; else if(hh_en) begin hh_ten <= 4'd1; //11:59:59 AM-> PM assign pm_en = ((hh_one == 4'd1) && (hh_ten == 4'd1) && (mm_one == 4'd9) && (mm_ten == 4'd5) && ena && (ss_one == 4'd9) && (ss_ten == 4'd5))?1'b1:1'b0; always @(posedge clk) begin if(reset) begin pm <= 1'b0; else if(pm_en) begin pm <= ~pm; endmodule
3.2.3 Shift Registers
(1) 4-bit shift register
module top_module( input clk, input areset, // async active-high reset to zero input load, input ena, input [3:0] data, output reg [3:0] q); always @(posedge clk,posedge areset) begin /*异步复位,因此要添加areset */ if(areset) begin /* 如果复位为1,则输出全部置零*/ q <= 4'b0000; else if(load) begin/*load 比ena的优先级更加高*/ q <= data[3:0];/*load有效时,输出装载data里的值*/ else if(ena) begin q <= {1'b0,{q[3:1]}};/*q[3] becomes zero, q[0] is shifted out and disappears*/ q <= q; endmodule
(2) Left/right rotator
module top_module(
input clk,
input load,
input [1:0] ena,
input [99:0] data,
output reg [99:0] q);//1.建立一个一百位可左移可右移的寄存器,同步置位和使能 //2.这个寄存器移入的位来自另一个寄存器的移出位 //3.不像上一题的移入位是0,移出位舍弃 //4.如果使能,这寄存器的每一位不会被修改或者舍弃,而是一直循环 always @(posedge clk) begin if(load) begin /*load 优先级更高*/ q <= data; else begin case (ena) 2'b00:q<=q;/*保持*/ 2'b01:q<={q[0],q[99:1]};/*向右移一位*/ 2'b10:q<={q[98:0],q[99]};/*向左移一位*/ 2'b11:q<=q;/*保持*/ default:q<=q; endcase endmodule
(3) Left/right arithmetic shift by 1 or 8
逻辑移位:寄存器中整组数据进行移位,空位补0,只有数字位置的变化,无数量的变化。算术移位:寄存器中带符号数的移位,移位时,符号位保持不变,仅数量变化。
module top_module( input clk, input load, input ena, input [1:0] amount, input [63:0] data, output reg [63:0] q); always @(posedge clk) begin if( load )begin q <= data; end else if(ena) begin case (amount) 2'b00:q <= {q[62:0],1'b0}; 2'b01:q <= {q[55:0],8'b0}; 2'b10:q <= {q[63],q[63:1]}; 2'b11:q <= {{8{q[63]}},q[63:8]}; endcase end else q <= q; endmodule
(4) 5-bit LFSR
Galois LFSR 就是在正常的移位寄存器中加入一些抽头(异或门)从而实现有效状态(不会有全零状态)最大化(2^n - 1)。
module top_module( input clk, input reset, output [4:0] q always @(posedge clk) begin if(reset) q <= 5'h1; q <= {q[0],q[4],{q[3]^q[0]},q[2],q[1]}; endmodule
(5) 3-bit LFSR
1.图中r0,r1,r2分别连接SW[0], SW[1], SW[2。]
2.Clock 连接KEY[0], L连接KEY[1]。
3.Q连接LEDR注意:模块化会使代码更加简洁
代码如下:module top_module ( input [2:0] SW, // R input [1:0] KEY, // L and clk output [2:0] LEDR); // Q //例化左边第一个 dff_plus inst_left( .clk(KEY[0]), .in_1(SW[0]), .in_0(LEDR[2]), .sel(KEY[1]), .q(LEDR[0]) //例化中间那个 dff_plus inst_mid( .clk(KEY[0]), .in_1(SW[1]), .in_0(LEDR[0]), .sel(KEY[1]), .q(LEDR[1]) //例化右边那个 dff_plus inst_right( .clk(KEY[0]), .in_1(SW[2]), .in_0(LEDR[1]^LEDR[2]), //抽头 .sel(KEY[1]), .q(LEDR[2]) endmodule //实现电路图中的一个模块 module dff_plus( input clk, input in_0, input in_1, input sel, output q //数据选择器输入 wire in_temp; assign in_temp = sel ? in_1 : in_0; reg q_temp = 0; always @(posedge clk) begin q_temp <= in_temp; assign q = q_temp; endmodule
(6) 32-bit LFSR
题目:建立一个 32-bit Galois LFSR 抽头的位置放在32, 22, 2, 和 1.
module top_module( input clk, input reset, // Active-high synchronous reset to 32'h1 output [31:0] q always @(posedge clk) begin if(reset) q <= 32'h1; else //tap 32 22 2 1 q <= {q[0],{q[31:23]},{q[22]^q[0]},{q[21:3]},{q[2]^q[0]},{q[1]^q[0]}}; endmodule
(6) Shift register
module top_module ( input clk, input resetn, // synchronous reset input in, output out); wire [2:0] qtemp;//输出中间态 //例化左边第一个 dff_res dff1( .clk(clk), .re_n(resetn), .in_temp(in), .q(qtemp[0]) //例化左边第二个 dff_res dff2( .clk(clk), .re_n(resetn), .in_temp(qtemp[0]), .q(qtemp[1]) //例化左边第三个 dff_res dff3( .clk(clk), .re_n(resetn), .in_temp(qtemp[1]), .q(qtemp[2]) //例化左边第四个 dff_res dff4( .clk(clk), .re_n(resetn), .in_temp(qtemp[2]), .q(out) endmodule module dff_res( input clk, input re_n, input in_temp, output q always @(posedge clk) begin //同步 if(!re_n) //低有效 q <= 1'b0; q <= in_temp; endmodule
(7) Shift register
module top_module ( input [3:0] SW, input [3:0] KEY, output [3:0] LEDR ); // MUXDFF dff3( .clk(KEY[0]), .wData(KEY[3]), .ena(KEY[1]), .r_tmp(SW[3]), .l_tmp(KEY[2]), .q(LEDR[3]) MUXDFF dff2( .clk(KEY[0]), .wData(LEDR[3]), .ena(KEY[1]), .r_tmp(SW[2]), .l_tmp(KEY[2]), .q(LEDR[2]) MUXDFF dff1( .clk(KEY[0]), .wData(LEDR[2]), .ena(KEY[1]), .r_tmp(SW[1]), .l_tmp(KEY[2]), .q(LEDR[1]) MUXDFF dff0( .clk(KEY[0]), .wData(LEDR[1]), .ena(KEY[1]), .r_tmp(SW[0]), .l_tmp(KEY[2]), .q(LEDR[0]) endmodule module MUXDFF ( input clk, input wData, input ena, input r_tmp, input l_tmp, output q wire [1:0] tmp; //组合逻辑 assign tmp[0] = ena ? wData : q; assign tmp[1] = l_tmp ? r_tmp : tmp[0]; //时序逻辑块 always @(posedge clk) begin q <= tmp[1]; endmodule
(8) 3-input LUT
可以解决组合逻辑使用门电路带来的延时的不确定性,LUT(查找表)相当于SRAM,把输入当成地址,输出当成该地址上的值。
module top_module ( input clk, input enable, input S, input A, B, C, output Z ); reg [7:0] q; //第一、建立一个8bit移位寄存器,且是将S移入第0位,最高位舍弃。 always @(posedge clk) begin if(enable)begin q <= {q[6:0],S}; else begin q <= q; //A,B,C 为000 时 Z = q[0],,, assign Z = q[{A,B,C}]; //此处的{A,B,C}为3bit 3‘b000 = 3'd0;以此类推 endmodule
3.2.4 More Circuits
(1)Rule 90
题目:输出为旁边两位的异或,并且data【-1】和data【512】为0;
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 begin // 错位相异或即可得到输出 // q[512] and q[-1] are both zero q <= {1'b0,q[511:1]}^{q[510:0],1'b0}; endmodule
(2)Rule 110
一维细胞自动机
题目与上一题一样,但是真值表不一样,直接看也看不出来,因此使用了卡诺图化简(数电的基础知识)。
再表述出来即可。module top_module( input clk, input load, input [511:0] data, output [511:0] q //left -- A ;center -- B ;right -- C ; reg [511:0] A,B,C; //左边那一位 assign A = {1'b0,q[511:1]}; //中间位 assign B = q; //右边那一位 assign C = {q[510:0],1'b0}; always @(posedge clk)begin if(load)begin q <= data; else begin //根据题中给的真值表,卡诺图化简得来 q <= ~B&C | ~A&B | B&~C; endmodule
(3)Conway’s Game of Life 16*16
二维细胞自动机
举例(0,0)边界的邻居:
假设棋盘是这样的:下图举例了q[0]邻居位置,同理可以推测出棋盘上每一个位置的邻居
module