参考视频链接
0 基础概念
变量
线网型(wire): 表示电路间的物理连接,wire定义的变量也可看成信号端口,当两个wire信号被连续赋值时,在逻辑块中会被映射成真实的物理连线,此时这两个信号端口的变化是同步的。
寄存器型(reg): 表示一个抽象的数据存储单元,reg 具有对某一时间点状态进行保持的功能。
在always、initial语句中被赋值的变量(赋值号左边的变量)都是reg型变量,在assign语句中被赋值的变量,为wire型变量。
vector(向量),是一组信号的集合,可视为位宽超过1bit 的 wire 信号。
1 累加累乘器
`timescale 1ns/10ps
module inout_test();
parameter ratio = 2;
reg [15:0]num ;
reg [31:0]save_add_v;
reg [31:0]save_multi_v;
initial
begin
save_add_v = 100;
save_multi_v = 100;
forever begin
save_add_v = save_add_v + ratio;
save_multi_v = save_multi_v * ratio;
#1;
$display("This is a test program");
$display("save_add_v:%d,save_multi_v:%d" , save_add_v , save_multi_v);
if($time >4)
$finish;
end
end
endmodule;
输出:
2 异或、与运算求解
`timescale 1ns/10ps
module fn_sw( a , b , sel , y );
input a;
input b;
input sel;
output y;
//assign y = sel? (a^b):(a&b);
reg y;
always@(a ,b , sel)
begin
if(sel == 1)
y = a^b;
else
y = a & b;
end
endmodule;
module fn_sw_tb;
reg a,b,sel;
wire y;
fn_sw fn_sw(
.a(a),
.b( b),
.sel(sel ),
.y(y)
);
initial begin
a<=0;b<=0;sel<=0;
#10 a<=0;b<=0;sel<=1;
#10 a<=0;b<=1;sel<=0;
#10 a<=1;b<=0;sel<=0;
#10 a<=0;b<=1;sel<=0;
#10 a<=0;b<=1;sel<=1;
#10 a<=1;b<=0;sel<=0;
#10 $stop;
end;
endmodule;
2.1 匹配4种case下的求解
`timescale 1ns/10ps
module fn_sw( a , b , sel , y );
input a;
input b;
input [1:0]sel;
output y;
//assign y = sel? (a^b):(a&b);
reg y;
always@(a ,b , sel)
begin
case(sel)
2'b00:
y<= a&b;
2'b01:
y<= a|b;
2'b10:
y<= a^b;
2'b11:
y<=~(a^b);
endcase
end
endmodule;
module fn_sw_tb;
reg a,b;
reg [1:0]sel;
wire y;
fn_sw fn_sw(
.a(a),
.b( b),
.sel(sel ),
.y(y)
);
initial begin
a<=0;b<=0;sel<=0;
#10 a<=0;b<=0;sel<=1;
#10 a<=0;b<=1;sel<=2;
#10 a<=1;b<=0;sel<=3;
#10 a<=0;b<=1;sel<=0;
#10 a<=0;b<=1;sel<=1;
#10 a<=1;b<=0;sel<=2;
#10 a<=1;b<=0;sel<=3;
#10 $stop;
end;
endmodule;
3 补码计算器
正数的补码是本身;
负数的补码是符号位不变,其他位,安位取反后加1;
以8 bit数为例,可操作的位数是[6:0]
`timescale 1ns/1ns
module comp_conv(
a,
a_comp
);
input [7:0] a;
output [7:0] a_comp;
wire [6:0] b; //按位取反的幅度位
wire [7:0] y; //负数的补码
assign b = ~a[6:0];
assign y[6:0] = b+1; //按位取反+1;
assign y[7] = a[7]; //符号位不变
assign a_comp = a[7]?y:a; //2选1
endmodule;
module comp_conv_tb;
reg[7:0] a_in;
wire[7:0] y_out;
comp_conv comp_conv(
.a(a_in),
.a_comp(y_out)
);
initial begin
a_in <= 0;
#3000 $stop;
end
always #10 a_in <= a_in + 1;
endmodule
负数的补码:
正数的不变:
其中计算补码的部分,也可用一句assign 实现:
assign a_comp = a[7] ? {a[7], ~a[6:0]+1}:a;
4 计数器
每产生一个上升沿,计数值加1
`timescale 1ns/10ps
module counter(
clk,
reset,
sum,
y
);
input clk , reset;
output [15:0]y;
reg [15:0] y;
output wire [15:0] sum;// +1 运算结果
assign sum = y + 1;
always @(posedge clk or negedge reset )
begin
if (~reset)
y <= 0;
else
y <= sum;
end
endmodule
module counter_tb;
reg clk,reset;
wire [15:0] y;
wire [15:0] sum;
counter counter(
.clk(clk),
.reset(reset),
.y(y),
.sum(sum)
);
initial
begin
clk <= 0; reset <= 0;
#17 reset <= 1;
#2880;
$display("counter num is:%d", sum);
$stop;
end
always #5 clk <= ~clk;
endmodule
结果:
设定simulation run time的地方:
5 伪随机码发生器
`timescale 1ns/1ns
module m_gen(
input clk,
input rstn,
output y
);
reg [3:0] d;
assign y = d[0];
always@(posedge clk or negedge rstn)
if(~rstn)
begin
d <= 4'b1111;
end
else
begin
d[2:0] <= d[3:1]; //右移一位
d[3] <= d[3] + d[0];
end
endmodule
module m_gen_tb();
reg clk,res;
wire y;
m_gen m_gen(
.clk(clk),
.rstn(res),
.y(y)
);
initial begin
clk <= 0;res<=0;
#17 res<=1;
#2888 $stop;
end
always #5 clk <= ~clk;
endmodule