1,在前面的电路中,寄存器输出端 q 在每个时钟的上升沿都会更新一次,但有时候我们可能需要使输出端保持不变,这时就需要加入使能信号,创建一 16bit 位宽(2byte)的寄存器,其中每字节都由一个使能信号控制,使能为 0 时,输出保持不变,使能为 1 时更新 q。时钟上升沿触发,同步复位,复位低电平有效,复位值为 0。
module top_module(
input clk,
input resetn,
input [1:0] byteena,
input [15:0] d,
output reg [15:0] q
);
// Write your code here
always@(posedge clk)
begin
if(~resetn)
q <= 0;
else
case(byteena)
2'b11:q <= d;
2'b10:q[15:8] <= d[15:8];
2'b01:q[7:0] <= d[7:0];
default:q <= q;
endcase
end
endmodule
2,编写Verilog代码,实现下图所示的电路功能,假设所有D触发器的初始复位值为0
module top_module (
input clk,
input x,
output z
);
reg q1,q2,q3;
initial
begin
q1 = 0;
q2 = 0;
q3 =0;
end
always@(posedge clk)
begin
q1 <= q1 ^ x;
q2 <= (~q2) & x;
q3 <= (~q3) | x;
end
assign z = ~(q1 ^ q2 ^ q3);
endmodule
3,在实际应用中,我们经常需要对某个信号的边沿进行检测,并以此作为后续动作的触发信号(例如电脑键盘的某个按键被按下或者被松开,在电路中则对应的是电平的变化)。
设计一个电路,包含clk信号、1bit输入信号in和1bit输出信号out,当in信号从0变为1时(相对于clk,该信号变化频率很慢),out信号在in信号上升沿附近输出1个时钟周期的高电平脉冲,其余时刻都为0
module top_module (
input clk,
input in,
output out
);
reg q1,q2;
assign out = q1 & ~q2;
initial
begin
q1 = 0;
q2 = 0;
end
always@(posedge clk)
begin
q2 <= q1;
q1 <= in;
end
endmodule
4,根据上升沿检测的思路,设计一双边沿检测电路,即在输入信号的上升沿和下降沿附近时刻,各输出一个高电平脉冲,如下图所示
module top_module (
input clk,
input in,
output out
);
reg q1,q2;
always@(posedge clk)
begin
q2 <= q1;
q1 <= in;
end
assign out = (q1 & ~q2)|(~q1 & q2);
endmodule
5,构建一个4位移位寄存器(右移),具有异步复位、同步加载和启用功能。
areset:将移位寄存器重置为零。
load:用数据[3:0]加载移位寄存器,而不是移位。
ena:右移(q[3]变为零,q[0]移出并消失)。
q:移位寄存器的内容。
* 如果load和ena输入同时有效,则load输入具有更高的优先级。
module top_module(
input clk,
input areset, //异步、高有效、复位值为0
input load,
input ena,
input [3:0] data,
output reg [3:0] q);
//Write your code here
reg [1:0]s;
always@(posedge clk or negedge areset)
begin
s <= {load,ena};
if(areset)
q <= 0;
else
case(s)
2'b11:q <= data;
2'b10:q <= data;
default:q[3:0] <= {1'b0,q[3:1]};
endcase
end
endmodule
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 or posedge areset)begin
if(areset)begin
q <= 4'b0;
end
else if(load)begin
q <= data;
end
else if(ena)begin
q <= {1'b0,q[3:1]};
end
else
q <= q;
end
endmodule
第一段代码会延迟一个时钟周期,想一想为什么
6,创建一带有使能信号的递减计数器,当使能信号有效(高电平)时,从15到5循环递减计数,每个周期减1,使能信号无效时,计数值保持不变,电路采用同步复位方式,高电平有效,复位值为5
module top_module(
input clk,
input reset,
input en,
output reg [3:0]q);
always@(posedge clk)
begin
if(reset)
q <= 4'b0101;
else
if(en)
if(q <= 4'b0101)
q <= 4'b1111;
else
q <= q - 1;
end
endmodule
7,下图是摩尔型有限状态机的结构图,我们可以发现其包含三个部分,第一部分为纯组合逻辑,通过现态和输入信号生成次态信号,第二部分为时序逻辑,该时序逻辑非常简单,只包含一个带有复位功能的寄存器单元,复位时现态信号变为初始值,否则在每个时钟的上升沿将次态信号赋值给现态信号。第三部分为组合逻辑,该部分通过现态信号生成各输出信号。
module top_module(
input clk,
input areset,
input in,
output out);
parameter A=1'b0, B=1'b1;
reg state, next_state;
always @(*)
begin
if(in)
next_state = state;
else
begin
case(state)
A:next_state = B;
B:next_state = A;
default:next_state = B;
endcase
end
end
always @(posedge clk, posedge areset)
begin
if(areset)
state <= B;
else
state <= next_state;
end
assign out = (state == B)? 1'b1 : 1'b0;
endmodule
8,给定被测试模块dut,其verilog代码如下:
module dut(input clk, output reg [2:0]out);
//测试模块
always @(posedge clk)
out <= out + 1'b1;
endmodule
请编写仿真文件,对该模块进行仿真(dut模块可直接调用,不需要用户编写),clk信号应符合以下波形:
module tb();
wire [2:0]out;//必要输出信号
//信号定义
reg clk;
parameter clk_period = 10;
//信号生成
initial begin
clk = 0;
forever
#(clk_period/2) clk = ~clk;
end
//模块例化
dut dut1(clk,out);
endmodule
module dut(input clk, output reg [2:0]out);
//测试模块
always @(posedge clk)
out <= out + 1'b1;
endmodule
9,在RV32I中,寄存器堆指32个通用寄存器的集合,具有专门的读写端口,可并发访问不同寄存器。
module top_module(
input clk,
input [4:0] A1,A2,A3,
input [31:0] WD,
input WE,
output [31:0] RD1,RD2
);
reg [31:0] reg_file[0:31];
//初始化寄存器堆
integer i;
initial
begin
for(i=0;i<32;i=i+1) reg_file[i] = 0;
end
//写入寄存器
always@(posedge clk)
begin
if(WE&A3!=5'd0)
reg_file[A3] <= WD;
end
//读取寄存器
assign RD1 = reg_file[A1];
assign RD2 = reg_file[A2];
endmodule
这里注意第0个寄存器为只读寄存器。
本文含有隐藏内容,请 开通VIP 后查看