1.VL33 非整数倍数据位宽转换8to12
1.题目:
实现数据位宽转换电路,实现8bit数据输入转换为12bit数据输出。其中,先到的数据应置于输出的高bit位。
电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号。
2.解题思路
2.1 生成一个寄存器 存储数据,寄存器的大小应该要 大于 等于12。
2.2 8*3 == 12*2
2.3 第一个数据取8位 第二个数据取4位, 输出第一个信号, 第二个信号取后4位加上第三个数据,输出第二个信号。
3.解题代码
`timescale 1ns/1ns
module width_8to12(
input clk ,
input rst_n ,
input valid_in ,
input [7:0] data_in ,
output reg valid_out,
output reg [11:0] data_out
);
reg[23:0] data; // data buffer
reg[1:0] cnt; // counter
//本题时 1个时序题 采用 状态机 或者 提前模式
// 输入为 8为 输出 为12位 3*8 = 2*12;
//设置三个状态。
//控制数据
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
data <=0;
end
else
begin
if(valid_in == 1'b1)
begin
data <={data[15:0],data_in} ;
end
else
begin
data <=data;
end
end
end
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
cnt <= 0;
end
else
begin
if(cnt==2'd0 && valid_in==1'b1)
begin
cnt <= 2'd1;
end
else if(cnt == 2'd1 && valid_in == 1'b1)
begin
cnt <= 2'd2;
end
else if(cnt == 2'd2 && valid_in == 1'd1)
begin
cnt <=2'd0;
end
end
end
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
data_out <=0;
valid_out <=0;
end
else
begin
if(cnt == 2'd0)
begin
data_out <= data_out;
valid_out <=0;
end
else if(cnt == 2'd1 && valid_in == 1'd1)
begin
data_out <= {data[7:0],data_in[7:4]};
valid_out <=1;
end
else if(cnt == 2'd2 && valid_in == 1'd1)
begin
data_out <= {data[3:0],data_in[7:0]};
valid_out <=1;
end
else
begin
valid_out <=0;
end
end
end
endmodule
2.VL34 整数倍数据位宽转换8to16
1.题目:
实现数据位宽转换电路,实现8bit数据输入转换为16bit数据输出。其中,先到的8bit数据应置于输出16bit的高8位。
电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号。
2.解题思路
2.1 和上面那题差不多。
2.2 首先是 第一个 和第二个数据 合并之后输出 第一个信号。
3.解题代码
`timescale 1ns/1ns
module width_8to16(
input clk ,
input rst_n ,
input valid_in ,
input [7:0] data_in ,
output reg valid_out,
output reg [15:0] data_out
);
reg[23:0] data; // data buffer
reg[1:0] cnt; // counter
//本题时 1个时序题 采用 状态机 或者 提前模式
// 输入为 8为 输出 为12位 3*8 = 2*12;
//设置三个状态。
//控制数据
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
data <=0;
end
else
begin
if(valid_in == 1'b1)
begin
data <={data[15:0],data_in} ;
end
else
begin
data <=data;
end
end
end
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
cnt <= 0;
end
else
begin
if(cnt==2'd0 && valid_in==1'b1)
begin
cnt <= 2'd1;
end
else if(cnt == 2'd1 && valid_in == 1'b1)
begin
cnt <= 2'd0;
end
end
end
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
data_out <=0;
valid_out <=0;
end
else
begin
if(cnt == 2'd0)
begin
data_out <= data_out;
valid_out <=0;
end
else if(cnt == 2'd1 && valid_in == 1'd1)
begin
data_out <= {data[7:0],data_in[7:0]};
valid_out <=1;
end
else
begin
valid_out <=0;
end
end
end
endmodule
3.VL35 状态机-非重叠的序列检测
1.题目:
设计一个状态机,用来检测序列 10111,要求:
1、进行非重叠检测 即101110111 只会被检测通过一次
2、寄存器输出且同步输出结果
注意rst为低电平复位
2.解题思路
2.1状态机 的解题思路, 时序同步输出。
2.2 注意 存储空间 清除问题,因为是 非重叠。
3.解题代码
`timescale 1ns/1ns
module sequence_test1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
reg[4:0] data1;
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
flag <=0;
end
else
begin
if({data1[3:0],data} == 5'b10111)
begin
flag <=1;
data1 <= 5'd0;
end
else
begin
flag <=0;
data1 <= {data1[3:0],data};
end
end
end
//*************code***********//
endmodule
4.VL36 状态机-重叠序列检测
1.题目:
设计一个状态机,用来检测序列 1011,要求:
1、进行重叠检测 即10110111 会被检测通过2次
2、寄存器输出,在序列检测完成下一拍输出检测有效
注意rst为低电平复位
2.解题思路
2.1 这里为 重复检测,所以 存储数据的寄存器不需要清零。
2.1 这个的状态机,周期比同步周期 晚了一个时序
3.解题代码
`timescale 1ns/1ns
module sequence_test2(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
reg[4:0] data1;
always@(posedge clk or rst)
begin
if(~rst)
begin
data1 <=0;
end
else
begin
data1 <= {data1[3:0],data};
end
end
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
flag <=0;
end
else
begin
if(data1[3:0]== 4'b1011)
begin
flag <=1;
end
else
begin
flag <=0;
end
end
end
//*************code***********//
endmodule
5.VL37 时钟分频(偶数)
1.题目:
请使用D触发器设计一个同时输出2/4/8分频的50%占空比的时钟分频器
注意rst为低电平复位
2.解题思路
2.1 首先是 需要一个 记录时序此时 的 计数器。
2.2 就是注意时序是 同步的
2.3 注意这里的 输出类型是 wire 所以时使用 assign 持续赋值语句。
2.4 注意这个 的输出 先是 1 , 然后是 0.
3.解题代码
`timescale 1ns/1ns
module even_div
(
input wire rst ,
input wire clk_in,
output wire clk_out2,
output wire clk_out4,
output wire clk_out8
);
//*************code***********//
reg[2:0] cnt ;//计数器
always@(posedge clk_in or negedge rst)
begin
if(~rst)
begin
cnt <=3'b000;
end
else
begin
if(cnt == 3'd000)
begin
cnt <=3'b111;
end
else
begin
cnt <= cnt-1'b1;
end
end
end
assign clk_out2 = (cnt[0]);
assign clk_out4 = (cnt[1]);
assign clk_out8 = (cnt[2]);
//*************code***********//
endmodule
6.VL38 自动贩售机1
1.题目:
设计一个自动贩售机,输入货币有三种,为0.5/1/2元,饮料价格是1.5元,要求进行找零,找零只会支付0.5元。
ps:投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号
注意rst为低电平复位
2.解题思路
2.1 首先是 当零钱的数额大于等于 饮料的价格 时输出 信号。
2.2 注意找零使用 0.5 元, 所以我们的把价格计录成 0.5 的个数就行了。
2.3 记得 零钱的数目清零。 因为找零了。
3.解题代码
`timescale 1ns/1ns
module seller1(
input wire clk ,
input wire rst ,
input wire d1 ,
input wire d2 ,
input wire d3 ,
output reg out1,
output reg [1:0]out2
);
//*************code***********//
reg[3:0] data;//0.5 的个数
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
data <=0;
end
else
begin
if(d1 == 1'b1)
begin
data <= data+1'b1;
end
else if(d2 == 1'b1)
begin
data <= data + 4'd2;
end
else if(d3 == 1'b1)
begin
data <= data + 4'd4;
end
end
end
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
out1<=0;
out2<=0;
end
else
begin
if(data >= 4'd3)
begin
out1<=1;
out2<=data - 4'd3;
data<=0;
end
else
begin
out1<=0;
out2<=0;
end
end
end
//*************code***********//
endmodule
7.VL39 自动贩售机2
1.题目:
设计一个自动贩售机,输入货币有两种,为0.5/1元,饮料价格是1.5/2.5元,要求进行找零,找零只会支付0.5元。
ps: 1、投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号
2、此题忽略出饮料后才能切换饮料的问题
注意rst为低电平复位
信号的示意 :
d1 0.5
d2 1
sel 选择饮料
out1 饮料1
out2 饮料2
out3 零钱
2.解题思路
2.1 首先是 当零钱的数额大于等于 饮料的价格 时输出 信号。
2.2 注意找零使用 0.5 元, 所以我们的把价格计录成 0.5 的个数就行了。
2.3 记得 零钱的数目清零。 因为找零了。
2.4 注意又两种 饮料,所以要判断当时是 买那种饮料。
3.解题代码
`timescale 1ns/1ns
module seller2(
input wire clk ,
input wire rst ,
input wire d1 ,
input wire d2 ,
input wire sel ,
output reg out1,
output reg out2,
output reg out3
);
//*************code***********//
reg[3:0] data;
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
data <=0;
end
else
begin
if(d1 == 1'b1)
begin
data <= data + 4'd1;
end
else if(d2== 1'd1)
begin
data <= data +4'd2;
end
else
begin
data <=data;
end
end
end
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
out1<=0;
out2<=0;
out3<=0;
end
else
begin
if(sel == 1'b0)
begin
if(data >= 4'd3)
begin
out1<=1;
out2<=0;
out3<=(data - 4'd3);
data<=0;
end
else
begin
out1<=0;
out2<=0;
out3<=0;
end
end
else if(sel == 1'b1)
begin
if(data >= 4'd5)
begin
out1<=0;
out2<=1;
out3<=(data - 4'd5);
data<=0;
end
else
begin
out1<=0;
out2<=0;
out3<=0;
end
end
end
end
//*************code***********//
endmodule
8.VL40 占空比50%的奇数分频
1.题目:
设计一个同时输出7分频的时钟分频器,占空比要求为50%
注意rst为低电平复位
2.解题思路
2.1 把他计数成 14 的 ,每 7 个计数, 输出信号变化 。
2.2 输出信号首先 是0 .
2.3 注意输出的信号 的类型是 wire 只能使用 assign 持续赋值。
2.4 同时输出 7个分频哦,
3.解题代码
`timescale 1ns/1ns
module odo_div_or
(
input wire rst ,
input wire clk_in,
output wire clk_out7
);
//*************code***********//
reg[3:0] cnt; //counter
always@(posedge clk_in or negedge rst or negedge clk_in)
begin
if(~rst)
begin
cnt <=0;
end
else
begin
if(cnt == 4'd13)
begin
cnt <=0 ;
end
else
begin
cnt <= cnt + 1;
end
end
end
assign clk_out7 = (cnt>=7) ? 1 : 0;
//*************code***********//
endmodule
9.VL41 任意小数分频
1.题目:
请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号
注意rst为低电平复位
提示:
其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。
设小数为nn,此处以8.7倍分频的时钟周期为例。
首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53个clkout时钟周期是10个clkin时钟周期的8.7倍。
2.解题思路
2.1 一个分频就是一个周期 所以 这里是 8 个时钟的周期, 或者 9个时钟的周期。
2.2 给了提示, 前三个是 8分频, 后几个 是 9分频。
2.3 注意是 输出信号的周期 晚一个时间节点。
2.4 注意一个 输出信号的类型为 wire .
3.解题代码
`timescale 1ns/1ns
module div_M_N(
input wire clk_in,
input wire rst,
output wire clk_out
);
parameter M_N = 8'd87;
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
reg[7:0] cnt; //counter
reg clk_out1;
always@(posedge clk_in or negedge rst )
begin
if(~rst)
begin
cnt <=0;
end
else
begin
if(cnt == 8'd86)
begin
cnt <=0;
end
else
begin
cnt <= cnt +1;
end
end
end
always@(posedge clk_in or negedge rst)
begin
if(~rst)
begin
clk_out1 <=0;
end
else
begin
case(cnt)
8'd0 : clk_out1 <= ~clk_out1;
8'd4 : clk_out1 <= ~clk_out1;
8'd8 : clk_out1 <= ~clk_out1;
8'd12: clk_out1 <= ~clk_out1;
8'd16: clk_out1 <= ~clk_out1;
8'd20: clk_out1 <= ~clk_out1;
8'd24: clk_out1 <= ~clk_out1;
8'd28: clk_out1 <= ~clk_out1;
8'd33: clk_out1 <= ~clk_out1;
8'd37: clk_out1 <= ~clk_out1;
8'd42: clk_out1 <= ~clk_out1;
8'd46: clk_out1 <= ~clk_out1;
8'd51: clk_out1 <= ~clk_out1;
8'd55: clk_out1 <= ~clk_out1;
8'd60: clk_out1 <= ~clk_out1;
8'd64: clk_out1 <= ~clk_out1;
8'd69: clk_out1 <= ~clk_out1;
8'd73: clk_out1 <= ~clk_out1;
8'd78: clk_out1 <= ~clk_out1;
8'd82: clk_out1 <= ~clk_out1;
//'d86: clk_out1 <= ~clk_out1;
default : clk_out1 <= clk_out1;
endcase
end
end
assign clk_out = clk_out1;
//*************code***********//
endmodule
10.VL42 无占空比要去的奇数分频
1.0题目:
请设计一个同时输出5分频的时钟分频器,本题对占空比没有要求
注意rst为低电平复位
2.解题思路
2.1 计数 器, 每5 个计数 转换输出信号, 只能计数 上升沿,所以第一个变换的时候是在 cnt =0 的时候,第二个是在 cnt = 2 的时候。
3.解题代码
`timescale 1ns/1ns
module odd_div (
input wire rst ,
input wire clk_in,
output wire clk_out5
);
//*************code***********//
reg[3:0] cnt ;// counter
reg out;
always@(posedge clk_in or negedge rst)
begin
if(~rst)
begin
cnt <=0;
end
else
begin
if(cnt == 3'd4)
begin
cnt <=0;
end
else
begin
cnt <= cnt +1;
end
end
end
always@(posedge clk_in or negedge rst)
begin
if(~rst)
begin
out <=0;
end
else
begin
if(cnt == 3'd0)
begin
out <= ~out;
end
else if(cnt == 3'd2)
begin
out <= ~out;
end
else
begin
out <= out;
end
end
end
assign clk_out5 = out;
//*************code***********//
endmodule
11. VL43 根据状态转移写状态机-三段式
1.题目
如图所示为两种状态机中的一种,请根据状态转移图写出代码,状态转移线上的0/0等表示的意思是过程中data/flag的值。
要求:
1、 必须使用对应类型的状态机
2、 使用三段式描述方法,输出判断要求要用到对现态的判断
2.解题思路
2.1 三段式状态机
3.解题代码
`timescale 1ns/1ns
module fsm1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
parameter s0 = 2'd00,
s1 = 2'd01,
s2 = 2'd10,
s3 = 2'd11;
reg[1:0] nextstate,cstate;
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
cstate <= s0;
end
else
begin
cstate <= nextstate;
end
end
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
nextstate <=s1;
end
else
begin
if(nextstate == s0)
begin
nextstate <=data ? s1:s0;
end
else if(nextstate ==s1)
begin
nextstate <=data ? s2:s1;
end
else if(nextstate == s2)
begin
nextstate <=data ? s3:s2;
end
else if(nextstate == s3)
begin
nextstate <=data ? s0:s3;
end
end
end
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
flag <=0;
end
else
begin
if(cstate == s3 && data ==1'd1)
begin
flag <=1;
end
else
begin
flag <=0;
end
end
end
//*************code***********//
endmodule
12.VL44 根据状态转移写状态机-二段式
1.题目:
如图所示为两种状态机中的一种,请根据状态转移图写出代码,状态转移线上的0/0等表示的意思是过程中data/flag的值。
要求:
1、 必须使用对应类型的状态机
2、 使用二段式描述方法
2.解题思路
2.1.注意三段机 与 二段机的差别 。
2.2 三段机的次态 的下一个状态 等于 data 和 上一个次态。
2.3 二段机的次态 的下一个状态 等于 data 和 上一个现态。
3.解题代码
`timescale 1ns/1ns
module fsm2(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
parameter s0 = 3'd0,
s1 = 3'd1,
s2 = 3'd2,
s3 = 3'd3,
s4 = 3'd4;
reg[2:0] nextstate,cstate;
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
cstate <= s0;
end
else
begin
cstate <= nextstate;
end
end
always@(*)//因为是根据现态来的, 所以是 用的 * , 上升沿在 cstate变化 的时候可能没有用,
begin //我们这里是要在 cstate 变化之后运行
case(cstate)
s0:begin
nextstate = data ? s1 : s0;
flag = 1'b0;
end
s1:begin
nextstate = data ? s2 : s1;
flag = 1'b0;
end
s2:begin
nextstate = data ? s3 : s2;
flag = 1'b0;
end
s3:begin
nextstate = data ? s4 : s3;
flag = 1'b0;
end
s4:begin
nextstate = data ? s1 : s0;
flag = 1'b1;
end
default:begin
nextstate = s0;
flag = 1'b0;
end
endcase
end
//*************code***********//
endmodule