目录
零、常撕题目
1、串并转换
题目描述:
设计一个模块进行并串转换,要求每四位d输为转到一位dout输出,输出valid_in表示此时的输入有效
波形示意图:
clk为时钟
rst为低电平复位
d 信号输入
dout 信号输出
valid_in 表示输入有效
`timescale 1ns/1ns
module huawei5(
input wire clk ,
input wire rst ,
input wire [3:0]d ,
output wire valid_in ,
output wire dout
);
//*************code***********//
reg [1:0] cnt;
reg vld_reg;
reg [3:0] data_reg;
always @(posedge clk or negedge rst)
if(!rst)
cnt <= 2'h0;
else
cnt <= cnt + 1'h1;
always @(posedge clk or negedge rst)
if(!rst)begin
vld_reg <= 1'b0;
data_reg <= 4'h0;
end
else if(cnt == 2'h3)begin
vld_reg <= 1'b1;
data_reg <= d[3:0];
end
else begin
vld_reg <= 1'b0;
data_reg <= data_reg << 1'b1;
end
assign valid_in = vld_reg;
assign dout = data_reg[3];
串并转换操作是非常灵活的操作,核心思想就是移位。串转并就是把1位的输入放到N位reg的最低位,然后N位reg左移一位,在把1位输入放到左移后的reg的最低位,这样循环,就可以得到,以最高位开始传输,最低位传输完成的N位数据了;并转串就是把并行的N位数据的最高位给1位输出,然后类似的循环左移就可以了。
2、时钟无毛刺切换
题目描述:
存在两个同步的倍频时钟clk0 clk1,已知clk0是clk1的二倍频,现在要设计一个切换电路,sel选择时候进行切换,要求没有毛刺。
信号示意图:
波形示意图:
clk0 clk1为时钟
rst为低电平复位
sel 是时钟选择器
clk_out 信号输出
`timescale 1ns/1ns
module huawei6(
input wire clk0 ,
input wire clk1 ,
input wire rst ,
input wire sel ,
output reg clk_out
);
//*************code***********//
reg sel1,sel0;
always@(negedge clk1 or rst)
if(!rst)
sel1 <= 0;
else
sel1 <= !sel0 && sel;
always@(negedge clk0 or rst)
if(!rst)
sel0 <= 0;
else
sel0 <= !sel1 && !sel;
always@(*)
clk_out = (sel1 & clk1) | (sel0 & clk0);
//*************code***********//
endmodule
在两个电平相反的时候切换时钟,肯定有毛刺;电平相同的时候,即使不产生毛刺,时钟切换后的第一个时钟的周期或占空比也不是理想的。所以,为避免毛刺的产生,需要在两个时钟都为低电平的时候进行时钟切换。
一种典型的时钟切换电路如下所示。
该电路利用时钟下降沿对时钟选择信号 sel_clk1 进行缓存。同时一个时钟选择信号对另一个时钟进行反馈控制,保证同一时刻只能有一路时钟有效。最后采用"或操作"将两路时钟合并,完成时钟切换的过程。
使用的是负边沿触发的D触发器。这是为了确保在切换时钟源时,即使时钟正处在高电平,也不会影响输出变化
考虑到选择信号有可能是异步信号,在选择路径上再插入一个上升沿触发D触发器,这是为了针对对两个异步时钟源产生的反馈信号以及异步信号SELECT,对选择信号进行同步处理,这样即使是两个异步的时钟源进行切换,也可以避免亚稳态的产生。
reg out_r1;
reg out1;
reg out_r0;
reg out0;
always @(posedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out_r1 <= 0;
end
else begin
out_r1 <= ~out0 & select;
end
end
always @(negedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out1 <= 0;
end
else begin
out1 <= out_r1;
end
end
always @(posedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out_r0 <= 0;
end
else begin
out_r0 <= ~select & ~out1;
end
end
always @(negedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out0 <= 0;
end
else begin
out0 <= out_r0;
end
end
assign outclk = (out1 & clk1) | (out0 & clk0);
一、信号部分比特位选择
1、变量选择信号单个比特位
Create a 1-bit wide, 256-to-1 multiplexer. The 256 inputs are all packed into a single 256-bit input vector. sel=0 should select in[0], sel=1 selects bits in[1], sel=2 selects bits in[2], etc.
module top_module(
input [255:0] in,
input [7:0] sel,
output out );
assign out = in[sel[7:0]];//in[sel[7:0]:sel[7:0]]的写法会报错
Endmodule
2、变量选择信号多个比特位
Create a 4-bit wide, 256-to-1 multiplexer. The 256 4-bit inputs are all packed into a single 1024-bit input vector. sel=0 should select bits in[3:0], sel=1 selects bits in[7:4], sel=2 selects bits in[11:8], etc.
in[sel*4 +: 4];//表示从sel*4起,选择比特序号大于sel*4 的 4 位比特,相当于[sel*4+3:sel*4];
module top_module(
input [1023:0] in,
input [7:0] sel,
output [3:0] out );
assign out[3:0] = in[sel*4 +: 4];//表示从sel*4起,选择比特序号大于sel*4 的 4 位比特,相当于[sel*4+3:sel*4];
endmodule
二、加法器
2.1 进位产生与结果计算
Create a full adder. A full adder adds three bits (including carry-in) and produces a sum and carry-out.
用 assign {cout,sum}= a+b+cin; 的形式同时计算进位和结果,写法巧妙值得借鉴。
module top_module(
input a, b, cin,
output cout, sum );
assign {cout,sum}= a+b+cin; //写法巧妙
endmodule
Assume that you have two 8-bit 2's complement numbers, a[7:0] and b[7:0]. These numbers are added to produce s[7:0]. Also compute whether a (signed) overflow has occurred.
module top_module (
input [7:0] a,
input [7:0] b,
output [7:0] s,
output overflow
); //
assign s = a[7:0] + b[7:0];
assign overflow = (a[7]==b[7]) && (a[7] != s[7]);
endmodule
补码加法运算溢出判断的方法:
- [方法一]
Xf、Yf分别两个数的符号位,Zf为运算结果符号位。
当Xf =Yf =0(两数同为正),而Zf=1(结果为负)时,负溢出;
当出现Xf =Yf =1(两数同为负),而Zf=0(结果为正),正溢出. - [方法二]
Cs表示符号位的进位,Cp表示最高数值位进位,⊕表示异或。
若 Cs⊕Cp =0 ,无溢出;
若 Cs⊕Cp =1 ,有溢出。
2.2 半加器实现全加器
①第一个半加器:先将A和B用加起来,生成和是s[0]和进位信号c[0];
②第二个半加器:第一个半加器生成的和s[0]与Ci用半加器相加,得到的和s[1]即为全加器的和S;
③全加器进位信号的生成是这样:两次半加器产生的进位信号有一个为1,则全加器的进位信号Co为1。
add_half add_half1 (A , B , s_tmp ,c_tmp);
add_half add_half2 (s_tmp , Ci , S ,c_tmp2);
assign Co = c_tmp|| c_tmp2;
2.3 串行进位加法器
用半加器搭建全加器,然后例化多个全加器实现串行进位加法器。
半加器:结果=a^b 进位=a&b
三、卡诺图化简
Implement the circuit described by the Karnaugh map below.
Try to simplify the k-map before coding it. Try both product-of-sums and sum-of-products forms. We can't check whether you have the optimal simplification of the