实现数据位宽转换电路,实现8bit数据输入转换为12bit数据输出。其中,先到的数据应置于输出的高bit位。
电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号。
2.1 生成一个寄存器 存储数据,寄存器的大小应该要 大于 等于12。
2.2 8*3 == 12*2
2.3 第一个数据取8位 第二个数据取4位, 输出第一个信号, 第二个信号取后4位加上第三个数据,输出第二个信号。
`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
实现数据位宽转换电路,实现8bit数据输入转换为16bit数据输出。其中,先到的8bit数据应置于输出16bit的高8位。
电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号。
2.1 和上面那题差不多。
2.2 首先是 第一个 和第二个数据 合并之后输出 第一个信号。
`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
设计一个状态机,用来检测序列 10111,要求:
1、进行非重叠检测 即101110111 只会被检测通过一次
2、寄存器输出且同步输出结果
注意rst为低电平复位
2.1状态机 的解题思路, 时序同步输出。
2.2 注意 存储空间 清除问题,因为是 非重叠。
`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
1.题目:
设计一个状态机,用来检测序列 1011,要求:
1、进行重叠检测 即10110111 会被检测通过2次
2、寄存器输出,在序列检测完成下一拍输出检测有效
注意rst为低电平复位
2.1 这里为 重复检测,所以 存储数据的寄存器不需要清零。
2.1 这个的状态机,周期比同步周期 晚了一个时序
`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
请使用D触发器设计一个同时输出2/4/8分频的50%占空比的时钟分频器
注意rst为低电平复位
2.1 首先是 需要一个 记录时序此时 的 计数器。
2.2 就是注意时序是 同步的
2.3 注意这里的 输出类型是 wire 所以时使用 assign 持续赋值语句。
2.4 注意这个 的输出 先是 1 , 然后是 0.
`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
设计一个自动贩售机,输入货币有三种,为0.5/1/2元,饮料价格是1.5元,要求进行找零,找零只会支付0.5元。
ps:投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号
注意rst为低电平复位
2.1 首先是 当零钱的数额大于等于 饮料的价格 时输出 信号。
2.2 注意找零使用 0.5 元, 所以我们的把价格计录成 0.5 的个数就行了。
2.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
设计一个自动贩售机,输入货币有两种,为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.1 首先是 当零钱的数额大于等于 饮料的价格 时输出 信号。
2.2 注意找零使用 0.5 元, 所以我们的把价格计录成 0.5 的个数就行了。
2.3 记得 零钱的数目清零。 因为找零了。
2.4 注意又两种 饮料,所以要判断当时是 买那种饮料。
`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
设计一个同时输出7分频的时钟分频器,占空比要求为50%
注意rst为低电平复位
2.1 把他计数成 14 的 ,每 7 个计数, 输出信号变化 。
2.2 输出信号首先 是0 .
2.3 注意输出的信号 的类型是 wire 只能使用 assign 持续赋值。
2.4 同时输出 7个分频哦,
`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
请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号
注意rst为低电平复位
提示:
其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。
设小数为nn,此处以8.7倍分频的时钟周期为例。
首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53个clkout时钟周期是10个clkin时钟周期的8.7倍。
2.1 一个分频就是一个周期 所以 这里是 8 个时钟的周期, 或者 9个时钟的周期。
2.2 给了提示, 前三个是 8分频, 后几个 是 9分频。
2.3 注意是 输出信号的周期 晚一个时间节点。
2.4 注意一个 输出信号的类型为 wire .
`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
请设计一个同时输出5分频的时钟分频器,本题对占空比没有要求
注意rst为低电平复位
2.1 计数 器, 每5 个计数 转换输出信号, 只能计数 上升沿,所以第一个变换的时候是在 cnt =0 的时候,第二个是在 cnt = 2 的时候。
`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
如图所示为两种状态机中的一种,请根据状态转移图写出代码,状态转移线上的0/0等表示的意思是过程中data/flag的值。
要求:
1、 必须使用对应类型的状态机
2、 使用三段式描述方法,输出判断要求要用到对现态的判断
2.1 三段式状态机
`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
如图所示为两种状态机中的一种,请根据状态转移图写出代码,状态转移线上的0/0等表示的意思是过程中data/flag的值。
要求:
1、 必须使用对应类型的状态机
2、 使用二段式描述方法
2.2 三段机的次态 的下一个状态 等于 data 和 上一个次态。
2.3 二段机的次态 的下一个状态 等于 data 和 上一个现态。
`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