①锁存器
我们定义:
①Q = 1,且Q’ = 0 为锁存器的1状态
②Q = 0,且Q’ = 1 为锁存器的0状态
③Q为现在的状态,Q*为下一个状态,Q’为Q反
其真值表及功能如下:
②触发器
触发器与锁存器的不同在于,它除了置1置0输人端以外,又加了一个触发信号输入,只有当触发信号到来时,触发器才能按照输人的置1、置0信号置成相应的状态,并保持下去,我们将这个触发信号称为时钟信号,记作CLK。
下面讲讲触发器的几种类型:
在D触发器中,为了保证触发器有效的翻转,在clk改变前FF1中的Q1的状态必须稳定的建立起来,使得Q1 = D;而这个先来的时间就叫做建立时间;至少 tsu = 2 td 。
①从触发器DFF1到DFF2,Tco为触发器内部延时,Tcmb为组合逻辑延时,在D2处还有需要满足建立时间Tset
②这里有两条路劲,一个是数据路径data_path,一个则是时钟路径timing_path
③为满足建立时间,data_path需要比timing_path跑得更快因此有:
Tco + Tcmb + Tset < clk2 - clk1 = T
④这是在没有时钟偏移Tskew下的不等式,而考虑悲观的Tskew,则data_path需要更前的时间到来,有:
Tco + Tcmb + Tset < T - Tskew
⑤在上面的式子中,Tco 和Tset 以及Tskew都是不能再改变的了,因此能改变的只剩下了Tcmb 和T ,这也是为什么T越大,越能满足建立时间的原因
⑥我们把式子移一下 Tcmb < T - Tskew - Tco - Tset ,综合工具做的逻辑优化就是优化这个Tcmb ,使得Tcmb 满足式子
②对于保持时间违例,可以采用以下方法:
1)插buffer,使得组合逻辑延时增大
2)调整Tskew,使得其对保持时间是有利的
以下参考崽象肚里能撑船的文章:CDC的部分内容
假设数据由clk1传向clk2
①单bit传输时,同步时钟域因为频率和相位关系都是已知的,可以推导,所以不需要采用额外的硬件电路就可以解决CDC问题,只需要源数据在clk1端保持足够长时间即可。
让其保持足够长时间有两个好处:即便出现亚稳态,也可以在两个clk2时钟周期后数据变得稳定下来,从而采到正确的结果;还可以防止低频采高频时,因为频率跟不上而导致数据丢失。
②单bit传输时,异步时钟域的传输就必须使用额外的电路模块(同步器)来保证数据正确的传输。最基本的同步器是双锁存结构的电平同步器,其余的同步器都是由其衍生而来。该同步器的基本原理,也是让数据至少在clk2的时钟下保存两个周期,消除亚稳态。当然同步器能解决异步时钟域的同步问题,自然也可以拿来解决同步时钟域的问题,毕竟同步时钟域更简单一些。
③实际的电路设计中,不用管那么多细节,不管是同步时钟域还是异步时钟域,只要是不同的时钟之间传数据,就加上同步器的结构,这当然是一种偷懒的解决办法。脉冲同步器就是这么一种万能的结构,对于单bit跨时钟域传输而言,使用脉冲同步器就够了,不需要区分时钟有没有关系,也不需要区分是高频采低频还是低频采高频,毕竟也很少有人能掌握这么全的细节
④对于多bit传输,不能采用单bit传输的方法。原因在于,单bit传输时,不能确定该数据到底经过1个clk2时钟周期之后有效还是两个clk2时钟周期之后才有效。所以对多个bit各自采用单bit的同步机制,会导致输出一些错误的中间状态。对于多bit传输,可以使用握手信号或者异步fifo
⑤异步fifo这里不做多少,手撕代码的时候自然见分晓
⑥握手:保持寄存器+握手信号,也就是先异步暂存,后同步写入。所谓握手,就是通信双方使用了专门控制信号进行状态指示,这些控制信号是双向的。(在边缘检测的综合项目中有用到,用于数据对齐)
⑦DMUX方法
多路选择器+触发器实现,MUX相当于触发器的使能信号,当两个时钟域同步时,打开使能接收数据
基于CMOS管的低功耗分析
首先功耗来源于两个大部分:动态和静态
动态:又分为开关功耗和短路功耗
短路功耗:在翻转的过程中,存在一段很短的时间t,使得CMOS正负导通,形成电流,叫做短路功耗,这也就是为什么沿变得快的时钟可以降低功耗的道理
那么动态功耗的公式为:
其中:
CL ------电路总负载电容
Vdd ------工作电压
Ptran------工作电路所占比例
F------工作时钟频率
ttran------上下MOS管同时导通时间
Ipeak------短路电流
而静态功耗则是MOS管上的漏电功耗,相对于动态功耗来说差了几个数量级
降低功耗的方法:
①clock gating 门控时钟 ,在时钟端加一个使能
②power gating ,控制电源的关断
③再非关键的路径用HVT,高阈值电压,使得漏电流更小(这个可以在时序要求比较宽松的时候用)
④DVFS,动态电压频率调节
注意:有竞争不一定产生尖峰脉冲,只有在存在不同步的跳变时,某输入先跳变而另一输入还未跳变时产生尖峰脉冲。
1. 项目需求
包括:
①工艺、面积、封装
②频率、功耗
③功能、接口
2. 前端设计
3.后端设计
举个例子:
①数字 5
原码:00000101
反码:00000101
补码:00000101
②数字 -5
原码:10000101
反码:11111010
补码:11111011
注意:符号位是不用变的
格雷码:在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码
如2位的格雷码:
00
01
11
10
独热码:独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效
如3状态的状态机采用的独热码:
S0=3'b001
S1=3'b010
S2=3'b100
格雷码的优缺:格雷码属于可靠性编码,是一种错误最小化的编码方式;比如十进制的3转换到4时二进制码的每一位都要变,使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它在任意两个相邻的数之间转换时,只有一个数位发生变化;但是格雷码编码使用最少的触发器,消耗较多的组合逻辑
独热码的优缺:独热码编码的最大优势在于状态比较时仅仅需要比较一个位,从而一定程度上简化了译码逻辑;虽然在需要表示同样的状态数时,独热编码占用较多的位,也就是消耗较多的触发器,但这些额外触发器占用的面积可与译码电路省下来的面积相抵消,也就是说组合逻辑用的少了,但是触发器用的多了
格雷码与二进制码的转化:
①二进制转格雷码:二进制码整体右移一位,然后与二进制码本身进行异或,得到该二进制码对应的格雷码
assign gray = (bin >>1) ^ bin;
②格雷码转二进制:最高位相同,二进制码的最高位与格雷码的次高位相异或
assign bin[N-1] = gray[N-1]; //最高位相同
genvar i;
generate
for(i = N-2; i >= 0; i = i - 1) begin: gray2bin
assign bin[i] = bin[i + 1] ^ gray[i];
end
endgenerate
101转成二进制就不用多说了,短除法,度数从下往上读,看下图:非小数部分则为1100101
而小数部分则是 x2 取整处理,然后小数部分继续x2
因此答案是1100101.01
第一级:
第二级:
第三级:
第四级:
第五级:
第六级:
第七级:
第八级:
之后逐级降低优先级:
第十五级:
第十六级:
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)
(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽
,input [WIDTH-1:0] wdata
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr
,output reg [WIDTH-1:0] rdata
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
①给到ram的地址waddr、raddr ,位宽是ADDR_WIDTH-1
②二进制计数地址waddr_bin、raddr_bin,位宽拓展一位,为ADDR_WIDTH,方便用来判断空满
③由二进制计数地址转化的格雷码地址waddr_gray、raddr_gray,用来进行跨时钟处理
④有格雷码地址打两拍的地址waddr_gray_ff1、raddr_gray_ff1,用来进行跨时钟处理
⑤由打完两拍的格雷码地址再转化而成的同步后的二进制地址waddr_gray2bin、raddr_gray2bin,用来进行fifo空满的判断
由fifo的空满决定读写使能
①读空判断:读地址和写地址一样时,则为读空
②写满判断:因为扩展了一位,所以最高位为1时表示读写地址刚好相差一圈,这时就是写满的时候;见下表,假设深度为8,那么扩展后是4位;从data1再次写到data1时,则为写满,从data2再次写到data2时,也为写满,以此类推;很明显写满的时候,最高位相反,其他位一样,也就是上面说的正好相差一圈,用代码表示就是:
assign wfull = (waddr == {~raddr[3],raddr[2:0]});
总结:fifo的设计要点就是 存数据的ram + 格雷码打两拍跨时钟 + fifo的空满判断
代码:
`timescale 1ns/1ns
/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
,input [WIDTH-1:0] wdata //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/***************************************AFIFO*****************************************/
module asyn_fifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input wclk ,
input rclk ,
input wrstn ,
input rrstn ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output wire wfull ,
output wire rempty ,
output wire [WIDTH-1:0] rdata
);
parameter ADDR_WIDTH = $clog2(DEPTH);
//internal sig
//二进制扩展移位的读写地址
reg [ADDR_WIDTH:0] waddr_bin;
reg [ADDR_WIDTH:0] raddr_bin;
//二进制打1拍 与 后面跨时钟后生成的二进制对齐
reg [ADDR_WIDTH:0] waddr_bin_ff0;
reg [ADDR_WIDTH:0] raddr_bin_ff0;
//格雷码扩展一位的读写地址
reg [ADDR_WIDTH:0] waddr_gray;
reg [ADDR_WIDTH:0] raddr_gray;
//格雷码打两拍的读写地址
reg [ADDR_WIDTH:0] waddr_gray_ff0;
reg [ADDR_WIDTH:0] waddr_gray_ff1;
reg [ADDR_WIDTH:0] raddr_gray_ff0;
reg [ADDR_WIDTH:0] raddr_gray_ff1;
//打完拍后再转二进制进行空满判断
wire [ADDR_WIDTH:0] waddr_gray2bin;
wire [ADDR_WIDTH:0] raddr_gray2bin;
//读写使能
wire wen ;
wire ren ;
//最后给到ram的地址 保持真实位宽地址
wire [ADDR_WIDTH-1:0] waddr;
wire [ADDR_WIDTH-1:0] raddr;
//-----------------------------------
//功能语句
//-----------------------------------
//例化ram作为存储
dual_port_RAM #(.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM
(
.wclk (wclk),
.wenc (wen),
.waddr(waddr[ADDR_WIDTH-1:0]),
.wdata(wdata),
.rclk (rclk),
.renc (ren),
.raddr(raddr[ADDR_WIDTH-1:0]),
.rdata(rdata)
);
//二进制打3拍
always @(posedge wclk or negedge wrstn) begin
if(~wrstn) begin
waddr_bin_ff0 <= 'd0;
end
else begin
waddr_bin_ff0 <= waddr_bin;
end
end
always @(posedge rclk or negedge rrstn) begin
if(~rrstn) begin
raddr_bin_ff0 <= 'd0;
end
else begin
raddr_bin_ff0 <= raddr_bin;
end
end
//读写使能
assign wen = winc & !wfull;
assign ren = rinc & !rempty;
//真是位宽地址 给到ram
assign waddr = waddr_bin[ADDR_WIDTH-1:0];
assign raddr = raddr_bin[ADDR_WIDTH-1:0];
//地址++ 再收到读写使能后 进行地址++
always @(posedge wclk or negedge wrstn) begin
if(~wrstn) begin
waddr_bin <= 'd0;
end
else if(wen)begin
waddr_bin <= waddr_bin + 1'd1;
end
end
always @(posedge rclk or negedge rrstn) begin
if(~rrstn) begin
raddr_bin <= 'd0;
end
else if(ren)begin
raddr_bin <= raddr_bin + 1'd1;
end
end
//二进制转格雷码
always @(posedge wclk or negedge wrstn) begin
if(~wrstn) begin
waddr_gray <= 'd0;
end
else begin
waddr_gray <= waddr_bin ^ (waddr_bin>>1);
end
end
always @(posedge rclk or negedge rrstn) begin
if(~rrstn) begin
raddr_gray <= 'd0;
end
else begin
raddr_gray <= raddr_bin ^ (raddr_bin>>1);
end
end
//交叉时钟下打两拍得到ff0 ff1
always @(posedge rclk or negedge rrstn) begin
if(~rrstn) begin
waddr_gray_ff0 <= 'd0;
waddr_gray_ff1 <= 'd0;
end
else begin
waddr_gray_ff0 <= waddr_gray;
waddr_gray_ff1 <= waddr_gray_ff0;
end
end
always @(posedge wclk or negedge wrstn) begin
if(~wrstn) begin
raddr_gray_ff0 <= 'd0;
raddr_gray_ff1 <= 'd0;
end
else begin
raddr_gray_ff0 <= raddr_gray;
raddr_gray_ff1 <= raddr_gray_ff0;
end
end
//再转二进制码
assign waddr_gray2bin[ADDR_WIDTH] = waddr_gray_ff1[ADDR_WIDTH]; //最高位相同
genvar i;
generate
for(i = ADDR_WIDTH-1; i >= 0; i = i - 1) begin: gray2bin_w
assign waddr_gray2bin[i] = waddr_gray2bin[i + 1] ^ waddr_gray_ff1[i];
end
endgenerate
assign raddr_gray2bin[ADDR_WIDTH] = raddr_gray_ff1[ADDR_WIDTH]; //最高位相同
genvar j;
generate
for(j = ADDR_WIDTH-1; j >= 0; j = j - 1) begin: gray2bin_r
assign raddr_gray2bin[j] = raddr_gray2bin[j + 1] ^ raddr_gray_ff1[j];
end
endgenerate
//读空的判断
assign rempty = (raddr_bin_ff0 == waddr_gray2bin);
//写满的判断
assign wfull = (waddr_bin_ff0 == {~raddr_gray2bin[ADDR_WIDTH],raddr_gray2bin[ADDR_WIDTH-1:0]});
endmodule
`timescale 1ns/1ns
/**********************************RAM************************************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
,input [WIDTH-1:0] wdata //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/**********************************SFIFO************************************/
module sfifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input clk ,
input rst_n ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output reg wfull ,
output reg rempty ,
output wire [WIDTH-1:0] rdata
);
parameter addr_width = $clog2(DEPTH);
reg [addr_width:0] waddr_pd;
reg [addr_width:0] raddr_pd;
wire wen;
wire ren;
assign wen = (winc & (!wfull));
assign ren = (rinc & (!rempty));
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
waddr_pd <= 0;
else if(wen)
waddr_pd <= waddr_pd + 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
raddr_pd <= 0;
else if(ren)
raddr_pd <= raddr_pd + 1'b1;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wfull <= 'd0;
rempty <= 'd0;
end
else begin
wfull <= (waddr_pd == {~raddr_pd[addr_width],raddr_pd[addr_width-1:0]});
rempty <= (raddr_pd == waddr_pd);
end
end
dual_port_RAM u1
(
.wclk(clk),
.wenc(wen),
.waddr(waddr_pd[addr_width-1:0]),
.wdata(wdata),
.rclk(clk),
.renc(ren),
.raddr(raddr_pd[addr_width-1:0]),
.rdata(rdata)
);
endmodule
5位的A和3位的B,计算C = A / B
module chu
(
input wire[15:0] a,
input wire [ 7:0] b,
output wire [15:0] c
);
reg [15:0] a_reg;
reg [7:0] b_reg;
reg [31:0] temp_a;
reg [31:0] temp_b;
integer i;
always@(*)begin
a_reg =a;
b_reg= b;
end
always@(*)begin
temp_a ={16'h0,a_reg} ;
temp_b={b_reg ,16'h0 } ;
for(i =0;i<16;i=i+1)begin
temp_a = temp_a <<1;
if (temp_a >= temp_b)begin
temp_a = temp_a-temp_b+1;
end
else begin
temp_a = temp_a;
end
end
end
assign c = temp_a[15:0];
endmodule
`timescale 1ns/1ns
module multi_pipe#(
parameter size = 4
)(
input clk ,
input rst_n ,
input [size-1:0] mul_a ,
input [size-1:0] mul_b ,
output reg [size*2-1:0] mul_out
);
wire [7:0] lv1;
wire [7:0] lv2;
wire [7:0] lv3;
wire [7:0] lv4;
reg [7:0] add1;
reg [7:0] add2;
assign lv1 = mul_b[0]?{4'b0,mul_a }:8'b0;
assign lv2 = mul_b[1]?{3'b0,mul_a,1'b0}:8'b0;
assign lv3 = mul_b[2]?{2'b0,mul_a,2'b0}:8'b0;
assign lv4 = mul_b[3]?{1'b0,mul_a,3'b0}:8'b0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
add1 <= 0;
add2 <= 0;
mul_out <= 0;
end
else
begin
add1 <= lv1 + lv2;
add2 <= lv3 + lv4;
mul_out <= add1 + add2;
end
end
endmodule
genvar i;
generate
for(i = 0; i < size; i = i + 1)begin : loop
assign temp[i] = mul_b[i] ? mul_a << i : 'd0;
end
endgenerate
module identify_tool
(
input clk,
input rst_n,
input signal,
output wire pose,
output wire nege
);
//内部信号
reg signal_before;
//前一刻信号值寄存
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
signal_before <= 0;
end
else begin
signal_before <= signal ;
end
end
//上升下降判断
assign nege = signal==0 && signal_before==1;
assign pose = signal==1 && signal_before==0;
endmodule
module prevent_jitter
(
input clk,
input rst_n,
input key_in,
output reg key_out
);
reg key_in0;
reg [19:0] cnt;
wire change;
parameter jitter=20'd1000000;
// ff0
always@(posedge clk)
if(!rst_n)
key_in0<=0;
else
key_in0<=key_in;
// up and down
assign change=(key_in & !key_in0)|(!key_in & key_in0);
// cnt
always@(posedge clk)
if(!rst_n)
cnt<=0;
else if(change) cnt<=0;
else cnt<=cnt+1;
// key_out
always@(posedge clk)
if(!rst_n)
key_out<=1;
else if(cnt==jitter-1)
key_out<=key_in;
endmodule
设计一个电路,使用时序逻辑对一个单bit信号进行毛刺滤除操作,高电平或者低电平宽带小于4个时钟周期的为毛刺
module filter
(
input clk,
input rst_n,
input in,
output out
);
reg in_ff0;
reg in_ff1;
wire pose;
wire nege;
reg [1:0] cnt;
reg out;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
in_ff0 <= 0;
in_ff1 <= 0;
end
else
begin
in_ff0 <= in;
in_ff1 <= in_ff0;
end
end
assign pose = ~in_ff1 && in_ff0;
assign nege = in_ff1 && ~in_ff0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if (pose || nege)
cnt <= 0;
else
cnt <= cnt + 1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
out <= 0;
else if(cnt == 'd3)
out <= in_ff1;
end
endmodule
写一个十六进制计数器模块,计数器输出信号递增每次到达0,给出指示信号zero,当置位信号set 有效时,将当前输出置为输入的数值set_num
`timescale 1ns/1ns
module count_module(
input clk,
input rst_n,
input set,
input [3:0] set_num,
output reg [3:0]number,
output reg zero
);
reg [3:0] number_cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
number_cnt <= 0;
else if(set)
number_cnt <= set_num;
else
number_cnt <= number_cnt + 1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
number <= 0;
else
number <= number_cnt;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
zero <= 0;
else if(number_cnt == 0)
zero <= 1;
else
zero <= 0;
end
endmodule
assign outclk = (clk1 & select) | (~select & clk0);
①当sel为1时,输出clk1;当sel为0时,输出clk0
②这个电路中存在一个致命的问题,就是切换时存在毛刺,时序如下图:
module glitch (
input clk0,
input clk1,
input select,
input rst_n,
output clkout
);
reg out1;
reg out0;
always @(negedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out1 <= 0;
end
else begin
out1 <= ~out0 & select;
end
end
always @(negedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out0 <= 0;
end
else begin
out0 <= ~select & ~out1;
end
end
assign clkout = (out1 & clk1) | (out0 & clk0);
endmodule
奇数分频比偶数分频要复杂一点,奇数分频的翻转点在0.5个时钟处,上升沿并不能检测到此处,因此我们需要用到上升沿计数以及下降沿计数;
一个时钟,然后两个计数器分别采样上升沿和下降沿,然后利用偶数分频的办法,得到两个中间时钟,这两个时钟周期为2N+1,N个周期的高电平,N+1个周期的低电平,然后利用两个中间时钟进行相或操作得到奇数分频
做法:对于一个2N+1分频,用两个计数器分别采样上升沿和下降沿个数,计数到2N+1(代码中是2N,因为计算机从0开始数),用两个计数器产生两个时钟,在N+1和2N+1计数处翻转,得到的两个时钟相或,得出2N+1分频时钟
module div_5
(
input clk,
input rst_n,
output wire clk_div
);
//参数
parameter N = 2'd2;
//内部信号
reg [2:0] cnt_pose;
reg [2:0] cnt_nege;
reg clk_pose;
reg clk_nege;
//功能块
always@(posedge clk or negedge rst_n)begin // 对上升沿计数
if(!rst_n)
cnt_pose <= 0;
else if(cnt_pose == 2*N)
cnt_pose <= 0;
else
cnt_pose <= cnt_pose + 1;
end
always@(posedge clk or negedge rst_n)begin // 中间时钟clk_pose
if(!rst_n)
clk_pose<=0;
else if(cnt_pose == N||cnt_pose == 2*N)
clk_pose <= ~clk_pose;
else
clk_pose <= clk_pose;
end
always@(negedge clk or negedge rst_n)begin // 对下降沿计数
if(!rst_n)
cnt_nege <= 0;
else if(cnt_nege == 2*N)
cnt_nege <= 0;
else
cnt_nege <= cnt_nege + 1;
end
always@(negedge clk or negedge rst_n)begin // 中间时钟clk_nege
if(!rst_n)
clk_nege <= 0;
else if(cnt_nege == N||cnt_nege == 2*N)
clk_nege <= ~clk_nege;
else
clk_nege <= clk_nege;
end
assign clk_div = clk_pose|clk_nege; // 2N+1分频时钟输出
endmodule
module div_10
(
input clk,
input rst_n,
output reg clk_div
);
//参数
parameter N = 4'd10;
//内部信号
reg [3:0] cnt;
//功能块
always@(posedge clk or negedge rst_n)begin
if (!rst_n)begin
cnt <= 0;
end
else if(cnt == N - 1 ) begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
always@(posedge clk or negedge rst_n)begin
if (!rst_n) begin
clk_div <= 0;
end
else if (cnt <= (N/2)-1) begin
clk_div <= 1;
end
else begin
clk_div <= 0;
end
end
endmodule
设计一个序列检测器,将码流中的“10010”序列检测出来:
①三个输入,clk,rst_n,x,其中x是一位的输入,由x传输的多个数据构成码流
②输出z,在检测到完整的10010序列时,z拉高
用移位寄存器的方法比状态机的方法代码要轻简很多,先说一下原理:
module check_num_shift
(
input clk,
input rst_n,
input x,
output wire z
);
reg [4:0] shift;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
shift <= 0;
else
shift <= {shift[3:0],x};
end
assign z = (shift == 5'b10010)?1:0;
endmodule
对1bit的脉冲信号进行展宽,转为32bit位宽,并产生有效信号
module 1_to_32(
input clk,
input rst_n,
input pulse_in,
output reg pulse_out,
output wire flag
);
//-------------------------------------------------------
reg pulse_in_ff0,pulse_in_ff1;
reg [4:0] cnt;
//-------------------------------------------------------
//监沿(下降沿)
always @(posedge clk or negedge rst_n)begin
if(!rst_n) begin
pulse_in_ff0<=1'b0;
pulse_in_ff1<=1'b0;
end
else begin
pulse_in_ff0 <= pulse_in;
pulse_in_ff1 <= pulse_in_ff0;
end
end
//前一拍为0,现在为1,则为上升沿
assign flag=(~pulse_in_ff1)&pulse_in_ff0;
//-------------------------------------------------------
//计数延长32个时钟
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
pulse_out<=1'b0;
else if(flag)
pulse_out<=1'b1;
else if(cnt==5'd31)
pulse_out<=1'b0;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt<=5'b0;
else if(pulse_out==1'b1)begin
if(cnt==5'd31)
cnt<=5'd0;
else
cnt<=cnt+1'b1;
end
end
//-------------------------------------------------------
endmodule
`timescale 1ns/1ns
module Tff_2 (
input wire data, clk, rst,
output wire q
);
//*************code***********//
reg data_tff0;
reg data_tff1;
always@(posedge clk or negedge rst)begin
if(!rst)begin
data_tff0 <= 0;
data_tff1 <= 0;
end
else begin
data_tff0 <= data^data_tff0;
data_tff1 <= data_tff0^data_tff1;
end
end
assign q = data_tff1;
//*************code***********//
endmodule
对输入的32位数据进行奇偶校验,根据sel输出校验结果,0输出奇校验,1输出偶校验
`timescale 1ns/1ns
module odd_sel(
input [31:0] bus,
input sel,
output check
);
//*************code***********//
wire ji;
wire ou;
wire check;
assign ou = ^bus;
assign ji = ~ou;
assign check = (sel) ? ou :ji;
//*************code***********//
endmodule
已知d为一个8位数,在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号表示此时刻输入d有效
`timescale 1ns/1ns
module multi_sel(
input [7:0]d ,
input clk,
input rst,
output reg input_grant,
output reg [10:0]out
);
//*************code***********//
reg [1:0] cnt;
reg [7:0] d_reg;
always@(posedge clk or negedge rst)begin
if(!rst)
cnt <= 0;
else
cnt <= cnt + 1;
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
d_reg <= 0;
out <= 0;
input_grant <= 0;
end
else
case(cnt)
0:
begin
d_reg <= d;
out <= d;
input_grant <= 1;
end
1:
begin
out <= (d_reg<<2) - d_reg;
input_grant <= 0;
end
2:
begin
out <= (d_reg<<3) - d_reg;
input_grant <= 0;
end
3:
begin
out <= d_reg<<3;
input_grant <= 0;
end
endcase
end
//*************code***********//
endmodule
用generata…for语句编写代码,替代下面语句,
assign data_out [0] = data_in [7];
assign data_out [1] = data_in [6];
assign data_out [2] = data_in [5];
assign data_out [3] = data_in [4];
assign data_out [4] = data_in [3];
assign data_out [5] = data_in [2];
assign data_out [6] = data_in [1];
assign data_out [7] = data_in [0];
`timescale 1ns/1ns
module gen_for_module(
input [7:0] data_in,
output [7:0] data_out
);
genvar i;
generate
for(i = 0; i < 8; i = i + 1)
begin : bit_gen
assign data_out[i] = data_in[7 - i];
end
endgenerate
endmodule
编写一个子模块,将输入两个8bit位宽的变量a,b,并输出ab之中较小的数;并在主模块中例化,实现输出三个8bit输入信号的最小值的功能
`timescale 1ns/1ns
module main_mod(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
input [7:0]c,
output [7:0]d
);
wire [7:0] d;
wire [7:0] ab_min;
wire [7:0] ac_min;
wire [7:0] min;
son u1
(
.clk (clk),
.rst_n (rst_n),
.a (a),
.b (b),
.c (ab_min)
);
son u2
(
.clk (clk),
.rst_n (rst_n),
.a (a),
.b (c),
.c (ac_min)
);
son u3
(
.clk (clk),
.rst_n (rst_n),
.a (ac_min),
.b (ab_min),
.c (min)
);
assign d = min;
endmodule
module son
(
input clk,
input rst_n,
input [7:0] a,
input [7:0] b,
output reg [7:0] c
);
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
c <= 0;
else if(a < b)
c <= a;
else
c <= b;
end
endmodule
用函数实现一个4bit数据大小端转换的功能。实现对两个不同的输入分别转换并输出。
程序的接口信号图如下:
`timescale 1ns/1ns
module function_mod(
input clk,
input rst_n,
input [3:0]a,
input [3:0]b,
output [3:0]c,
output [3:0]d
);
assign c = data_rev(a);
assign d = data_rev(b);
function [3:0] data_rev;
input [3:0] data_in;
begin
data_rev[0] = data_in[3];
data_rev[1] = data_in[2];
data_rev[2] = data_in[1];
data_rev[3] = data_in[0];
end
endfunction
endmodule
`timescale 1ns/1ns
module lca_4(
input [3:0] A_in ,
input [3:0] B_in ,
input C_1 ,
output wire CO ,
output wire [3:0] S
);
wire [3:0] g;
wire [3:0] p;
wire [3:0] s;
wire [3:0] c;
assign g[3] = A_in[3]*B_in[3];
assign g[2] = A_in[2]*B_in[2];
assign g[1] = A_in[1]*B_in[1];
assign g[0] = A_in[0]*B_in[0];
assign p[3] = A_in[3]^B_in[3];
assign p[2] = A_in[2]^B_in[2];
assign p[1] = A_in[1]^B_in[1];
assign p[0] = A_in[0]^B_in[0];
assign c[3] = g[2]+c[2]*p[2];
assign c[2] = g[1]+c[1]*p[1];
assign c[1] = g[0]+c[0]*p[0];
assign c[0] = C_1;
assign s[3] = p[3]^c[3];
assign s[2] = p[2]^c[2];
assign s[1] = p[1]^c[1];
assign s[0] = p[0]^c[0];
assign S = s;
assign CO = c[3];
endmodule
`timescale 1ns/1ns
module encoder_83(
input [7:0] I ,
input EI ,
output reg [2:0] Y ,
output reg GS ,
output reg EO
);
always@(*)begin
if(~EI)begin
Y = 0;
GS = 0;
EO = 0;
end
else
casex(I)
8'b00000000:begin
Y = 0;
GS = 0;
EO = 1;
end
8'b1xxxxxxx:begin
Y = 3'b111;
GS = 1;
EO = 0;
end
8'b01xxxxxx:begin
Y = 3'b110;
GS = 1;
EO = 0;
end
8'b001xxxxx:begin
Y = 3'b101;
GS = 1;
EO = 0;
end
8'b0001xxxx:begin
Y = 3'b100;
GS = 1;
EO = 0;
end
8'b00001xxx:begin
Y = 3'b011;
GS = 1;
EO = 0;
end
8'b000001xx:begin
Y = 3'b010;
GS = 1;
EO = 0;
end
8'b0000001x:begin
Y = 3'b001;
GS = 1;
EO = 0;
end
8'b00000001:begin
Y = 3'b000;
GS = 1;
EO = 0;
end
default:begin
Y = 3'b000;
GS = 0;
EO = 0;
end
endcase
end
endmodule
module decoder1(
input A ,
input B ,
input Ci ,
output reg D ,
output reg Co
);
wire [2:0] x;
assign x = {A,B,Ci};
always@(*)begin
case(x)
0: begin
D = 0;
Co = 0;
end
1: begin
D = 1;
Co = 1;
end
2: begin
D = 1;
Co = 1;
end
3: begin
D = 0;
Co = 1;
end
4: begin
D = 1;
Co = 0;
end
5: begin
D = 0;
Co = 0;
end
6: begin
D = 0;
Co = 0;
end
7: begin
D = 1;
Co = 1;
end
endcase
end
endmodule
signal_a是clka(300M)时钟域的一个单时钟脉冲信号,如何将其同步到时钟域clkb(100M)中,并产生出signal_b同步脉冲信号。请用Verilog代码描述,并画出对应的时序波形图说明图
module pulse_syn
(
input clka,
input rst_n_a,
input clkb,
input rst_n_b,
input signal_a,
output signal_b
);
reg [1:0] cnt;
reg signal_a_exp;
reg signal_a_ff0;
reg signal_a_ff1;
reg signal_a_ff2;
reg signal_b;
//expand 3T for signal_a
always@(posedge clka or negedge rst_n_a)begin
if(!rst_n_a)
signal_a_exp <= 0;
else if(cnt == 'd2)
signal_a_exp <= 0;
else if(signal_a)
signal_a_exp <= 1;
end
always@(posedge clka or negedge rst_n_a)begin
if(!rst_n_a)
cnt <= 0;
else if(signal_a_exp)
cnt <= cnt + 1;
else
cnt <= 0;
end
//在b时钟域下打拍
always@(posedge clkb or negedge rst_n_b)begin
if(!rst_n_b)
begin
signal_a_ff0 <= 0;
signal_a_ff1 <= 0;
signal_a_ff2 <= 0;
end
else
begin
signal_a_ff0 <= signal_a_exp;
signal_a_ff1 <= signal_a_ff0;
signal_a_ff2 <= signal_a_ff1;
end
end
always@(posedge clkb or negedge rst_n_b)begin
if(!rst_n_b)
signal_b <= 0;
else if(~signal_a_ff1 && signal_a_ff2)
signal_b <= 1;
else
signal_b <= 0;
end
endmodule
`timescale 1 ns / 1 ns
module pulse_syn_tb();
reg clka;
reg rst_n_a;
reg clkb;
reg rst_n_b;
reg signal_a;
wire signal_b;
parameter CYCLE = 15;
parameter RST_TIME = 3 ;
//clka and rst_n_a
initial begin
clka = 0;
forever
#(CYCLE/3)
clka=~clka;
end
initial begin
rst_n_a = 1;
#2;
rst_n_a = 0;
#(CYCLE*RST_TIME);
rst_n_a = 1;
end
//clkb and rst_n_b
initial begin
clkb = 0;
forever
#(CYCLE)
clkb=~clkb;
end
initial begin
rst_n_b = 1;
#2;
rst_n_b = 0;
#(CYCLE*RST_TIME);
rst_n_b = 1;
end
initial begin
signal_a = 0;
#95
signal_a = 1;
#10
signal_a = 0;
#200
signal_a = 1;
#10
signal_a = 0;
end
initial begin
$vcdpluson;
end
initial begin
# 800 $finish;
end
pulse_syn u1
(
.clka (clka),
.rst_n_a (rst_n_a),
.clkb (clkb),
.rst_n_b (rst_n_b),
.signal_a (signal_a),
.signal_b (signal_b)
);
endmodule
`timescale 1ns/1ns
module seq_circuit(
input A ,
input clk ,
input rst_n,
output wire Y
);
reg [1:0] curr_state;
reg [1:0] next_state;
always @ (posedge clk or negedge rst_n)
begin
if( !rst_n ) begin
curr_state <= 2'b00;
next_state <= 2'b00;
end
else begin
curr_state <= next_state;
end
end
always @ (*)
begin
case(curr_state)
2'b00 : next_state = (A == 1'b1) ? 2'b11 : 2'b01;
2'b01 : next_state = (A == 1'b1) ? 2'b00 : 2'b10;
2'b10 : next_state = (A == 1'b1) ? 2'b01 : 2'b11;
2'b11 : next_state = (A == 1'b1) ? 2'b10 : 2'b00;
default : next_state = 2'b00;
endcase
end
assign Y = (curr_state == 2'b11) ? 1 : 0;
endmodule
实现一个深度为8,位宽为4bit的ROM,数据初始化为0,2,4,6,8,10,12,14。可以通过输入地址addr,输出相应的数据data
`timescale 1ns/1ns
module rom(
input clk,
input rst_n,
input [7:0]addr,
output [3:0]data
);
reg [3:0] data;
reg [3:0] men [7:0];
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
men[0] <= 4'd0;
men[1] <= 4'd2;
men[2] <= 4'd4;
men[3] <= 4'd6;
men[4] <= 4'd8;
men[5] <= 4'd10;
men[6] <= 4'd12;
men[7] <= 4'd14;
data <= 0;
end
else
begin
data <= men[addr];
end
end
endmodule
请描述如下代码,实现加法;
C = A + B;
A是21bit无符号数;
B是18位有符号数;
保证正确得到一个不溢出的有符号数C;
module unsign_sign
(
input wire [20:0]A,
input wire signed [17:0]B,
output wire signed [22:0]C
);
assign C =$signed({1'b0,A})+ B;
endmodule
编写一个信号发生器模块,根据波形选择信号wave_choise发出相应的波形:wave_choice=0时,发出方波信号;
wave_choice=1时,发出锯齿波信号;
wave_choice=2时,发出三角波信号;
mamodule bo
(
input clk,
input rst_n,
input [1:0] wave_choise,
output reg [4:0]wave
);
reg [4:0] fang;
reg [4:0] juchi;
reg [4:0] sanjiao;
reg [4:0] cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(wave_choise != 3)
cnt <= cnt + 1;
else
cnt <= 0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
fang <= 0;
else if(cnt < 15)
fang <= 20;
else
fang <= 0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
juchi <= 0;
else if(juchi == 31)
juchi <= 0;
else
juchi <= juchi + 1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
sanjiao <= 0;
else if(cnt < 16)
sanjiao <= sanjiao + 1;
else
sanjiao <= sanjiao - 1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
wave <= 0;
else if(wave_choise == 0)
wave <= fang;
else if(wave_choise == 1)
wave <= juchi;
else if(wave_choise == 2)
wave <= sanjiao;
else
wave <= 0;
end
endmodule
设计一个自动贩售机,输入货币有三种,为0.5/1/2元,饮料价格是1.5元,要求进行找零
d1 0.5元
d2 1元
d3 2元
out1 饮料
out2 零钱
`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
);
parameter idle = 0;
parameter mao5 = 1;
parameter yuan1 = 2;
parameter yuan2 = 4;
parameter yuan3 = 6;
parameter yuan2mao5 = 5;
parameter yuan1mao5 = 3;
reg [2:0] cstate;
reg [2:0] nstate;
always@(posedge clk or negedge rst)begin
if(!rst)
cstate <= idle;
else
cstate <= nstate;
end
always@(*)begin
case(cstate)
idle:
begin
if({d1,d2,d3} == 3'b100)
nstate = mao5;
else if({d1,d2,d3} == 3'b010)
nstate = yuan1;
else if({d1,d2,d3} == 3'b001)
nstate = yuan2;
else if({d1,d2,d3} == 3'b000)
nstate = nstate;
end
mao5:
begin
if({d1,d2,d3} == 3'b100)
nstate = yuan1;
else if({d1,d2,d3} == 3'b010)
nstate = yuan1mao5;
else if({d1,d2,d3} == 3'b001)
nstate = yuan2mao5;
else if({d1,d2,d3} == 3'b000)
nstate = nstate;
end
yuan1:
begin
if({d1,d2,d3} == 3'b100)
nstate = yuan1mao5;
else if({d1,d2,d3} == 3'b010)
nstate = yuan2;
else if({d1,d2,d3} == 3'b001)
nstate = yuan3;
else if({d1,d2,d3} == 3'b000)
nstate = nstate;
end
yuan2:
begin
nstate = idle;
end
yuan2mao5:
begin
nstate = idle;
end
yuan1mao5:
begin
nstate = idle;
end
yuan3:
begin
nstate = idle;
end
default:
nstate = idle;
endcase
end
always@(*)begin
if(!rst)
begin
out1 = 0;
out2 <= 0;
end
else if(cstate == yuan1mao5)
begin
out1 = 1;
out2 <= 0;
end
else if(cstate == yuan2)
begin
out1 = 1;
out2 <= 1;
end
else if(cstate == yuan2mao5)
begin
out1 = 1;
out2 <= 2;
end
else if(cstate == yuan3)
begin
out1 = 1;
out2 <= 3;
end
else
begin
out1 = 0;
out2 <= 0;
end
end
endmodule
`timescale 1ns/1ns
module gray_counter(
input clk,
input rst_n,
output reg [3:0] gray_out
);
reg [3:0] bin;
wire [3:0] gray;
reg [3:0] bin_cnt;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0) begin
bin <= 4'b0;
end
else begin
bin[3] = gray[3];
bin[2] = gray[2]^bin[3];
bin[1] = gray[1]^bin[2];
bin[0] = gray[0]^bin[1];
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n) begin
bin_cnt <= 4'b0;
end
else begin
bin_cnt <= bin + 1'b1;
end
end
assign gray = (bin_cnt >> 1) ^ bin_cnt;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0) begin
gray_out <= 4'b0;
end
else begin
gray_out <= gray;
end
end
endmodule
将A时钟下的多bit数据同步到B时钟下,已知data_in端数据变化频率很低,相邻两个数据间的变化,至少间隔10个B时钟周期
`timescale 1ns/1ns
module mux(
input clk_a ,
input clk_b ,
input arstn ,
input brstn ,
input [3:0] data_in ,
input data_en ,
output reg [3:0] dataout
);
reg [3:0] data_buff;
reg data_en_ff0;
reg data_en_ff1;
always@(posedge clk_b or negedge brstn)begin
if(!brstn)begin
data_en_ff0 <= 0;
data_en_ff1 <= 0;
end
else begin
data_en_ff0 <= data_en;
data_en_ff1 <= data_en_ff0;
end
end
always@(posedge clk_b or negedge brstn)begin
if(!brstn)begin
data_buff <= 0;
end
else
data_buff <= data_in;
end
always@(posedge clk_b or negedge brstn)begin
if(!brstn)begin
dataout <= 0;
end
else if(data_en_ff1)
dataout <= data_buff;
end
endmodule
数据发送模块循环发送0-7,在每个数据传输完成之后,间隔5个时钟,发送下一个数据。请在两个模块之间添加必要的握手信号,保证数据传输不丢失
module data_driver
(
input clk_a,
input rst_n,
input data_ack,
output reg [3:0]data,
output reg data_req
);
reg data_ack_ff0;
reg data_ack_ff1;
reg data_ack_ff2;
reg [9:0] cnt;
wire pose;
//==========同步并检测ack上升沿==================
always @ (posedge clk_a or negedge rst_n)begin
if (!rst_n)
begin
data_ack_ff0 <= 0;
data_ack_ff1 <= 0;
data_ack_ff2 <= 0;
end
else
begin
data_ack_ff0 <= data_ack;
data_ack_ff1 <= data_ack_ff0;
data_ack_ff2 <= data_ack_ff1;
end
end
assign pose = ~data_ack_ff2 & data_ack_ff1;
//==============DATA赋值==========================
always @ (posedge clk_a or negedge rst_n)begin
if (!rst_n)
begin
data <= 0;
end
else if(pose)
begin
data <= data+1; //上升沿赋值
end
else begin
data <= data;
end
end
//=============cnt================================
always @ (posedge clk_a or negedge rst_n)begin
if (!rst_n)
cnt <= 0;
else if (pose)
cnt <= 0;
else if (data_req)
cnt <= cnt;
else
cnt <= cnt+1;
end
always @ (posedge clk_a or negedge rst_n)begin
if (!rst_n)
data_req <= 0;
else if (cnt == 3'd4) //cnt计数5个时钟,发送下一个数据
data_req <= 1'b1;
else if (pose)
data_req <= 1'b0;
else
data_req <= data_req;
end
endmodule
module data_receiver
(
input clk_b,
input rst_n,
input [3:0] data,
input data_req,
output reg data_ack
);
reg [3:0] data_in_reg;
reg data_req_ff0;
reg data_req_ff1;
reg data_req_ff2;
always @ (posedge clk_b or negedge rst_n)begin
if (!rst_n)
begin
data_req_ff0 <= 0;
data_req_ff1 <= 0;
data_req_ff2 <= 0;
end
else
begin
data_req_ff0 <= data_req;
data_req_ff1 <= data_req_ff0;
data_req_ff2 <= data_req_ff1;
end
end
assign pose = data_req_ff1 && ~data_req_ff2;
always @ (posedge clk_b or negedge rst_n)begin
if (!rst_n)
data_ack <= 0;
else if (data_req_ff0)
data_ack <= 1;
else data_ack <=0 ;
end
always @ (posedge clk_b or negedge rst_n)begin
if (!rst_n)
data_in_reg <= 0;
else if (pose)
data_in_reg <= data;
else
data_in_reg <= data_in_reg ;
end
endmodule
N个乘积项的表达(与项),如两变量AB的最小项为A’B’、A’B,、AB’、AB
最小项的性质:
①在输入变量任一取值下,有且仅有一个最小项的值为1;
②全体最小项之和为1 ;
③任何两个最小项之积为0 ;
④两个相邻的最小项之和可以合并,消去一对因子,只留下公共因子;(卡诺图重要原理)
相邻:仅一个因子不同的最小项,如:A'BC'与A'BC;
N个项和的表达(或项),如两变量AB的最大项为A’+B’、A’+B,、A+B’、A+B
最大项的性质:
①在输入变量任一取值下,有且仅有一个最大项的值为0 ;
②全体最大项之积为0 ;
③任何两个最大项之和为1 ;
④两个相邻的最大项之积可以合并,消去一对因子,只留下公共因子。
相邻:仅一个因子不同的最大项,如:A'+B+C和A'+B+C
卡诺图:用来进行化简
①将函数化为最小项之和的形式
②画出卡诺图(00、01、11、10 格雷码),在最小项位置填1
③把一圈起来!
圈1原则:
覆盖所有的1
圈圈数目做到最少
圈圈里面1尽量多
如上图,找公用的项
横着的圈是 AB’
竖着的圈是BC’
结果就是AB’ + BC’
总的就是说:在DS两极加电压,DS不导通;在GS加电压,DS间形成沟道使得DS导通
其也可以分为三个区:
①当Vgs < Vgs(th) 时,也就是小于启动电压时,这部分区域成为截至区
②当Vgs > Vgs(th) 时,如上图所示,虚线左边成为可变电阻区,其等效电阻的大小与Vgs有关
③虚线右边是恒流区,此时电流基本上由Vgs决定
①截止区:条件Vbe= 0, ib = 0, ic = 0, c一e间“断开”
②放大区 :条件Vce> 0.7, ib>0, ic 随ib成正比变化, △ic=β△ib
③饱和区 :条件Vce< 0.7, ib >0, Vce 很低,△ic随△ib增加变缓,趋于“饱和”
前面1.1已经说过了,这里不在阐述
①对称式多谐振荡器:两个反相器与两个电容耦合起来的正反馈振荡电路。
②非对称式多谐振荡器:在对称式的基础上简化。
③施密特多谐振荡器:用施密特触发电路的反相输出经RC积分接回输入。
④环形振荡器:利用延迟负反馈产生振荡。
⑤石英晶体多谐振荡器:石英晶体 + 对称式(接入石英晶体稳频)
单稳态电路中的工作特性具有下的显著特点:
例子: 声控灯,灭的时候是稳态、而亮则是暂稳态
原理:
①当vi = 0,vi2 = vdd,所以vo = 0
②当vi接脉冲时,在cd和rd之间会产生窄脉冲vd,当vd = vth后,发生如下正反馈
③迅速使得vo1 = vi2 = 0
④由于电容电压不会发生迅速的跳变,因此进入暂稳态
⑤当vdd给电容充电完毕后,又进入稳态
①输入信号在上升和下降过程中,电路状态转换的输入电平不同
②电路状态转换时有正反馈过程,使输出波形边沿变陡
③用于波形的变换
④用于监幅
①当vi = 0 ,vo = vol = 0 ,这是va也是0
②而vi从0升到vth,CMOS管G1导通,引起如下正反馈
③此时vo迅速上高到vdd,而此时vi的值就是我们所说的vt+
④同理vi从vdd下降到vt-,vo从voh变成vol,也是正反馈过程
放大区(也叫线性区) :条件Vce> 0.7, ib>0, ic 随ib成正比变化, △ic=β△ib
0.7的Von是硅三极管,锗三极管是0.3
单个MOS管时,看下图;
输入为低电平时,MOS管处于截止区,输出高电平1;
输入为高电平时,MOS管导通(个人觉得时工作在可变电阻区),输出低电平0
当为CMOS管时,看下图;
无论输入是高电平还是低电平,两个MOS管总是一个截至一个导通,即为所谓的互补关系;
而CMOS中的C就是互补的意思;
module check_num_shift
(
input clk,
input x,
output wire is_it
);
reg [9:0] shift;
always@(posedge clk)begin
shift <= {shift[8:0],x};
end
assign is_it= (shift == 10'b0010110111)?1:0;
endmodule
输入为0101即要显示数字5,因此afgcd亮灯,置0,其他置1 ,所以输出是0100100
每输入一个时钟脉冲,触发器状态便翻转一次,实现一次分频,因此5个就是除以 2^5,最后为8KHZ
BCD码就是用4位二进制数来表示1位十进制数中的0~9这10个数码,因此BCD码计数器就是0-9的计数器,4位触发器共有16种状态,所以多出了6种无关状态
传感器的输出电压为模拟信号,它作为ADC的输入信号,其分辨率为1mV,为保证ADC采样精度,n位ADC可以分辨的最小模拟电压就是1mV;分辨率的公式如下,Vref是基准电压2.5
所以算的n最小为12位
处于零电位一端,电流表上承受的共模电压小。
对着信号一个一个列出来感觉不会有什么问题
Y = A’B +AB’,即:A=0时,Y = B;A=1时,F = Y’
撤销复位时,恢复到解复位状态的电平必须在时钟有效沿来临之前的一段时间到来,才能保证时钟能有效恢复到解复位状态,此段时间为recovery time。
复位时,在时钟有效沿来临之后复位信号还需要保持的时间为移除时间removal time
A.网表仿真不能发现实现约束的问题
B.仿真速度比RTL仿真速度更快
C.网表仿真可以发现电路设计中的异步问题
D.为了保证芯片正常工作,即使在时间和资源紧张情况下,也需要将所有的RTL仿真用例都进行网表仿真并且确保通过
网表仿真通过网表反标sdf进行仿真,仿真速度较RTL仿真慢,由于sdf通过sdc约束和单元逻辑延时和线网延时而来,可以发现约束问题。设计大的话,网表仿真太耗时,常用采用形式验证手段来保证门级网表在功能上与RTL设计保持一致,配合静态时序分析工具保证门级网表的时序
扭环形计数器,亦称约翰逊计数器,每次状态变化时仅有一个触发器发生翻转,译码不存在竞争冒险,在n(n≥3)位计数器中,可使用2n个状态,有2^n-2n个状态未使用
Verilog代码:右移,[0]位取反补高位
module johnson_cnt(
input clk,
input rst_n,
output reg [3:0] out
);
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
out <= 4'b0;
end
else begin
out <= {~out[0], out[3:1]} ;
end
end
endmodule
数据流描述:采用assign 连续赋值语录。
行为描述:使用always 语句或initial 语句块中的过程赋值语录
结构化描述:实例化已有的功能模块或原语
A m1与m3
B m4与m6
C m5与m13
D m2与m8
首先要知道什么是相邻:仅一个因子不同的最小项,如:A’BC’与A’BC
我们把四变量列出来
0000 m0
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111 m15
所以最后检验选项 选D
优先编码器首先输出最高顺序的输入,根据优先编码器的优先级别,5的级别最高,则其二进制输出为101
Verilog 里的取模运算,即求余数运算,先把各自符号位去掉运算,然后取第一个运算数的符号位,答案为1。
在下列Verilog代码中,a=11, b=10,则z的运算结果为:
input [3:0] a;
input [3:0] b;
output signed [7:0] z;
wire signed [3:0] c;
assign c = a[3:0] * b[3:0];
assign z = c;
(1)输入的 a 和 b 都是无符号数,所以进行无符号数的乘法,11 和 10 也在输入的表示范围内,执行 11*10 =110;
(2)c 只有 4 bit ,所以直接截取低 4 位为 1110,也就是14;
(4)将其赋值给 z 后,由于 z 是有符号数,且 c 的最高位符号位为 1,所以进行符号位的扩展,得到 1111_1110,该数表示 -2。
(1)该数目前是补码表示,去掉最高位的符号位为 111_1110;
(2)取反,000_0001;
(3)加 1,得到 000_0010,该数表示2;
(4)符号位为 1,表示负数,所以是 -2;
现有表达式Y = C ? A : B;如果C = x或z,A=1010,B=1100时,Y为多少?
①用2048x12的ROM芯片,最多能实现()个输入 ()个 输出的组合逻辑的数?
②SRAM共12根地址线,32根数据线, 如果要实现2的20次方bytes的Memory,需要多少块这样的SRAM?
1、NOR的读速度比NAND稍快一些
2、NAND的写入速度比NOR快很多
3、NAND的4ms擦除速度远比NOR的5s快
4、NAND的擦除单元更小,相应的擦除电路更少
ModuleA、ModuleB用的是同个Clock, Clock领率80MHz。
ModuleA和ModuleB同时启动,ModuleA产生burst数据给ModuleB,一共产生8次burst;burst rate : 1280 Mbit/s,burst持续时间1us;burst内部速率均匀,burst周期5us,余下的4us内没有数据
ModuleB收到启动信号后,需要花10us做初始化,所以先把moduleA的数据缓存在moduleB内部的同步fifo中,同步fifo位宽32bits,初始化结束后moduleB以640Mbit/s的均匀速率从fifo中读取数据
问:最小的fifo深度?
对12.918做无损定点化,需要的最小位宽是多少?位宽为11时量化误差是多少?
以上是正常的crc检验的流程,但verilog代码中一般通过异或来实现:
crc_reg[0] <= send[当前位]^crc_reg[6];
crc_reg[1] <= crc_reg[0];
crc_reg[2] <= crc_reg[1];
crc_reg[3] <= send[当前位]^crc_reg[6]^crc_reg[2];
crc_reg[4] <= crc_reg[3];
crc_reg[5] <= crc_reg[4];
crc_reg[6] <= crc_reg[5];