常见面试笔试题verilog程序库
加减法
module addsub
( input [7:0] dataa,
input [7:0] datab,
input add_sub, // if this is 1, 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;"
else result <= 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。至于溢出的最高位能够无视掉。
乘法器
module mult(outcome,a,b);
parameter SIZE=8;
input[SIZE:1] a,b;
output reg[2*SIZE:1] outcome;
integer i;
always @(a or 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: begin isDone <= 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; // result of A
reg [7:0]s; // reverse result of A
reg [16:0]p; // p空间,16+1位
reg [3:0]X; //指示n次循环
reg isDone;
always @ ( posedge CLK or negedge RSTn )
if( !RSTn )
begin
i <= 4'd0;
a <= 8'd0;
s <= 8'd0;
p <= 17'd0;
X <= 4'd0;
isDone <= 1'b0;
end
else if( 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
else if( 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
else i <= 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
assign Done_Sig = isDone;
assign Product = p[16:1];
endmodule
除法器
module divider_module
(
input CLK,
input RSTn,
input Start_Sig,
input [7:0]Dividend,
input [7:0]Divisor,
output Done_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;
reg isNeg;
reg isDone;
always @ ( posedge CLK or 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 )
begin Q <= isNeg ? ( ~Q + 1'b1 ) : Q; i <= i + 1'b1; end
else begin Dend <= Dend + Dsor; Q <= Q +
1'b1; end
2: begin isDone <= 1'b1; i <= i + 1'b1; end
3: begin isDone <= 1'b0; i <= 4'd0; end
endcase
assign Done_Sig = isDone;
assign Quotient = Q;
assign Reminder = Dend;
endmodule
除法器2
module div(a,b,clk,result,yu)
input[3:0]a,b;
output reg[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) begin n<=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: begin result<=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@(clk or reset)
begin
if(reset) out<=4'd0;
else if(load) out<=date;
else if(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@(posedge clk 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) begin count<=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;reg count2;
always@(posedge clk)
begin
if(reset) begin m<=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; else count1<=0; end
end
always@(negedge clk)
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)
input clkin,clr; output reg clkout;
reg clk1; wire clk2; integer count;
xor xor1(clk2,clkin,clk1)
always@(posedge clkout or negedge clr)
begin if(~clr) begin clk1<=1’b0; end
else clk1<=~clk1;
end
always@(posedge clk2 or negedge clr)
begin if(~clr)
begin count<=0; clkout<=1’b0; end
else if(count==5)
begin count<=0; clkout<=1’b1; end
else begin 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@(posedge clkin or posedge rst)
begin if(rst) begin cnt1<=0;cnt2<=0;clkout<=0; end
else if(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
else begin //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)
input clk,clr,load;
input [3:0] pi;
output so;
reg[3:0] r;
always@(posedge clk or negedge clr)
if(~clr) r<=4'h0;
else if(load) r<=pi;
else r<={r, 1'b0}; // or r<<1;
assign so=r[3];
endmodule
module s2p(clk,clr,en,si,po)
input clk,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; end else 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;
else state<=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:begin if(x) next_state<=s1;
else next_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)
parameter COUNTWIDTH=8;
input clk,keyin;output reg keyout; reg[COUNTWIDTH-1:0] counter;
wire clk_use;//频率较低的时钟
assign clk_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;output reg keyout; 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
数码管显示
module number_mod_module //分别取得数字的十位和个位
(CLK, RSTn, Number_Data, Ten_Data, One_Data);
input CLK;
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 CLK or negedge 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
module led(CLK, Ten_Data, One_Data,led0, led1); //数码管显示
input [3:0] Ten_Data, One_Data;
input CLK;
output [7:0] led0, led1;
reg [7:0] led0, led1;
always @( posedge cp_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的宽度,the width,指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,
input Read_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 CLK or 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
else if( 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;
assign Empty_Sig = ( Count == 0 ) ? 1'b1 : 1'b0;
/************************************/
assign SQ_rS1 = rShift[1];
assign SQ_rS2 = rShift[2];
assign SQ_rS3 = rShift[3];
assign SQ_rS4 = rShift[4];
assign SQ_Count = Count;
/************************************/
Endmodule
fifi 2 (指针控制)
module FIFO(date,q,clr,clk,we,re,ff,ef);
parameter WIDTH=8,DEEPTH=8,ADDR=3;
input clk,clr;
input we,re;
input[WIDTH-1:0] date;
output ff,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 clk or negedge clr) //写地址begin if(!clr) waddr=0;
else if(we==1&&ff==0) waddr=waddr+1;
else if(we==1&&ff==0&&waddr==7) waddr=0; end
always@(posedge clk)
begin if(we&&!ff) mem_date[waddr]=date; end
always@(posedge clk or negedge clr) //读地址begin if(!clr) raddr=0;
else if(re==1&&ef==0) raddr=waddr+1;
else if(re==1&&ef==0&&raddr==7) raddr=0;
end
always@(posedge clk)
begin if(re&&!ef) q=mem_date[raddr]; end
always@(posedge clk or negedge clr)
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)
begin if(!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);
input clk,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; //计数器必须赋初值,否者无法进行计数
else if(count1==32'd100) count1<=0;
else count1<=count1+1;
end
always@(clk or 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;
else if(count1>=32'd96&&count1<=32'd100) state=3;
end
always@(clk)
begin
case(state) //state只能在一个过程快内被赋值,因此其复位操作放在前一个always块中0:begin lamp<=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:begin lamp<=6'b001010; timedown<='d100-count1;end
endcase
end
assign downtime=timedown;
endmodule
仿真激励:
`timescale 1ms/1ms
`include "jiaotong.v"
module jiaotong_tp;
reg clk; reg reset;
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=%b count1=%d",clk,count1); //只是在调试过程中监控count1的计数状态
endmodule