2020/3/17
module top_module(
input [2:0] a,
input [2:0] b,
output [2:0] out_or_bitwise,
output out_or_logical,
output [5:0] out_not
);
assign out_or_bitwise=a|b;//按位或
assign out_not={~b, ~a};
assign out_or_logical=a||b; //逻辑或
endmodule
补充:^代表的是异或; 每一位进行
^~代表的是同或; 每一位进行
几个向量串联可以直接assign {w,x,y,z}={a,b,c,d,e,f,2’b11};
wxyz就可分到自己对应的值;
将较小的数拓展为较大的数时,assign out={{24{in[7]}},in};
一般都是将它的符号位保留,也就是最左边的那位;
复制时,需按照以下形式进行;
assign converge1={5{a,b,c,d,e}};
assign converge2={{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}};
不能通过循环通过assign给变量赋值;
模块例化有两种方法;
实例化三个模块:
需创建中间变量,然后传值
module top_module ( input clk, input d, output q );
wire q1_d2;
wire q2_d3;
my_dff u_my_dff1(
.clk (clk),
.d (d),
.q (q1_d2)
);
my_dff u_my_dff2(
.clk (clk),
.d (q1_d2),
.q (q2_d3)
);
my_dff u_my_dff3(
.clk (clk),
.d (q2_d3),
.q (q)
);
endmodule
这个题我感觉有点难。。。。
2020/3/18
因为第三个的q没有直接和输出相连,所以需要创建一个中间变量储存,然后根据sel的值是多少,再赋值给一个暂时储存输出的中间变量,通过assign语句将值赋给q。(因为assign不能连续赋值,所以不能放在case里面,直接把值赋给q,所以需要建立一个储存输出值的中间变量);
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire [7:0] q1_d2;
wire [7:0] q2_d3;
wire [7:0] q3_data_tep;
reg [7:0] data_tep;
always@(*)begin
case(sel)
2'd0:begin
data_tep=d;
end
2'd1:begin
data_tep=q1_d2;
end
2'd2:begin
data_tep=q2_d3;
end
2'd3:begin
data_tep=q3_data_tep;
end
endcase
end
assign q=data_tep;
my_dff8 u_my_dff81(
.clk (clk),
.d (d),
.q (q1_d2)
);
my_dff8 u_my_dff82(
.clk (clk),
.d (q1_d2),
.q (q2_d3)
);
my_dff8 u_my_dff83(
.clk (clk),
.d (q2_d3),
.q (q3_data_tep)
);
endmodule
这个最后开始没读懂题,以为要建16个add1和16个add2。。。。
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire cout1_cin2,cout;
wire [15:0] sum1;
wire [15:0] sum2;
add16 add1(.a(a[15:0]), .b(b[15:0]), .cin(1'b0), .sum(sum1),.cout(cout1_cin2));
add16 add2(.a(a[31:16]),.b(b[31:16]),.cin(cout1_cin2),.sum(sum2),.cout(cout));
assign sum={sum2, sum1};
endmodule
module add1( input a, input b, input cin, output sum, output cout );
assign sum=a^b^cin;
assign cout=(a&b)|(a&cin)|(b&cin);
endmodule
多位数据和少位数据异或时,少位数据要扩增复制;
2021/3/19
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum
);
reg [99:0] sum_tmp;
reg [99:0] cout_tmp;
always@(*)begin
sum_tmp[0]=a[0]^b[0]^cin;
cout_tmp[0]=(a[0]&b[0])|(a[0]&cin)|(cin&b[0]);
for(int i=1;i<=99;i++)begin
sum_tmp[i]=a[i]^b[i]^cout_tmp[i-1];
cout_tmp[i]=(a[i]&b[i])|(a[i]&cout_tmp[i-1])|(cout_tmp[i-1]&b[i]);
end
end
assign sum=sum_tmp;
assign cout=cout_tmp;
endmodule
generate知识
module top_module(
input [399:0] a, b,
input cin,
output cout,
output [399:0] sum
);
reg [99:0] cout_temp;
reg [399:0] sum_temp;
assign sum=sum_temp;
generate
genvar i;
assign cout_temp[0]=cin;
for(i=0;i<=399;i=i+4)begin:bcdadd
bcd_fadd u_bcd_fadd(
.a (a[i+3:i]),
.b (b[i+3:i]),
.cin (cout_temp[i/4]),
.cout ((i==396)?cout:cout_temp[i/4+1]),
.sum (sum_temp[i+3:i])
);
end
endgenerate
endmodule
OR或,AND与,XOR异或,NOR或非,NAND与非,XNOR异或非(同或)。
卡洛图化简
最后加就是或,乘在一起就是与。
module top_module(
input x3,
input x2,
input x1, // three inputs
output f // one output
);
assign f=(x3&x1)|((~x3)&x2);
endmodule
2020/3/21
verilog不能使用out_tmp=in[(i3’d4+2’d3):(i3’d4)];这种形式,使用In[p:o]这种形式时,里面不能为变量。
可以用下面代替
assign out = {in[sel4+3], in[sel4+2], in[sel4+1], in[sel4+0]};
2020/3/22
我没有把补码弄清楚,导致一直判断出来是否溢出,区分出什么时候会一处溢出(原来的符号位和现在的不同即为溢出)。
assign s = a + b;
assign overflow = (a[7] & b[7] & ~s[7]) | (~a[7] & ~b[7] & s[7]);
直接用a+b就能表达求和,再加上cin就能得出最后的进位。
assign {cout,sum}=a+b+cin;
卡洛图化简的两种形式
SOP form 即与或式,对应于卡诺图就是圈1即可
POS form 即或与式, 对应于卡诺图就是圈0后,整体取反. 不用管的打其他符号可以用作化简
这个最开始还是没读懂题,后面发现就是ab固定求cd不同值时 的输出,注意顺序
assign mux_in[0]=c?1'b1:(d?1'b1:1'b0);
assign mux_in[1]=1'b0;
assign mux_in[2]=c?(d?1'b0:1'b1):(d?1'b0:1'b1);
assign mux_in[3]=c?(d?1'b1:1'b0):1'b0;
同步
always@(posedge clk)begin
这里面出现reset时,它需要在clk的上升沿到来时,才会触发。
end
异步
always@(posedge clk,posedge reset)begin
这里面出现reset时,它能够在clk或reset的任意一个上升沿到来时,都会触发。
end
边沿触发器,置位信号和clk同步
这个题一开始也没有看懂
module top_module (
input clk,
input L,
input r_in,
input q_in,
output reg Q
);
always@(posedge clk)begin
if(L)
Q<=r_in;
else
Q<=q_in;
end
endmodule
没有弄懂,需要加深,我最开始加了个中间变量在里面,在always里先把值给中间变量然后在外面赋值给z,不对,这样的话使用的是上一次的值,因该是有变化输出马上就变.不要中间变量正确。
module top_module (
input clk,
input x,
output z
);
reg q0,q1,q2;
always@(posedge clk)begin
q0<=x^q0;
q1<=x&~q1;
q2<=x|~q2;
end
assign z=~(q0|q1|q2);
endmodule
2021/3/23
这个题也是一开始完全没看懂再说什么。。。
module top_module (
input clk,
input [7:0] in,
output [7:0] pedge
);
reg [7:0] pedge_1,pedge_2;
assign pedge=pedge_1&~pedge_2;
always@(posedge clk)begin
pedge_1<=in;
pedge_2<=pedge_1;
end
endmodule
这个题太难了。。。。。。,捕获”意味着输出将保持1直到寄存器被重置(同步复位),应该就是指只要没有被清除就一直保持高电平,所以需要或。这里的复位不是清清除那两个寄存的高低电平,而是直接清除输出。
module top_module (
input clk,
input reset,
input [31:0] in,
output [31:0] out
);
wire [31:0] nedge;
reg [31:0] reg_in;
always@(posedge clk)
reg_in <= in;
assign nedge = reg_in & ~in;//下降沿检测
always@(posedge clk)begin
if(reset)
out<= 0;
else if(nedge!=0)
out<=nedge|out;
else
out<=out;
end
endmodule
这个题我想了好久还是不会。。。 它先将值储存再两个不同变量当中,然后根据clk的电平来赋值,我之前就是没想到用什么来判断。
module top_module (
input clk,
input d,
output q
);
reg co,coo;
always@(posedge clk)begin
co<=d;
end
always@(negedge clk)begin
coo<=d;
end
assign q=clk?co:coo;
endmodule
这个题我一开始没有用bcd去做,导致c_enable没有用。
module top_module (
input clk,
input reset,
output OneHertz,
output [2:0] c_enable
); //
reg [3:0] q0,q1,q2;
assign OneHertz=(q0==4'd9&&q1==4'd9&&q2==4'd9);//计时0到999,全为9时说明到一个1hz周期
assign c_enable={(q1==4'd9&&q0==4'd9),q0==4'd9,1'b1};//指明每一个bcd器开始工作的时间,借用的之前做过的bcd
bcdcount ge (clk, reset, c_enable[0], q0);
bcdcount shi (clk, reset, c_enable[1], q1);
bcdcount bai (clk, reset, c_enable[2], q2);
endmodule
2021/3/24
一直没弄懂那个时间是怎么跳的卡了几个小时。。。。后面才发现早上11点一过就算下午 ,12跳1,然后晚上11点一过,就是早上,12跳1
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss
);
reg flag;
always@(posedge clk)begin
if(reset)begin
hh[7:4]<=4'd1;
hh[3:0]<=4'd2;
mm[7:4]<=4'd0;
mm[3:0]<=4'd0;
ss[7:4]<=4'd0;
ss[3:0]<=4'd0;
pm<=1'b0;
flag=1'b0;
end
else begin
if(ena)begin
if(ss[3:0]<4'd9)
ss[3:0]<=ss[3:0]+1'b1;
else begin
ss[3:0]<=4'd0;
if(ss[7:4]<4'd5)
ss[7:4]<=ss[7:4]+1'b1;
else begin
ss[7:4]<=4'd0;
if(mm[3:0]<4'd9)
mm[3:0]<=mm[3:0]+1'b1;
else begin
mm[3:0]<=4'd0;
if(mm[7:4]<4'd5)
mm[7:4]<=mm[7:4]+1'b1;
else begin
mm[7:4]<=4'd0;
if(!pm)begin //白天
if(hh[3:0]<4'd9)begin
hh[3:0]<=hh[3:0]+1'b1;
if((hh[3:0]==4'd1)&(hh[7:4]==4'd1))begin //11
pm<=~pm;
end
else if((hh[3:0]==4'd2)&(hh[7:4]==4'd1))begin
hh[7:4]<=4'd0;
hh[3:0]<=4'd1;
end
end
else begin
hh[7:4]<=hh[7:4]+1'b1;
hh[3:0]<=4'd0;
end
end
else begin
if(hh[3:0]<4'd9)begin
hh[3:0]<=hh[3:0]+1'b1;
if(hh[7:4]==4'd1&(hh[3:0]==4'd2))begin
hh[7:4]<=4'd0;
hh[3:0]<=4'd1;
end
else if((hh[3:0]==4'd1)&(hh[7:4]==4'd1))begin //11
pm<=~pm;
end
end
else begin
hh[7:4]<=hh[7:4]+1'b1;
hh[3:0]<=4'd0;
end
end
end
end
end
end
end
else begin
hh<=hh;
mm<=mm;
ss<=ss;
pm<=pm;
end
end
end
endmodule
算数逻辑和移位逻辑的不同:算数右移时,符号位不变,以符号位为基准移动,例如1100 移动一位 1110
逻辑右移就是直接移动没有这些规则。
2021/3/28
计算某种条件的个数时,要注意是否有这个状态,例如
if(count==2'd2)
count<=2'd0;
在这里面count有2’d2这个状态,但是每个周期的count0时才作为那个使用,因为一开始的时候count0就已经使用了,还有就是尽量少用两个计数去表示一个东西,我这样会经常出错。。。。。
要使几个时钟周期里面高电平为2时输出为1,可以采用延迟打拍
例如:出现2个高电平就是 110 101 011三种情况 当满足这三种中的一种时,就输出高电平。
w_reg1 <= w;
w_reg2 <= w_reg1;
以上为打拍举例
if(w&~w_reg1&w_reg2|w&w_reg1&~w_reg2|~w&w_reg1&w_reg2)begin
z <= 1'b1;
end
2021/3/30
verilog 中
initial:它只会执行一次;
forever:它会不停的重复执行里面的内容;
#5:代表延迟5个时间。
module top_module ( );
reg clk;
initial
forever begin
clk=1'b0;
#5 clk=1'b1;
#5 clk=1'b0;
end
dut u_dut(
.clk (clk)
) ;
endmodule
initial begin
in[0]=1'b0;
in[1]=1'b0;
#10;
in[0]=1'b1;
in[1]=1'b0;
#10;
in[0]=1'b0;
in[1]=1'b1;
#10;
in[0]=1'b1;
in[1]=1'b1;
end