一、Getting Started
1.1Getting Started
1.1.1 编译后提示的意思
当你把代码写完然后编译之后,会给出相应的提示:
- 如果语言的编译和线路的仿真都正确,并且符合题目要求,则会提示Success!
- 编译错误,则会提示Compile Error
- 电路仿真错误,则会提示Simulation Error
- 如果语言的编译和线路的仿真都正确,但是不符合题目要求,则会提示Incorrect
- 可以在My Stats 查看或者分享我们写题目的进度,可以理解为自动存档哈。如图1.1所示。
1.1.2 网站的几个重要的板块
见下图即可。
1.1.3 问题的翻译与解答
意思:创建一个没有输入只有一个输出的电路,且输出总是为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];
end
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
end
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;
end
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;
end
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;
end
always @(posedge clk)
begin
out_always_ff <= a^b;
end
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;
end
else begin
out_always = a;
end
end
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;
else
shut_off_computer = 0;
end
always @(*) begin
if (~arrived)
//还没到达目的地,油箱没空就保持行驶
keep_driving = ~gas_tank_empty;
else
//到了就不行驶了
keep_driving = 0;
end
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
end
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
end
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位优先编码器。
代码如下:
方法一、casez
module 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
end
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
end
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
end
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;
end
endcase
end
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];
end
end
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;
end
else
out=out;
end
end
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])
);
end
else begin
adder_full add100(
.a(a[i]),
.b(b[i]),
.cin(cout[i-1]),
.cout(cout[i]),
.sum(sum[i])
);
end
end
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]);
end
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]);
end
end
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;
end
else begin
temp=temp;
end
end
out=temp;
end
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
end
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]);
else
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]);
end
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;
end
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;
end
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;
else
q<=d;
end
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;
else
q<=d;
end
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;
else
q<=d;
end
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 ];
end
end
endmodule
(7) D Latch
module top_module (
input d,
input ena,
output q);
always @ (*)
begin
if(ena)
q=d;
else
q=q;
end
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;
else
q<=d;
end
endmodule
(9) DFF
代码如下:
module top_module (
input clk,
input d,
input r, // synchronous reset
output q);
always @ (posedge clk)
begin
if(r)
q<=0;
else
q<=d;
end
endmodule
(10) DFF + gate
代码如下:
module top_module (
input clk,
input in,
output out);
always @ (posedge clk)
begin
out<=in^out;
end
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;
end
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);
end
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;
end
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);
end
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;
end
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;
end
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
end
end
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;
end
always @ (negedge clk)
begin
N_q<=d;
end
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;
else
q<=q+1'b1;
end
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;
else
q<=q+1'b1;
end
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;
else
q<=q+1'b1;
end
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;
else
q<=q+1'b1;
end
else
q<=q;
end
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;
end
end
//十位递增
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;
end
end
//百位递增
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;
end
end
//千位递增
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;
end
end
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;
end
else if(ena) begin
if(ss_one == 4'd9) begin
ss_one <= 4'b0;
end
else
ss_one <= ss_one +1'b1;
end
end
/*
* 秒的十位
*/
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;
end
else if(ss_en) begin
if(ss_one == 4'd9 && ss_ten == 4'd5) begin
ss_ten <= 4'b0;
end
else
ss_ten <= ss_ten + 1'b1;
end
end
/*
* 分的个位
*/
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;
end
else if(ss_60_en) begin
if(mm_one==4'd9) begin
mm_one <= 4'b0;
end
else
mm_one <= mm_one + 1'b1;
end
end
/*
* 分的十位
*/
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;
end
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;
end
else
mm_ten <= mm_ten + 1'b1;
end
end
/*
* 时的个位
*/
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;
end
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点了*/
end
//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点*/
end
else
hh_one <= hh_one + 1'b1;
end
end
/*
* 时的十位
*/
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;
end
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;
end
else if(hh_en) begin
hh_ten <= 4'd1;
end
end
//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;
end
else if(pm_en) begin
pm <= ~pm;
end
end
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;
end
else if(load) begin/*load 比ena的优先级更加高*/
q <= data[3:0];/*load有效时,输出装载data里的值*/
end
else if(ena) begin
q <= {1'b0,{q[3:1]}};/*q[3] becomes zero, q[0] is shifted out and disappears*/
end
else
q <= q;
end
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;
end
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
end
end
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;
end
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;
else
q <= {q[0],q[4],{q[3]^q[0]},q[2],q[1]};
end
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;
end
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]}};
end
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;
else
q <= in_temp;
end
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];
end
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};
end
else begin
q <= q;
end
end
//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};
end
end
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;
end
else begin
//根据题中给的真值表,卡诺图化简得来
q <= ~B&C | ~A&B | B&~C;
end
end
endmodule
(3)Conway’s Game of Life 16*16
二维细胞自动机
举例(0,0)边界的邻居:
假设棋盘是这样的:下图举例了q[0]邻居位置,同理可以推测出棋盘上每一个位置的邻居
module top_module(
input clk,
input load,
input [255:0] data,
output [255:0] q );
//用于记录邻居存活的个数
reg [3:0] sum;
//下一个状态
reg [255:0] q_next;
always @(posedge clk) begin
if(load)
q <= data;
else begin
for(integer i=0;i<256;i++) begin
if(i==0)//左上角
sum = q[1]+q[16]+q[17]+q[240]+q[241]+q[15]+q[31]+q[255];
else if(i==15)//右上角
sum = q[14]+q[16]+q[0]+q[240]+q[254]+q[30]+q[31]+q[255];
else if(i==240)//左下角
sum = q[0]+q[15]+q[239]+q[241]+q[1]+q[224]+q[225]+q[255];
else if(i==255)//右下角
sum = q[0]+q[15]+q[14]+q[224]+q[238]+q[240]+q[239]+q[254];
else if(0<i & i<15)//上边界 //注意这里的书写不可以是0<i<15
sum = q[i-1]+q[i+1]+q[i+15]+q[i+16]+q[i+17]+q[i+239]+q[i+240]+q[i+241];
else if(i%16==0)//左边界
sum = q[i-1]+q[i+1]+q[i+15]+q[i+16]+q[i+17]+q[i-16]+q[i-15]+q[i+31];
else if(i%16==15)//右边界
sum = q[i-1]+q[i+1]+q[i+15]+q[i+16]+q[i-17]+q[i-16]+q[i-15]+q[i-31];
else if(240<i & i<255)//下边界
sum = q[i-1]+q[i+1]+q[i-17]+q[i-16]+q[i-15]+q[i-239]+q[i-240]+q[i-241];
else //非边界
sum = q[i-1]+q[i+1]+q[i-17]+q[i-16]+q[i-15]+q[i+15]+q[i+16]+q[i+17];
//判断规则见本题第一个图
case (sum)
2:q_next[i]=q[i]; //周围有两个则不变
3:q_next[i]=1; //有三个则繁衍
default:q_next[i]=0; //其余情况都减员
endcase
end
q <= q_next;
end
end
endmodule
3.2.5 Finite State Machines
(1)Simple FSM1
module top_module(
input clk,
input areset, // Asynchronous reset to state B
input in,
output out);//
//状态编码
parameter A=0, B=1;
reg state, next_state;
always @(*) begin // This is a combinational always block
// State transition logic
case (state)
B: begin
//看状态图 输入为1则下一个状态也是B
if(in == 1'b1)
next_state = B;
else
next_state = A;
end
A: begin
if(in == 1'b1)
next_state = A;
else
next_state = B;
end
endcase
end
//异步所以要包含areset的敏感列表
always @(posedge clk, posedge areset) begin // This is a sequential always block
// State flip-flops with asynchronous reset
if(areset)
state <= B;
else
state <= next_state;
end
// Output logic
assign out = (state == B);
endmodule
(2)Simple FSM1s
与(1)一致 不过是同步复位了
// Note the Verilog-1995 module declaration syntax here:
module top_module(clk, reset, in, out);
input clk;
input reset; // Synchronous reset to state B
input in;
output out;//
reg out;
parameter A = 0, B = 1;
reg present_state, next_state;
always @(posedge clk) begin //同步复位
if (reset) begin
present_state <= B;
end
else
present_state <= next_state;
end
always @(*) begin
case(present_state)
A:begin
if(in == 1'b1)
next_state = A;
else
next_state = B;
end
B:begin
if(in == 1'b1)
next_state = B;
else
next_state = A;
end
endcase
end
assign out = (present_state == B);
endmodule
(3)Simple FSM2
2输入1输出的异步复位状态机;
module top_module(
input clk,
input areset, // Asynchronous reset to OFF
input j,
input k,
output out); //
parameter OFF=0, ON=1;
reg state, next_state;
always @(*) begin
case(state)
OFF: begin
if(j== 1'b1)
next_state = ON;
else
next_state = OFF;
end
ON : begin
if(k == 1'b1)
next_state = OFF;
else
next_state = ON;
end
endcase
end
always @(posedge clk, posedge areset) begin
if(areset)
state <= OFF;
else begin
state <= next_state;
end
end
// Output logic
assign out = (state == ON);
endmodule
(3)Simple FSM2 S
module top_module(
input clk,
input reset, // Synchronous reset to OFF
input j,
input k,
output out); //
parameter OFF=0, ON=1;
reg state, next_state;
always @(*) begin
// State transition logic
case(state)
OFF: begin
if(j== 1'b1)
next_state = ON;
else
next_state = OFF;
end
ON : begin
if(k == 1'b1)
next_state = OFF;
else
next_state = ON;
end
endcase
end
always @(posedge clk) begin
// State flip-flops with synchronous reset
if(reset)
state <= OFF;
else begin
state <= next_state;
end
end
// Output logic
assign out = (state == ON);
endmodule
(4)Simple state transitions 3
module top_module(
input in,
input [1:0] state,
output [1:0] next_state,
output out); //
//状态编码A=2'b00, B=2'b01, C=2'b10, D=2'b11.
parameter A=0, B=1, C=2, D=3;
// State transition logic: next_state = f(state, in)
always @ (*)begin
case (state)
A: begin
if(in == 1'b1)
next_state = B;
else
next_state = A;
end
B: begin
if(in == 1'b1)
next_state = B;
else
next_state = C;
end
C: begin
if(in == 1'b1)
next_state = D;
else
next_state = A;
end
D: begin
if(in == 1'b1)
next_state = B;
else
next_state = C;
end
endcase
end
// Output logic: out = f(state) for a Moore state machine
always @(*) begin
case (state)
A:out = 0;
B:out = 0;
C:out = 0;
D:out = 1;
endcase
end
endmodule
(5)Simple one-hot state transitions 3
(1)one-hot 编码:这种编码方式所用的D触发器比递增二进制编码多,状态数就等于触发器的数量,这使得译码电路就比较简单,因此他的速度非常快。
(2)格雷编码:能够避免进入错误状态,常用于高可靠性设计。
(3)递增二进制编码:效率高,但是会导致很大的组合逻辑。
ps:编码方式见下图:
module top_module(
input in,
input [3:0] state,
output [3:0] next_state,
output out); //
parameter A=0, B=1, C=2, D=3;
// State transition logic: Derive an equation for each state flip-flop.
assign next_state[A] = state[A]&(~in) | state[C]&(~in);
assign next_state[B] = state[A]&in | state[B]&in | state[D]∈
assign next_state[C] = state[B]&(~in) | state[D]&(~in);
assign next_state[D] = state[C]∈
// Output logic:
assign out = state[D];
endmodule