常见面试笔试题verilog程序库
常见面试笔试题-verilog程序库
————————————————————————————————作者:————————————————————————————————日期:
加减法
module addsub
( input [7:0] dataa,
input [7:0] datab,
input add_sub,//if thisis1, add; else subtract
input clk,
output reg [8:0] result );
always @ (posedge clk)
begin
if (add_sub) result<= dataa + datab;//or "assign {cout,sum}=dataa+datab;"
elseresult <=dataa- datab;
end
endmodule
四位的全加法器.
module add4(cout,sum,a,b,cin)
input[3:0]a,b; input cin;
output [3:0] sum; output cout;
assign?{cout,sum}=a+b+cin;
endmodule
补码不仅可以执行正值和负值转换,其实补码存在的意义,就是避免计算机去做减法的操作。
1101 -3 补
+ 1000 8
01015
假设-3 + 8,只要将-3 转为补码形式,亦即0011 => 1101,然后和8,亦即1000 相加
就会得到5,亦即0101。至于溢出的最高位可以无视掉。
乘法器
modulemult(outcome,a,b);
parameter SIZE=8;
input[SIZE:1] a,b;
outputreg[2*SIZE:1] outcome;
integer i;
always@(aor b)
begin outcome<=0;
for(i=0,i<=SIZE;i=i+1)
if(b[i]) outcome<=outcome+(a<<(i-1));
end
endmodule
另一种乘法器。在初始化之际,取乘数和被乘数的正负关系,然后取被乘数和乘数的正值。输出结果根据正负关系取得。
else if( Start_Sig)
case( i)
0: begin
isNeg<= Multiplicand[7]^ Multiplier[7];
Mcand <=Multiplicand[7] ?( ~Multiplicand + 1'b1 ) : Multiplicand;
Mer<= Multiplier[7] ? (~Multiplier + 1'b1 ) : Multiplier;
Temp <= 16'd0;
i<=i + 1'b1;
end
1: // Multipling
if( Mer == 0) i <= i+1'b1;
else begin Temp <= Temp + Mcand; Mer <= Mer- 1'b1; end
2:beginisDone <=1'b1;i <= i + 1'b1; end
3:begin isDone<= 1'b0; i <=2'd0; end
endcase
assign Done_Sig =isDone;
assign Product= isNeg? ( ~Temp + 1'b1 ) : Temp;
endmodule
booth乘法器
module booth_multiplier_module
(
input CLK,
? input RSTn,
?input Start_Sig,
? input [7:0]A,
input[7:0]B,
output Done_Sig,
output [15:0]Product,
?output[7:0]SQ_a,
output [7:0]SQ_s,
? output [16:0]SQ_p
);
reg [3:0]i;
? reg [7:0]a; // resultof A
? reg [7:0]s; //reverse resultof A
? reg [16:0]p;//p空间,16+1位
reg [3:0]X;?//指示n次循环
? reg isDone;
?always @ ( posedgeCLKor negedgeRSTn )
if( !RSTn )
begin
???i<=4'd0;
???a<= 8'd0;
???s <=8'd0;
??p <=17'd0;
???X<= 4'd0;
???isDone <=1'b0;
??end
elseif(Start_Sig)
?case(i)
0:
?begin a<= A; s <=( ~A + 1'b1 );p<= { 8'd0, B , 1'b0 }; i <= i + 1'b1;end
1:
???if( X ==8 ) begin X<= 4'd0; i<= i +4'd2; end
??elseif(p[1:0] == 2'b01 ) begin p<= {p[16:9] + a , p[8:0] };i <= i + 1'b1; end
?else if( p[1:0] == 2'b10 )begin p<= { p[16:9] + s ,p[8:0]}; i <=i + 1'b1; end
???elsei <= i + 1'b1; //00和11,无操作
??2:
begin p <= { p[16], p[16:1] }; X <= X + 1'b1; i <= i - 1'b1; end //右移,最高位补0 or 1.
??3:
??begin isDone <= 1'b1; i<= i+1'b1;end
?4:
??begin isDone <= 1'b0; i <= 4'd0;end
endcase
? assignDone_Sig= isDone;
assign Product= p[16:1];
endmodule
除法器
moduledivider_module
(
input CLK,
input RSTn,
input Start_Sig,
input [7:0]Dividend,
input [7:0]Divisor,
outputDone_Sig,
output [7:0]Quotient,
output [7:0]Reminder,
);
reg[3:0]i;
reg [7:0]Dend;
reg [7:0]Dsor;
reg[7:0]Q;
reg[7:0]R;
regisNeg;
reg isDone;
always @( posedge CLKor negedge RSTn )
if( !RSTn )
begin
i <= 4'd0;
Dend <= 8'd0;
Dsor <= 8'd0;
Q <= 8'd0;
isNeg <= 1'b0;
isDone <= 1'b0;
end
else if( Start_Sig )
case( i )
0:
begin
Dend<= Dividend[7] ? ~Dividend+ 1'b1 : Dividend;
Dsor <=Divisor[7] ? Divisor : ( ~Divisor +1'b1 );
??isNeg <=Dividend[7] ^Divisor[7];
i <= i + 1'b1;
end
1: if( Divisor > Dend)
beginQ <= isNeg ? ( ~Q + 1'b1): Q; i <=i+ 1'
b1; end
else begin Dend<= Dend + Dsor;Q <
=Q + 1'b1;end
2:beginisDone <= 1'b1;i<= i +1'b1; end 3: begin isDone <= 1'b0; i <= 4'd0;end
endcase
assignDone_Sig= isDone;
assignQuotient =Q;
assignReminder= Dend;
endmodule
除法器2
modulediv(a,b,clk,result,yu)
input[3:0]a,b;
outputreg[3:0] result,yu;
input clk;reg[1:0]state;reg[3:0] m,n;
parameter S0=2'b00,S1=2'b01,S2=2'b10;
always@(posedge clk)
begin case(state)
S0: begin if(a>b) beginn<=a-b;m<=4'b0001; state<=S1;end
else begin m<=4'b0000;n<=a; state<=S2; end
end
S1: begin if(n>=b) begin m<=m+1;n<=n-b;state<=S1;end
else begin state<=S2;end
end
S2:beginresult<=m;yu<=n;state<=S0;end
defule:state<=S0;
endcase
end
endmodule
13、一个可预置初值的7进制循环计数器
①verilog
module count(clk,reset,load,date,out);
input load,clk,reset;
input[3:0] date;
output reg[3:0]out;
parameter WIDTH=4'd7;
always@(clkor reset)
begin
if(reset) out<=4'd0;
else if(load)?out<=date;
?elseif(out==WIDTH-1) out<=4'd0;
else ?out<=out+1;
end
endmodule
Johnson计数器
约翰逊(Johnson)计数器又称扭环计数器,是一种用n位触发器来表示2n个状态的计数器。它与环形计数器不同,后者用n位触发器仅可表示n个状态。n位二进制计数器(n为触发器的个数)有2^n个状态。若以四位二进制计数器为例,它可表示16个状态。
“0000-1000-1100-1110-1111-0111-0011-0001-0000-1000……”
module Johnson(input clk,input clr,output reg[N-1:0]q);
always@(posedgeclk or negedge clr)
if(!clr)?q<={N{1’b0}}
else if(!q[0]) q<={1’b1,q[N-1:1]};
else??q<={1’b0,q[N-1]:1}];
endmodule
任意分频,占空比不为50%
always(clk)
?begin?if(count==x-1) count<=0;
??else?count<=count+1;?end
assign clkout=count[y]?//y一般用count的最高位
偶数分频(8分频,占空比50%)(计数至n-1,翻转)
module count5(reset,clk,out)
input clk,reset; output out;
reg[1:0]count;
always@(clk)
if(reset) begincount<=0; out<=0; end
else if(count==3)?begin count<=0;out<=!out: end
else count<=count+1;
endmodule
奇数分频电路(占空比50%)。
module count5(reset,clk,out)
input clk,reset;?output out;
reg[2:0] m,n;
reg count1;regcount2;
always@(posedge clk)
begin
?if(reset) ?beginm<=0;count1<=0;end
?else?begin if(m==4)m<=0; else m<=m+1; //“4”为分频数NUM-1,NUM=5
if(m<2)count1<=1; elsecount1<=0;?end
end
always@(negedgeclk)
begin
if(reset) begin?n<=0;count2<=0;end
else begin?if(n==4) n<=0; else n<=n+1;
if(n<2)count2<=1;else count2<=0;?end
end
assign out=count1|count2;
半整数分频
module fdiv5_5(clkin,clr,clkout)
inputclkin,clr;?outputreg clkout;
reg clk1; wire clk2; integer count;
xorxor1(clk2,clkin,clk1)
always@(posedgeclkout or negedgeclr)
begin?if(~clr) begin clk1<=1’b0; end
elseclk1<=~clk1;
end
always@(posedge clk2 or negedgeclr)
begin?if(~clr)
begin count<=0; clkout<=1’b0; end
?elseif(count==5)
??begin count<=0; clkout<=1’b1; end
?elsebegin count<=count+1; clkout<=1’b0; end
end
endmodule
小数分频
N=M/P.N为分配比,M为分频器输入脉冲数,P为分频器输出脉冲数。
N=(8×9+9×1)/(9+1)=8.1先做9次8分频再做1次9分频。
module fdiv8_1(clkin,rst,clkout)
input clkin,rst; output reg clkout;
reg[3:0] cnt1,cnt2;
always@(posedgeclkinorposedge rst)
begin if(rst) begin cnt1<=0;cnt2<=0;clkout<=0; end
elseif(cnt1<9) //cnt1, 0~8 begin
if(cnt2<7) begin cnt2<=cnt2+1;clkout<=0; end
else begin cnt2<=0;cnt1<=cnt1+1;clkout<=1;end
end
elsebegin //cnt1, 9
if(cnt2<8) begin cnt2<=cnt2+1;clkout<=0; end
else begin cnt2<=0;cnt1<=0;clkout<=1;end
end
end
endmodule
串并转换
module p2s(clk,clr,load,pi,so)
inputclk,clr,load;
input[3:0] pi;
output so;
reg[3:0]r;
always@(posedgeclk or negedgeclr)
if(~clr)?r<=4'h0;
else if(load) r<=pi;
else r<={r, 1'b0}; // or r<<1;
assignso=r[3];
endmodule
module s2p(clk,clr,en,si,po)
inputclk,clr,en,si;
output[3:0] po;
always@(posedge clk or negedge clr)
if(~clr)?r<=8’ho;
else r<={r,si};
assign po=(en) ?r :4’h0;
endmodule
b) 试用VHDL或VERILOG、ABLE描述8位D触发器逻辑。module dff(q,qn,d,clk,set,reset)
input[7:0] d,set;
input clk,reset;
output reg[7:0] q,qn;
always @(posedge clk)
begin
if(reset) begin?q<=8’h00; qn<=8’hFF; end
else if(set) begin q<=8’hFF; qn<=8’h00; endelse begin q<=d; qn<=~d;end
end
endmodule
序列检测“101”
module xulie101(clk,clr,x,z);
input clk,clr,x;output reg z;
reg[1:0]state,next_state;
parameter s0=2'b00,s1=2'b01,s2=2'b11,s3=2'b10;
always @(posedge clk or posedge clr)
begin if(clr) state<=s0;
elsestate<=next_state;
end
always @(state or x)
begin
case(state)
s0:begin if(x)?next_state<=s1;
?? else next_state<=s0;end
s1:begin if(x)?next_state<=s1;
?else next_state<=s2;end
?s2:begin if(x)?next_state<=s3;
??else next_state<=s0;end
?s3:beginif(x) next_state<=s1;
?elsenext_state<=s2;end
?default: next_state<=s0;
endcase
end
always @(state)
begin case(state)
??s3:z=1;
?default:z=0;
?endcase
end
endmodule
?
按键消抖
1.采用一个频率较低的时钟,对输入进行采样,消除抖动。
module switch(clk,keyin,keyout)
parameterCOUNTWIDTH=8;
input clk,keyin; output reg keyout; reg[COUNTWIDTH-1:0]counter; wireclk_use; //频率较低的时钟
assignclk_use=counter[COUNTWIDTH-1];
always@(posegde clk)
counter<=counter+1’b1;
always@(posedge clk_use)
?keyout<=keyin;
endmodule
2.module switch(clk,keyin,keyout)
parameter COUNTWIDTH=8;
input clk,keyin;?outputregkeyout;reg[COUNTWIDTH-1:0]counter; initial ?counter<=0,keyout<=0,keyin<=0;
always@(posegde clk)
if(keyin=1)begin key_m<=keyin, counter<=counter+1;end
?else counter<=0;
?if(keyin&&counter[m]) keyout<=1; //m定义时延
endmodule
数码管显示
modulenumber_mod_module ??//分别取得数字的十位和个位
(CLK, RSTn, Number_Data, Ten_Data, One_Data);
inputCLK;
input RSTn;
? input[7:0]Number_Data;
output[3:0]Ten_Data;
output[3:0]One_Data;
?reg [31:0]rTen;
?reg [31:0]rOne;
always @ (posedge CLKornegedge RSTn)
if( !RSTn)
begin
???rTen<= 32'd0;
???rOne <= 32'd0;
?end
?else
?begin
??rTen <= Number_Data / 10;
??rOne <= Number_Data%10;
?end
?assign Ten_Data =rTen[3:0];
?assign One_Data =rOne[3:0];
endmodule
moduleled(CLK, Ten_Data, One_Data,led0, led1);?//数码管显示input [3:0] Ten_Data,One_Data;
?inputCLK;
output [7:0] led0,led1;
?reg [7:0]led0, led1;
always@( posedgecp_50)
begin
???casez (One_Data)
??4'd0 : led0= 8'b1100_0000;
???4'd1 : led0 = 8'b1111_1001;
?4'd2: led0 =8'b1010_0100;
??4'd3 : led0 =8'b1011_0000;
???4'd4 : led0 = 8'b1001_1001;
???4'd5 : led0 = 8'b1001_0010;
?????4'd6: led0 = 8'b1000_0010;
???4'd7 :led0 =8'b1111_1000;
??4'd8 : led0 = 8'b1000_0000;
???4'd9:led0= 8'b1001_0000;?
????default: led0 = 8'b1111_1111; ?
?endcase
???casez (Ten_Data)
????4'd0 :led1=8'b1100_0000;
???4'd1 : led1 = 8'b1111_1001;
??4'd2 : led1=8'b1010_0100;
???4'd3 :led1 = 8'b1011_0000;
?4'd4 : led1 = 8'b1001_1001;
???4'd5 :led1 = 8'b1001_0010;
????4'd6 : led1= 8'b1000_0010;
?4'd7 : led1 =8'b1111_1000;
?4'd8 : led1 = 8'b1000_0000;
????4'd9: led1 = 8'b1001_0000;?
????default: led0= 8'b1111_1111; ??
?endcase
??end
endmodule
5. fifo控制器.
FIFO存储器FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。在系统设计中,以增加数据传输率、处理大量数据流、匹配具有不同传输率的系统为目的而广泛使用FIFO存储器,从而提高了系统性能.
FIFO参数:
FIFO的宽度,thewidth,指FIFO一次读写操作的数据位;
FIFO深度,THE DEEPTH,指FIFO可以存储多少个N位的数据;
满标志,FIFO已满或将要满时送出的一个信号,以阻止FIFO的血操作继续向FIFO中写数据而造成溢出(overflow);
空标志,阻止FIFIO的读操作;
module fifo_module
(
input CLK,
input RSTn,
input Write_Req,
input [7:0]FIFO_Write_Data,
inputRead_Req,
output[7:0]FIFO_Read_Data,
output Full_Sig,
output Empty_Sig,
/**********************/
output [7:0]SQ_rS1,
output[7:0]SQ_rS2,
output [7:0]SQ_rS3,
output [7:0]SQ_rS4,
output [2:0]SQ_Count
/**********************/
);
/************************************/
parameter DEEP=3'd4;
/************************************/
reg [7:0]rShift [DEEP:0];
reg [2:0]Count;
reg [7:0]Data;
always @ ( posedge CLKor negedge RSTn)
if( !RSTn )
begin
rShift[0] <= 8'd0; rShift[1]<= 8'd0; rShift[2] <=8'd0;
rShift[3]<= 8'd0; rShift[4] <= 8'd0;
Count <=3'd0;
Data <=8'd0;
end
elseif( Read_Req && Write_Req&&Count <DEEP && Count > 0 ) begin
rShift[1] <= FIFO_Write_Data;
rShift[2] <= rShift[1];
rShift[3] <= rShift[2];
rShift[4] <=rShift[3];
Data <= rShift[ Count];
end
else if( Write_Req &&Count < DEEP )
begin
rShift[1] <= FIFO_Write_Data;
rShift[2]<= rShift[1];
rShift[3] <= rShift[2];
rShift[4] <= rShift[3];
Count <= Count+1'b1;
end
else if( Read_Req &&Count>0)
begin
Data <= rShift[Count];
Count <= Count - 1'b1;
end
/************************************/
assign FIFO_Read_Data= Data;
assign Full_Sig = (Count == DEEP ) ?1'b1 : 1'b0;
assignEmpty_Sig= (Count== 0 )? 1'b1 : 1'b0;
/************************************/
assign SQ_rS1= rShift[1];
assign SQ_rS2 = rShift[2];
assignSQ_rS3= rShift[3];
assign SQ_rS4 = rShift[4];
assign SQ_Count =Count;
/************************************/
Endmodule
fifi2 (指针控制)
module FIFO(date,q,clr,clk,we,re,ff,ef);
parameter WIDTH=8,DEEPTH=8,ADDR=3;
inputclk,clr;
input we,re;
input[WIDTH-1:0] date;
outputff,ef;
output reg[WIDTH-1:0] q;
reg[WIDTH-1:0] mem_date[DEEPTH-1:0];
reg[ADDR-1:0] waddr,raddr; reg ff,ef;
always@(posedge clkor negedgeclr) //写地址
begin if(!clr) waddr=0;
?else if(we==1&&ff==0) waddr=waddr+1;
?elseif(we==1&&ff==0&&waddr==7) waddr=0;
end
always@(posedge clk)
begin if(we&&!ff) mem_date[waddr]=date; end
always@(posedgeclk or negedge clr)?//读地址
begin if(!clr)raddr=0;
?elseif(re==1&&ef==0) raddr=waddr+1;
??elseif(re==1&&ef==0&&raddr==7)raddr=0;
end
always@(posedge clk)
begin if(re&&!ef) q=mem_date[raddr];?end
always@(posedgeclk or negedgeclr)
begin if(!clr) ff=1'b0;
??else if((we & !re) && ((waddr==raddr-1) || ((waddr==DEEPTH-1) &&(raddr==1'b0))))
??ff=1'b1;
?else ff=1'b0;
end
always@(posedge clk or negedge clr)
beginif(!clr)ef=1'b0;
?else if(((!we&re)&&(waddr==raddr+1)||((raddr==DEEPTH-1)&&(waddr==1'b0))))
?ef=1'b1;
?else ef=1'b0;
end
endmodule
交通信号灯
module jiaotong(clk,reset,lamp,downtime);
inputclk,reset;
output reg [5:0]lamp;
output[6:0]downtime;
reg [6:0]timedown;
reg[1:0]state;
reg [31:0]count1;
always@(clk)//产生0~100s的计时
begin
if(reset) count1<=0;//计数器必须赋初值,否者无法进行计数
elseif(count1==32'd100) count1<=0;
else count1<=count1+1;
end
always@(clkor count1)
begin
if(reset) state<=0;
else if(count1>=32'd1&&count1<=32'd45)state=0;
else if(count1>=32'd46&&count1<=32'd50) state=1;
else if(count1>=32'd51&&count1<=32'd95) state=2;
elseif(count1>=32'd96&&count1<=32'd100) state=3;
end
always@(clk)
begin
case(state)//state只能在一个过程快内被赋值,所以其复位操作放在前一个always块中
0:beginlamp<=6'b100001;timedown<='d45-count1;end
1:begin lamp<=6'b010001;timedown<='d50-count1;end
2:begin lamp<=6'b001100; timedown<='d95-count1;end
3:beginlamp<=6'b001010; timedown<='d100-count1;end
endcase
end
assign downtime=timedown;
endmodule
仿真激励:
`timescale 1ms/1ms
`include "jiaotong.v"
module jiaotong_tp;
reg clk; regreset;
wire [5:0]lamp;
wire [6:0]downtime; //输出需用wire型
jiaotong u1(
.clk(clk),
.reset(reset),
.lamp(lamp),
.downtime(downtime)
);
initial
begin
clk=0; reset=0;
#500 reset=1;
#500 reset=0; //需统一放入begin-end块中
end
always #500 clk=~clk;
initial $monitor($time,,,"clk=%bcount1=%d",clk,count1); //只是在调试过程中监控count1的计数状态
endmodule