今天开始重新刷一遍题目,强迫自己看英文,然后再把知识点记录下来!
2022.11.16 学习打卡第一天开始!
1、wire
:线网类型,声明input和output信号时,缺省默认是wire
assign a = 3'b101; // a = 101
assign b = a; // b = 1
这种情况下隐式的创建一个单bit的wire类型,默认是1bit的变量b
2、连续性赋值assign
:声明连线关系,将等号右边的信号值驱动到左边,assign只是声明连接关系,没有声明变量类型,因而没有先后顺序。后面是组合逻辑。
3、逻辑运算符
:&& || !,输出是1bit
位运算符
:& | ~,每一位运算,输入是Nbit,输出也是Nbit
4、循环
:
//第一种
integer i;
always@(*)begin
for(i = 0; i <= 7; i = i + 1)begin
out[i] = in[7-i];
end
end
//第二种
generate
genvar i;
for(i = 0; i <= 7; i = i + 1)begin:conv
//这个地方必须给block命名conv,否则会报错
assign out[i] = in[7-i];
end
endgenerate
5、拼接运算符{ }
:中间的变量必须声明位宽,不然不知道结果是几位数。
assign a = {5{a,b,c}, {5{a}}}; //5a放到一起也要有括号,容易忘记
6、模块例化方法:按照变量顺序,按照名称例化
7、加法器
:32位加法器由两个16位加法器串联组成
16位加法器:
1位全加器:{cout,sum} = a + b + cin
(1)纹波/行波进位加法器 ripple carry adder / RCA
:Nbit的加法器由N个1bit的全加器组成。速度较慢,第二部分需要等第一部分计算完,得到它的进位再进行第二部分的计算。
//第一种方法,更简单!!!
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
generate
genvar i;
for(i = 0; i <= 99; i = i + 1)begin:adder
if(i == 0)begin
assign {cout[0], sum[0]} = a[0] + b[0] + cin;
end
else begin
assign {cout[i], sum[i]} = a[i] + b[i] + cout[i-1];
end
end
endgenerate
endmodule
//第二种方法,先写全加器,再例化100个全加器
module fulladder(
input a,
input b,
input cin,
output s,
output c);
assign {c,s} = a+b+cin;
endmodule
module top_mod(
input [99:0] a,
input [99:0] b,
input cin,
output cout,
output [99:0] sum);
wire [100:0] cin_tmp;
assign cin_tmp[0] = cin;
generate
genvar i;
for(i=0;i<=99;i=i+1)begin:adder
fulladder add1( a[i],
b[i],
cin_tmp[i],
sum[i],
cin_tmp[i+1]);
end
endgenerate
assign cout = cin_tmp[100];
endmodule
改进方法一
:假设第一部分的进位为0或者1,去计算第二部分的结果。根据第一部分的进位去选择结果。
(2)4位BCD,1位十进制的加法器
module bcd_fadd (
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
assign {cout,sum} = a+b+cin;
endmodule
现有400bit的数a和b,例化100个实现100位的加法器
module top_module(
input [399:0] a, b,
input cin,
output cout,
output [399:0] sum );
wire [99:0] cout_tmp;
generate
genvar i;
for(i=0;i<=99;i=i+1)begin:adder
if(i==0)
bcd_fadd add1(a[3:0],b[3:0],cin,cout_tmp[0],sum[3:0]);
else
bcd_fadd add2(
a[3+4*(i):4*(i)],
b[3+4*(i):4*(i)],
cout_tmp[i-1],
cout_tmp[i],
sum[3+4*(i):4*(i)]
);
end
endgenerate
assign cout = cout_tmp[99];
endmodule
8、加法器-减法器 adder-subtractor
加法器变减法器
:就是求b的补码,求补码把b取反加一。
n+n=n+1;n*n=2n
(1)把32{sub}和b进行异或,就能实现取反,同时把sub放到cin。
当sub为0时,是加法器;当sub为1时,b的32位分别取反,同时加一,是减法器。
(2)还可以sub控制二选一的选择器,为0不变,为1取反即可,进位为1。
9、避免产生latch
:case语句、ifelse语句要完整
case语句中很多都是无效状态,全部写出来比较麻烦——可以在case语句之前将输出值都赋初始值。使得在所有可能的情况下,输出都有值。
10、统计输入的向量中1的个数:把输入向量的每一个数相加即可,for循环。
[2:0] in,计算1的个数也是每一位直接相加
11、判断补码相加是否溢出:(不太理解)
[7:0] a,b,s;
如果两个数都为负数,那个相加一定为负数,但是最终s的最高位不是1,那就证明溢出了,两个数都是正数同理。
12、卡诺图化简
最小项SOP/sum of product:积之和,最常用的,与或形式。
最大项POS/prodcut of sum:和之积,或与形式
(1)d可以当作是1或者0,下面化简就是cout = a | ~b&c;
(2)cout = a ^ b ^ c ^ d;
(3)最大项和最小项
//sop:sum of product pos:product of sum
assign out_sop = c & d | ~a & ~b & c;
assign out_pos = ~((~c | ~d) & (a | b | ~c));
(4)用尽可能少的二选一选择器实现下面电路
//先固定ab变量,化简得到cd选项
assign mux_in[0] = c | d;
assign mux_in[1] = 1'b0;
assign mux_in[2] = ~d;
assign mux_in[3] = c & d;
//再把上述表达式变成二选一选择器
assign mux_in[0] = c ? 1'b1 : d;
assign mux_in[1] = 1'b0;
assign mux_in[2] = d ? 1'b0 : 1'b1;
assign mux_in[3] = c ? d : 1'b0;
13、触发器
带同步/异步、低电平/高电平复位、保持端的D触发器
14、计数器
(1)已知一个4位二进制计数器,去实现从1-12的计数器
module count4(
input clk,
input enable,
input load,
input [3:0] d,
output reg [3:0] Q
);
module top_module (
input clk,
input reset,
input enable,
output [3:0] Q,
output c_enable,
output c_load,
output [3:0] c_d
); //
assign c_enable = enable;
assign c_load = reset | ((Q == 4'd12) && (enable == 1'b1));
assign c_d = c_load ? 4'd1 : 4'd0;
count4 the_counter (clk, c_enable, c_load, c_d , Q);
endmodule
(2)已知一个模10 BCD的计数器,去实现1000的计数器,对1000hz的clk进行分频,输出1hz的信号,实现1000分频
module bcdcount (
input clk,
input reset,
input enable,
output reg [3:0] Q
);
module top_module (
input clk,
input reset,
output OneHertz,
output [2:0] c_enable
); //
wire[3:0] one, ten, hundred;
assign c_enable = {one == 4'd9 && ten == 4'd9, one == 4'd9, 1'b1};
assign OneHertz = (one == 4'd9 && ten == 4'd9 && hundred == 4'd9);
bcdcount counter0 (clk, reset, c_enable[0], one);
bcdcount counter1 (clk, reset, c_enable[1], ten);
bcdcount counter2 (clk, reset, c_enable[2], hundred);
endmodule
(3)4位二进制数表示一位十进制数,实现4位十进制数的计数器,当个、十、百位为9时,ena输出一个脉冲。
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
one_decade one (.clk(clk), .reset(reset), .enable(1'b1), .q(q[3:0]));
one_decade two (.clk(clk), .reset(reset), .enable(ena[1]),.q(q[7:4]));
one_decade three(.clk(clk), .reset(reset),.enable(ena[2]),.q(q[11:8]));
one_decade four (.clk(clk),.reset(reset),.enable(ena[3]),.q(q[15:12]));
assign ena[1] = (q[3:0] == 4'd9) ? 1'b1:1'b0;
assign ena[2] = (q[7:4] == 4'd9) && (q[3:0] == 4'd9) ? 1'b1:1'b0;
assign ena[3] = (q[11:8] == 4'd9) && (q[7:4] == 4'd9) && (q[3:0] == 4'd9)? 1'b1:1'b0;
endmodule
module one_decade (
input clk,
input reset, // Synchronous active-high reset
input enable,
output [3:0] q);
always @(posedge clk) begin
if(reset) q <= 0;
else if(enable) begin
if(q == 4'd9) q <= 0;
else q <= q + 1;
end
end
endmodule
(4)时钟计数(难)
reset:恢复到12:00:00,pm=0。
关键是清零和加一
的条件。
分成两个子模块来写,秒钟和分针都是59计数器的。小时是12计数器。
module mm_ss_bcd(
input clk,
input reset, // Synchronous active-high reset
input enable,
output [7:0] q);
always @(posedge clk) begin
if(reset) q <= 8'h0;
else if(enable)begin
if (q[7:0] == 8'h59) q[7:0] <= 4'h0;
else if(q[3:0] == 4'h9 ) begin
q[3:0] <= 4'h0;
q[7:4] <= q[7:4] + 4'h1;
end
else q[3:0] <= q[3:0] + 4'h1;
end
end
endmodule
module hh_bcd(
input clk,
input reset, // Synchronous active-high reset
input enable,
output [7:0] q);
always @(posedge clk) begin
if(reset) q <= 8'h12;
else if (enable) begin
if (q[7:0] == 8'h12) q[7:0] <= 8'h01;
else if (q[7:0] == 8'h9 ) q[7:0] <= 8'h10; //十进制数计数0-9
else q[7:0] <= q[7:0] + 4'h1;
end
end
endmodule
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
wire mm_enable,hh_enable;
mm_ss_bcd mm_ss_bcdss(.clk(clk), .reset(reset), .enable(ena), .q(ss));
mm_ss_bcd mm_ss_bcdmm(.clk(clk), .reset(reset), .enable(mm_enable), .q(mm));
hh_bcd hh_bcd_1 (.clk(clk), .reset(reset), .enable(hh_enable), .q(hh));
assign mm_enable = (ss == 8'h59) ? 1'b1:1'b0;
assign hh_enable = (mm == 8'h59) && (ss == 8'h59) ? 1'b1:1'b0;
always @(posedge clk) begin
if(reset) pm <= 0;
if((hh == 8'h11) && (mm == 8'h59) && (ss == 8'h59))
pm <= ~pm;
end
endmodule
15、线性反馈移位寄存器LFSR
组成:由寄存器和异或门组成
(1)五位LFSR
always@(posedge clk)begin
if(reset)begin
q <= 5'd1;
end
else begin
q[4] <= q[0];
q[3] <= q[4];
q[2] <= q[3] ^ q[0];
q[1] <= q[2];
q[0] <= q[1];
end
end