实验一:四选一选择器
// module test3, 选择器(mux)的代码,
module test3(
IN0 , // input 1
IN1 , // input 2
IN2 , // input 3
IN3 , // input 4
SEL1 , // select
SEL2 ,
OUT ); // out data
parameter WL = 16; // 输入输出数据信号位宽
input [WL-1:0] IN0, IN1, IN2, IN3;// 选择器的两个输入数据信号
input SEL1,SEL2; // 通道选通的控制信号
output[WL-1:0] OUT; // 选择器的输入数据信号
reg [WL-1:0] OUT;
// 生成组合逻辑的代码
always @ (IN0 or IN1 or IN2 or IN3 or SEL1 or SEL2) begin
if(SEL1==0 && SEL2==0) // SEL为1 选择输入1
OUT = IN0;
else if(SEL1==1 && SEL2==0)
OUT = IN1;
else if(SEL1==0 && SEL2==1) // SEL为0 选择输入0
OUT = IN2;
else
OUT = IN3;
end
endmodule
// endmodule top
时序图:
编码得出的二选一选择器结构:
二选一选择器消耗资源:
编码得出的四选一选择器结构
四选一选择器消耗资源:
实验二:4x4交叉选择器
代码:
// module top, a 2x2 crossbar switch circuit
module test4(
IN0 , // input 1
IN1 , // input 2
IN2 , // input 3
IN3 , // input 4
SEL0 , // select the output0 source
SEL1 , // select the output1 source
SEL2 , // select the output2 source
SEL3 , // select the output3 source
OUT0 , // output data 0
OUT1 ,
OUT2 ,
OUT3 ,
); // output data 1
parameter WL = 16;
input [WL-1:0] IN0, IN1, IN2, IN3;
input SEL0, SEL1, SEL2, SEL3;
output[WL-1:0] OUT0, OUT1, OUT2, OUT3;
reg [WL-1:0] OUT0, OUT1, OUT2, OUT3;
// get the OUT0
always @ (IN0 or IN1 or IN2 or IN3 or SEL0 or SEL1) begin
if(SEL0==0 && SEL1==0)
OUT0 = IN0;
else if(SEL0==1 && SEL1==0)
OUT0 = IN1;
else if(SEL0==0 && SEL1==1)
OUT0 = IN2;
else
OUT0 = IN3;
end
// get the OUT1
always @ (IN0 or IN1 or IN2 or IN3 or SEL1 or SEL2) begin
if(SEL1==0 && SEL2==0)
OUT1 = IN0;
else if(SEL1==1 && SEL2==0)
OUT1 = IN1;
else if(SEL1==0 && SEL2==1)
OUT1 = IN2;
else
OUT1 = IN3;
end
// get the OUT2
always @ (IN0 or IN1 or IN2 or IN3 or SEL2 or SEL3) begin
if(SEL2==0 && SEL3==0)
OUT2 = IN0;
else if(SEL2==1 && SEL3==0)
OUT2 = IN1;
else if(SEL2==0 && SEL3==1)
OUT2 = IN2;
else
OUT2 = IN3;
end
// get the OUT1
always @ (IN0 or IN1 or IN2 or IN3 or SEL0 or SEL3) begin
if(SEL0==0 && SEL3==0)
OUT3 = IN0;
else if(SEL0==1 && SEL3==0)
OUT3 = IN1;
else if(SEL0==0 && SEL3==1)
OUT3 = IN2;
else
OUT3 = IN3;
end
endmodule
// endmodule top
4x4选择器消耗资源
2X2选择器消耗资源
RTL结构图
实验三:8输入优先编码器
设计8输入优先编码器只需要对4输入优先编码器进行简单的修改,代码如下:
// module top, 4 input priority encoder with zero input check
module test5(
IN , // input
OUT ); // output
input [7:0] IN;
output[3:0] OUT;
reg [2:0] OUT;
// get the OUT
always @ (IN) begin
if(IN[7]) // 第一优先
OUT = 4'b0111;
else if(IN[6]) // 第二优先
OUT = 4'b0110;
else if(IN[5]) // 第三优先
OUT = 4'b0101;
else if(IN[4]) // 第四优先
OUT = 4'b0100;
else if(IN[3]) // 第四优先
OUT = 4'b0011;
else if(IN[2]) // 第四优先
OUT = 4'b0010;
else if(IN[1]) // 第四优先
OUT = 4'b0001;
else if(IN[0]) // 第四优先
OUT = 4'b0000;
else // 什么都没有检测到
OUT = 4'b1111; // 输出值可自定义,不和上面的输出值混淆即可
end
endmodule
时序图:
其RTL图如下:
实验四:4-16译码器、
代码:
// module top, 4 input priority encoder with zero input check
module test6(
IN , // input
OUT ); // output
input [3:0] IN;
output[15:0] OUT;
reg [15:0] OUT;
// get the OUT
always @ (IN) begin
case(IN)
4'b0000: OUT = 16'b0000_0000_0000_0001;
4'b0001: OUT = 16'b0000_0000_0000_0010;
4'b0010: OUT = 16'b0000_0000_0000_0100;
4'b0011: OUT = 16'b0000_0000_0000_1000;
4'b0100: OUT = 16'b0000_0000_0001_0000;
4'b0101: OUT = 16'b0000_0000_0010_0000;
4'b0110: OUT = 16'b0000_0000_0100_0000;
4'b0111: OUT = 16'b0000_0000_1000_0000;
4'b1000: OUT = 16'b0000_0001_0000_0000;
4'b1001: OUT = 16'b0000_0010_0000_0000;
4'b1010: OUT = 16'b0000_0100_0000_0000;
4'b1011: OUT = 16'b0000_1000_0000_0000;
4'b1100: OUT = 16'b0001_0000_0000_0000;
4'b1101: OUT = 16'b0010_0000_0000_0000;
4'b1110: OUT = 16'b0100_0000_0000_0000;
4'b1111: OUT = 16'b1000_0000_0000_0000;
// full case 不需要写default,否则一定要有default
endcase
end
endmodule
3-8译码器的资源开销:
4-16译码器的资源开销:
RTL图:
实验五:加法器
代码如下:
module test7(
IN1 ,
IN2 ,
OUT );
input[3:0] IN1, IN2;
output[3:0] OUT;
reg[3:0] OUT;
always@(IN1 or IN2) begin // 生成组合逻辑的always 块
OUT = IN1 + IN2;
end
endmodule
波形仿真图如下:
从波形仿真图中可以看出,从00变化到11并不能做到同时反转,存在过渡过程01。
00变成11与00变成10相比,后者的过渡过程偏多。
不难看出,如果输入输出信号宽度都为4比特,输出结果的大小会溢出导致结果错误。
如果将输入信号的位宽改为8比特,输出延迟会增大。例如当输入信号位宽为4比特时,输出延迟为1ns左右,改为8比特后卫2ns左右。
实验六:补码加法器
补码加法器代码与加法器相同。
可以看出当两数相加大于等于0时能够得到正确的数值结果。
增加位宽后延时加大。
实验七:带流水线的加法器
代码:
module test9(
IN1 ,
IN2 ,
CLK ,
OUT );
input [3:0] IN1, IN2;
input CLK;
output [4:0] OUT;
reg [3:0] in1_d1R, in2_d1R;
reg [4:0] adder_out, OUT;
always@(posedge CLK) begin // 生成D触发器的always块
in1_d1R <= IN1;
in2_d1R <= IN2;
OUT <= adder_out;
end
always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块
adder_out = in1_d1R + in2_d1R;
end
endmodule
一级流水线的延时低于无流水线的加法器。
实验八:双流水线加法器
代码:
module test11(
IN1 ,
IN2 ,
CLK ,
OUT ,
SUM);
input [7:0] IN1, IN2;
input CLK;
output OUT;
output [7:0] SUM;
reg [3:0] in1_d1R, in2_d1R,B;
reg A;
reg OUT;
reg [7:0]SUM;
always@(posedge CLK) begin // first line
{A,B}=IN1[3:0] + IN2[3:0];
in1_d1R = IN1[7:4];
in2_d1R = IN2[7:4];
end
always@(posedge CLK) begin // second line
{OUT,SUM[7:4]} =in1_d1R + in2_d1R + A;
SUM[3:0]=B;
end
endmodule
RTL图:
输出的时序图:
实验九:乘法器
输入位宽为8的乘法器输出时序图:
采用不包含硬件乘法器的FPGA芯片的资源开销,相应的8位加法器开销如下所示
实验十:计数器
多种信号控制计数器,其中同步清零CLR的优先级最高,使能EN次之,LOAD最低,代码如下:
计数器代码 /
module test13(
RST , // 异步复位, 高有效
CLK , // 时钟,上升沿有效
EN , // 输入的计数使能,高有效
CLR , // 输入的清零信号,高有效
LOAD , // 输入的数据加载使能信号,高有效
DATA , // 输入的加载数据信号
CNTVAL, // 输出的计数值信号
OV );// 计数溢出信号,计数值为最大值时该信号为1
input RST , CLK , EN , CLR , LOAD ;
input [3:0] DATA ;
output [3:0] CNTVAL;
output OV;
reg [3:0] CNTVAL, cnt_next;
reg OV;
// 电路编译参数,最大计数值
parameter CNT_MAX_VAL = 9;
// 组合逻辑,生成cnt_next
// 计数使能最优先,清零第二优先,加载第三优先
always @(EN or CLR or LOAD or DATA or CNTVAL) begin
if(CLR) begin // 清零有效
cnt_next = 0;
end
else begin //qingling wuxiao
if(EN) begin // 使能有效
// 使能有效,清零和加载都无效,根据当前计数值计算下一值
if(CNTVAL < CNT_MAX_VAL) begin // 未计数到最大值, 下一值加1
cnt_next = CNTVAL + 1'b1;
end
else begin // 计数到最大值,下一计数值为0
cnt_next = 0;
end
end
else begin
if(LOAD) begin // 加载有效
cnt_next = DATA;
end
else begin // 加载无效,正常计数
cnt_next = CNTVAL;
end
end // else EN
end // if clr
end
// 时序逻辑 更新下一时钟周期的计数值
// CNTVAL 会被编译为D触发器
always @ (posedge CLK or posedge RST) begin
if(RST)
CNTVAL <= 0;
else
CNTVAL <= cnt_next;
end
// 组合逻辑,生成OV
always @ (CNTVAL) begin
if(CNTVAL == CNT_MAX_VAL)
OV = 1;
else
OV = 0;
end
endmodule
///
产生的波形图如下图所示:
实验十一:状态机
代码:
三段式状态机代码 /
module test10(
CLK , // clock
RST , // reset
CENT1IN , // input 1 shuju
TINOUT ,
EN); // output 1
input CLK ;
input RST ;
input CENT1IN ;
input EN ;
output TINOUT ;
parameter ST_0_CENT = 0;
parameter ST_1_CENT = 1;
parameter ST_2_CENT = 2;
parameter ST_3_CENT = 3;
parameter ST_4_CENT = 4;
reg [2:0]stateR ;
reg [2:0]next_state ;
reg TINOUT ;
// calc next state
always @ (CENT1IN or stateR or EN) begin
case (stateR)
ST_0_CENT :begin if(CENT1IN && EN) next_state = ST_1_CENT ; else next_state = ST_0_CENT; end
ST_1_CENT :begin if(CENT1IN && EN) next_state = ST_0_CENT ; else next_state = ST_2_CENT; end
ST_2_CENT :begin if(CENT1IN && EN) next_state = ST_3_CENT ; else next_state = ST_0_CENT; end
ST_3_CENT :begin if(CENT1IN && EN) next_state = ST_4_CENT ; else next_state = ST_2_CENT; end
ST_4_CENT :begin next_state = ST_0_CENT; end
endcase
end
// calc output
always @ (stateR) begin
if(stateR == ST_4_CENT)
TINOUT = 1'b1;
else
TINOUT = 1'b0;
end
// state DFF
always @ (posedge CLK or posedge RST)begin
if(RST)
stateR <= ST_0_CENT;
else
stateR <= next_state;
end
endmodule
//
生成的状态图:
实验十二:并串转换器
代码:
module test30 (
pdin,
sdout,
en,
width_sw,
clk,
rstn
);
input [7:0] pdin; //
output sdout;
input en;
input width_sw;
input clk;
input rstn;
reg [6:0] tmp; //
reg sdout;
always @ ( posedge clk or negedge rstn )
if ( !rstn )
{tmp, sdout} <= 0;
else
if ( en ) // start p2s
{tmp, sdout} <= pdin;
else
begin
if( width_sw )
{tmp, sdout} <= {1'b0, tmp};
else
{tmp[4:0], sdout} <= {1'b0, tmp[4:0]};
end
endmodule