01、8位加法器
功能代码
module adder_8 ( cout,sum,a,b,cin );
input [7:0] a,b;
input cin;
output cout;
output [7:0] sum;
assign {cout,sum} = a + b + cin;
endmodule
测试代码
`timescale 1ns/1ns
module adder_8_test;
reg [7:0]a, b;
reg cin;
wire [7:0] sum;
wire cout;
parameter INTERVAL;
adder_8 a1(.cout(cout), .sum(sum), .a(a), .b(b), .cin(cin));
initial
begin
#INTERVAL {a,b,cin} = 17'b0000_0000_0000_0000_0;
#INTERVAL {a,b,cin} = 17'b1101_1011_0010_0011_0;
#INTERVAL {a,b,cin} = 17'b1111_0000_0000_1111_1;
#INTERVAL {a,b,cin} = 17'b1001_0100_1001_0011_1;
end
endmodule
02、8位计数器
功能代码
module counter(out,clk,enable,rst);
output[7:0] out;
input clk, rst, enable;
reg[7:0] out;
always @ (posedge clk) begin
if (rst) begin
out <= 8'b0;
end else if (enable) begin
out <= out + 1;
end
end
endmodule
测试代码
`timescale 1ns/1ns
module counter_tb;
reg clk, enable, rst;
wire [7:0] out;
parameter INTERVAL = 10;
counter c1(.out(out), .clk(clk), .enable(enable), .rst(rst));
initial begin
enable = 1;
clk = 0;
forever #(INTERVAL/2) clk = ~clk;
end
initial begin
rst = 1;
#INTERVAL rst = 0;
#(200*INTERVAL) $finish;
end
endmodule
03、二选一多路选择器
连续赋值方式
module onInTwo(a,b,s,d);
input a,b,s;
output d;
assign d = (s == 0)?a:b;
endmodule
阻塞赋值方式
module onInTwo2(out,d,a,s);
input a,b,s;
output out;
always @(*)begin
if (s==0) begin
out = a;
end else begin
out = b;
end
end
endmodule
04、阻塞赋值实现双触发器
功能代码
module Dflip(output c,input a,input clk,);
reg b,c;
always @(posedge clk)begin
c=b;
b=a;
end
endmodule
测试代码
`timescale 1ns / 1ns
module tb_Dflip;
parameter INTERVAL = 10;
reg a = 0,clk=0;
wire c;
initial begin
forever #(INTERVAL/2) clk = ~clk;
end
initial begin
forever #(INTERVAL) a = ~a;
end
Dflip d1(.c (c),.a (a), .clk (clk));
endmodule
05、四位移位寄存器
功能代码
module register(out,clk,in);
input clk,in;
output [3:0] out;
always @(posedge clk) begin
out = (out<<1);
out[0] = in;
end
endmodule
测试代码
`timescale 1ns/1ns
module tb_register;
wire [3:0] out;
parameter INTERVAL = 10;
reg in, clk;
initial forever #(INTERVAL/2) clk = ~clk;
initial forever #INTERVAL in = ~in;
initial begin
clk = 1;
in = 1;
end
register r1(.out(out),.clk(clk), .in(in));
initial #(INTERVAL*100) $finish;
endmodule
模拟仿真
06、for循环七人表决器
功能代码
module vote_7(output pass,input [6:0] vote);
integer i;
reg[2:0] vote_count;
always@(vote)begin
vote_count=0;
for(i = 0;i<7;i = i+1) begin
if (vote[i])
vote_count = vote_count+1;
end
end
assign pass = (vote_count>3) ? 1 : 0;
endmodule
测试代码
`timescale 1ns/1ns
module tb_vote_7;
reg[6:0] vote;
wire pass;
parameter INTERVAL = 10;
initial begin
#INTERVAL vote = 7'b1001010;
#INTERVAL vote = 7'b0101101;
#INTERVAL vote = 7'b1001011;
#INTERVAL vote = 7'b1011111;
#INTERVAL vote = 7'b0001010;
#INTERVAL vote = 7'b1000011;
#INTERVAL vote = 7'b1011000;
#INTERVAL vote = 7'b1101011;
end
vote_7 v1(.pass(pass),.vote(vote));
endmodule
模拟仿真
07、32位整数循环
a、for实现
`timescale 1ns/1ns
module tb_circle_32;
reg [31:0] num;
reg temp;
integer i;
initial begin
#10
for(i=0;i<32;i=i+1) begin
#10
temp = num[31];
num = (num<<1);
num[0] =temp;
end
end
initial
num = 32'b1011_0101_1001_0100_1100_0110_1011_1101;
initial #500 $finish;
endmodule
b、while实现
`timescale 1ns/1ns
module tb_circle_32;
reg [31:0] num;
reg temp;
integer i;
initial begin
#10
i=0;
while(i<32) begin
#10
temp = num[31];
num = (num<<1);
num[0] =temp;
i=i+1;
end
end
initial
num = 32'b1011_0101_1001_0100_1100_0110_1011_1101;
initial #500 $finish;
endmodule
c、repeat实现
`timescale 1ns/1ns
module tb_circle_32;
reg [31:0] num;
reg temp;
initial begin
#10
repeat(32) begin
#10
temp = num[31];
num = (num<<1);
num[0] =temp;
end
end
initial num = 32'b1011_0101_1001_0100_1100_0110_1011_1101;
initial #700 $finish;
endmodule
d、模拟仿真
三者仿真结果相同
08、用持续赋值、task、function实现四选一
a、持续赋值
功能代码
module oneInFour(y,a,b,enable,d0,d1,d2,d3);
input a,b,enable,d0,d1,d2,d3;
output y;
assign y = !enable&&((!a && !b && d0) || (!a && b && d1) || (a && !b && d2) || (a && b && d3));
endmodule
测试代码
`timescale 10ns/10ns
module tb_oneInFour;
reg a,b,enable,d0,d1,d2,d3;
wire y;
initial begin
enable = 0;
{d0,d1,d2,d3} = 4'b0110;
end
initial begin
{a,b} = 2'b00
#10 {a,b} = 2'b01;
#10 {a,b} = 2'b10;
#10 {a,b} = 2'b11;
#10 $finish;
end
oneInFour u1(.y(y),.a(a),.b(b),.enable(enable),.d0(d0),.d1(d1),.d2(d2),.d3(d3));
endmodule
b、task
`timescale 10ns/10ns
module tb_oneInFour_task;
reg a,b,enable,d0,d1,d2,d3,y;
initial begin
enable = 0;
{d0,d1,d2,d3} = 4'b0110;
end
initial begin
{a,b} = 2'b00
#10 {a,b} = 2'b01;
#10 {a,b} = 2'b10;
#10 {a,b} = 2'b11;
#10 $finish;
end
always @(a or b or enable or d0 or d1 or d2 or d3) begin
selectOne(y,a,b,enable,d0,d1,d2,d3);
end
task selectOne;
input a,b,enable,d0,d1,d2,d3;
output y;
begin
y = !enable&&((!a && !b && d0) || (!a && b && d1) || (a && !b && d2) || (a && b && d3));
end
endtask
endmodule
c、function
`timescale 10ns/10ns
module tb_oneInFour_fun;
reg a,b,enable,d0,d1,d2,d3, y;
function selectOne;
input a,b,enable,d0,d1,d2,d3;
begin
selectOne = !enable&&((!a && !b && d0) || (!a && b && d1) || (a && !b && d2) || (a && b && d3));
end
endfunction
initial begin
enable = 0;
{d0,d1,d2,d3} = 4'b0110;
end
initial begin
{a,b} = 2'b00
#10 {a,b} = 2'b01;
#10 {a,b} = 2'b10;
#10 {a,b} = 2'b11;
#10 $finish;
end
always @(a or b or enable or d0 or d1 or d2 or d3) begin
y = selectOne(a,b,enable,d0,d1,d2,d3);
end
endmodule
d、模拟仿真
09、空调机
设计一个空调机的控制机。温度传感器控制两个输入端temp_high和temp_low, 如果室内温度较高,则temp_high为’1’, 同时temp_low为’0’; 如果室内温度较低,则temp_high为’0’, 同时temp_ low为’1’; 如果室内温度正常,则temp_high为’0’, 同时temp_low为’0’。 根据输入端temp_high和temp_ _low的值来判断当前的状态是: 1.too_hot (太热) ; 2. too_cold (太冷) ; 3.just_right (正好),然后决定输出端heat和cool的值是’1’还是’0’,从而控制是制冷还是制热。
要求:
1.画出有限状态机,标明状态转换条件;
2.写出程序代码,标注说明和解释;
3.写出验证程序,对设计进行全面的验证。
状态转移图
源代码
module air(clk,rst,temp_high,temp_low,heat,cool);
input clk,rst,temp_high,temp_low;
output heat,cool;
reg heat,cool;
reg [1:0] cur_state,next_state;
//定义三个状态
parameter TOO_HIGH = 2'b10,
JUST_RIGHT = 2'b00,
TOO_LOW = 2'b01;
//时序 设置当前状态为预设的下一状态或初始
always @(posedge clk or posedge rst) begin
if(rst)begin
//重设置零
cur_state <= JUST_RIGHT;
end else begin
cur_state <= next_state;
end
end
//根据当前状态决定输出
always @(cur_state) begin
case (cur_state)
TOO_HIGH: begin
{heat,cool} = 2'b01;
end
JUST_RIGHT: begin
{heat,cool} = 2'b00;
end
TOO_LOW: begin
{heat,cool} = 2'b10;
end
default: begin
{heat,cool} = 2'b00;
end
endcase
end
//根据输入决定下一预设状态
always @(cur_state or temp_high or temp_low or rst) begin
if(rst)
next_state <= JUST_RIGHT;
else begin
case (cur_state)
TOO_HIGH: begin
next_state = (temp_high == 1)?TOO_HIGH:JUST_RIGHT;
end
JUST_RIGHT: begin
if (temp_high == 1 && temp_low == 0) begin
next_state = TOO_HIGH;
end else if (temp_high == 0 && temp_low == 1) begin
next_state = TOO_LOW;
end else begin
next_state = JUST_RIGHT;
end
end
TOO_LOW: begin
next_state = (temp_low == 1)?TOO_LOW:JUST_RIGHT;
end
default: begin
next_state = JUST_RIGHT;
end
endcase
end
end
endmodule
测试代码
`timescale 1ns/1ns
module tb_air;
reg clk,rst,temp_high,temp_low;
wire heat,cool;
parameter PERIOD = 10;
parameter CHANGE_PERIOD = 4*PERIOD;
//初始化各值
initial begin
clk = 1'b0;
rst = 1'b0;
temp_high = 1'b0;
temp_low = 1'b0;
end
//设定时钟周期
initial
forever #(PERIOD/2) clk = ~clk;
//重置模块
initial begin
#PERIOD rst = 1;
#PERIOD rst = 0;
end
initial begin
//测试JUST_RIGHT状态下输入改变
#CHANGE_PERIOD {temp_high,temp_low} = 2'b11;
#CHANGE_PERIOD {temp_high,temp_low} = 2'b00;
#CHANGE_PERIOD {temp_high,temp_low} = 2'b01;
//转入TOO_LOW,测试TOO_LOW状态下输入改变
#CHANGE_PERIOD {temp_high,temp_low} = 2'b01;
#CHANGE_PERIOD {temp_high,temp_low} = 2'b11;
#CHANGE_PERIOD {temp_high,temp_low} = 2'b10;
//重新转入JUST_RIGHT
#CHANGE_PERIOD {temp_high,temp_low} = 2'b10;
//转入TOO_HIGH,测试TOO_HIGH状态下输入改变
#CHANGE_PERIOD {temp_high,temp_low} = 2'b11;
#CHANGE_PERIOD {temp_high,temp_low} = 2'b10;
#CHANGE_PERIOD {temp_high,temp_low} = 2'b00;
#CHANGE_PERIOD $finish;
end
//实例化模块
air i1(clk,rst,temp_high,temp_low,heat,cool);
endmodule //tb_air
模拟仿真
10、交通灯
设计一个交通灯控制器。一个十字交叉路口,东西方向为主干道(HighWay),南北方向为副干道(CountryWay) 。副干道车辆很少,因此在交叉路口处有车辆探测器(Sensor) ,可以判断副干道是否有车。如果没有车,则主干道始终绿灯(Green) ;如果副干道有车,则在主干道通行40秒后,主干道红灯(Red),而副干道绿灯,通行时间为20秒。这时无论副干道有无车,副干道都要红灯,而主干道绿灯。从绿灯到红灯的转换中间有4秒黄灯(Yellow) 。
要求:
1.画出有限状态机,标明状态转换条件;
2.写出程序代码,标注说明和解释;
3.写出验证程序,对设计进行全面的验证。
状态转换图
源代码
该程序源代码分为2子模块(计数器模块+交通灯模块)+顶模块
计数器模块
module counter(out,clk,enable,rst);
output[6:0] out;
input clk, rst,enable;
reg[6:0] out;
always @ (posedge rst or posedge clk) begin
if (rst) begin
out <= 8'b0;
end else if (enable) begin
out <= (out + 1)%69;
end
end
endmodule
交通灯模块
module light(highWay,countryWay,counter_enable,clk,rst,senor,count);
input clk,rst,senor;
input [6:0] count;
output counter_enable;
output [1:0] highWay,countryWay;
reg counter_enable;
reg [1:0] highWay,countryWay;
//标志计数状态
wire [6:0] count;
//主干状态,副干状态与之对应
reg [1:0] cur_state,next_state;
//灯输出结果常量
parameter GREEN = 2'b00,
YELLOW = 2'b01,
RED = 2'b11;
//状态常量
parameter PASS = 2'b00,
WAIT1 = 2'b01,
WAIT2 = 2'b10,
STOP = 2'b11;
//根据下一状态或重置改变现在状态
always @(posedge rst or posedge clk) begin
if(rst) begin
cur_state <= PASS;
end else begin
cur_state <= next_state;
end
end
//不同状态不同输出
always @(cur_state) begin
case (cur_state)
PASS:begin
highWay = GREEN;
countryWay = RED;
end
WAIT1:begin
highWay = YELLOW;
countryWay = YELLOW;
end
WAIT2:begin
highWay = YELLOW;
countryWay = YELLOW;
end
STOP:begin
highWay = RED;
countryWay = GREEN;
end
default: begin
highWay = GREEN;
countryWay = RED;
end
endcase
end
//根据输入改变下一预设状态
always @(senor or count or rst) begin
if(rst) begin
next_state <= PASS;
counter_enable <= 0;
end else begin
next_state = PASS;
case (cur_state)
PASS:begin
if (senor) begin
if (count==40) begin
next_state = WAIT1;
end
counter_enable = 1;
end else begin
counter_enable = 0;
end
end
WAIT1:begin
next_state = (count==44)?STOP:WAIT1;
end
WAIT2:begin
next_state = (count==68)?PASS:WAIT2;
end
STOP:begin
next_state = (count==64)?WAIT2:STOP;
end
endcase
end
endmodule
顶层模块
module top(highWay,countryWay,clk,rst,senor);
input clk,rst,senor;
output [1:0] highWay,countryWay;
wire counter_enable;
wire [6:0] count;
light i1(.highWay(highWay),.countryWay(countryWay),
.counter_enable(counter_enable),
.clk(clk),.rst(rst),
.senor(senor),.count(count));
counter c1(.out(count),.clk(clk),
.enable(counter_enable),.rst(rst));
endmodule
注意:当前代码中,默认了主干副干状态相互对应,red(主)-green(副),yellow(主)-yellow(副),green(主)-red(副)。
但实际上不是这样。
很多交通灯设计时,只有在red->green时需要穿插一个黄灯,正如题干最后一句。所以我这样的设计实际上是不符合题干要求的。
如果你想做一个更符合实际的,那么你需要再增加两个变量:cur_state2
和next_state2
来保存副干状态。同时将状态机中的WAIT1
状态删去,使得PASS
直接指向STOP
。
测试代码
`timescale 1ns/1ns
module tb_light;
reg clk,rst,senor;
wire [1:0] highWay,countryWay;
parameter INTERVAL = 10;
//初始化各值
initial begin
clk = 1'b0;
rst = 1'b0;
senor = 1'b0;
end
//设定时钟周期
initial
forever #(INTERVAL/2) clk = ~clk;
//重置模块
initial begin
#INTERVAL rst = 1;
#INTERVAL rst = 0;
end
initial begin
//测试副干有车情况
#(5*INTERVAL) senor = 1'b1;
//测试副干无车情况
#(60*INTERVAL) senor = 1'b0;
#(100*INTERVAL) $finish;
end
//实例化模块
top t1(highWay,countryWay,clk,rst,senor);
endmodule
注意:交通灯模块中是用senor
来判断是否在计时状态的。如果测试代码中,使senor=0
时是在主干PASS
的状态(senor=0
意味着副干车没了,在主干PASS
的状态下,副干原本的车突然没了?路口调头怕是来不及吧……所以本身算是一个伪命题——当然这排除了设备出故障情况),注意到交通灯模块并没有对计数器模块进行清零,所以下一次使senor=1
时,主干通行时间可能会小于40S。
模拟仿真
11、基本门描述设计
利用Verilog基本门(门级)描述设计和验证如下图所示电路的结构化模型。并在设计的测试平台中分别使用模型名与端口名t_Combo_ str()和Combo_ str (Y,A,B,C,D)。
注意:该测试平台没有端口。
源代码
module Combo_str(Y,A,B,C,D);
input A,B,C,D;
output Y;
wire D_bar,A_D,A_D_bar,B_C_D_bar;
not n1(D_bar,D),n2(A_D_bar,A_D);
or o1(A_D,A,D);
and a1(B_C_D_bar,D_bar,B,C),a2(Y,A_D_bar,B_C_D_bar);
endmodule
测试代码
`timescale 10ns/1ns
module t_Combo_str;
parameter INTERVAL = 10;
reg A,B,C,D;
wire Y;
initial begin
#INTERVAL {A,B,C,D} = 4'b0000;
#INTERVAL {A,B,C,D} = 4'b0001;
#INTERVAL {A,B,C,D} = 4'b0010;
#INTERVAL {A,B,C,D} = 4'b0011;
#INTERVAL {A,B,C,D} = 4'b0100;
#INTERVAL {A,B,C,D} = 4'b0101;
#INTERVAL {A,B,C,D} = 4'b0110;
#INTERVAL {A,B,C,D} = 4'b0111;
#INTERVAL {A,B,C,D} = 4'b1000;
#INTERVAL {A,B,C,D} = 4'b1001;
#INTERVAL {A,B,C,D} = 4'b1010;
#INTERVAL {A,B,C,D} = 4'b1011;
#INTERVAL {A,B,C,D} = 4'b1100;
#INTERVAL {A,B,C,D} = 4'b1101;
#INTERVAL {A,B,C,D} = 4'b1110;
#INTERVAL {A,B,C,D} = 4'b1111;
end
Combo_str c1(Y,A,B,C,D);
endmodule
仿真结果
12、闹钟设计
源代码
module clock(out,alarm,work,clk,rst);
input alarm,work,clk,rst;
output out;
reg out;
reg [2:0] cur_state,next_state;
parameter ASLEEP = 3'b001,
AWAKE = 3'b010,
RISE = 3'b100;
//更改当前状态
always @(posedge clk or posedge rst) begin
if (rst) begin
cur_state <= ASLEEP;
end else begin
cur_state <= next_state;
end
end
//输出
always @(cur_state or alarm) begin
if (cur_state == AWAKE) begin
out = 0;
end else begin
out = alarm?1:0;
end
end
//修改下一状态
always @(cur_state or alarm or work or rst) begin
if(rst)
next_state <= ASLEEP;
else begin
next_state = RISE;
case (cur_state)
ASLEEP: begin
next_state = alarm?AWAKE:ASLEEP;
end
AWAKE: begin
if (alarm) begin
next_state = AWAKE;
end else begin
next_state = work?RISE:ASLEEP;
end
end
RISE: begin
next_state = RISE;
end
endcase
end
end
endmodule
测试代码
module tb_clock;
reg alarm,work,clk,rst;
wire out;
parameter INTERVAL = 10;
initial begin
alarm = 0;
work = 0;
end
initial begin
clk = 0;
forever #(INTERVAL/2) clk = ~clk;
end
initial begin
//测试非工作日
#INTERVAL rst = 1;
#INTERVAL rst = 0;
#(INTERVAL*2) alarm = 1;
#(INTERVAL*2) alarm = 0;
//测试工作日
#INTERVAL work = 1;
#INTERVAL rst = 1;
#INTERVAL rst = 0;
#(INTERVAL*2) alarm = 1;
#(INTERVAL*2) alarm = 0;
#INTERVAL $finish;
end
clock c(.out(out),.alarm(alarm),.work(work),.clk(clk),.rst(rst));
endmodule