错题笔记
Vector1
Vector的大小端是定义的时候决定的,后面就不可以修改了
e.g
[3:0]是小端
[0:3]是大端
Vector的定义类似C语言,也有隐式定义,不要有这种写法
wire [2:0] a,b;//这是两个向量,一个4位,1个1位
使用vector可以实现大小端调换和数据部分选择
//The part-select operator can be used to access a portion of a vector:
w[3:0] // Only the lower 4 bits of w
x[1] // The lowest bit of x
x[1:1] // ...also the lowest bit of x
z[-1:-2] // Two lowest bits of z
b[3:0] // Illegal. Vector part-select must match the direction of the declaration.
b[0:3] // The *upper* 4 bits of b.
assign w[3:0] = b[0:3]; // Assign upper 4 bits of b to lower 4 bits of w. w[3]=b[0], w[2]=b[1], etc.
题目要求将一个16位的数的高低8位提取出来
按题目的要求,数据都是按小端表示的
位 15 14 13 12 | 11 10 9 8 |7 6 5 4| 3 2 1 0|
值 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0
所以正确的写法是这样的
module top_module(
input wire [15:0] in,
output wire [7:0] out_hi,
output wire [7:0] out_lo );
assign out_hi[7:0]=in[15:8];
assign out_lo[7:0]=in[7:0];
endmodule
Vectorgates
这里讲的是按位或|和逻辑或||的区别
和C语言类似的
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_logical=a||b;//逻辑或
assign out_or_bitwise=a|b;//按位或
assign out_not[2:0]=~a;
assign out_not[5:3]=~b;
endmodule
Vector3
向量的部分选择与数据拼接
e.g
{3'b111, 3'b000} => 6'b111000
{1'b1, 1'b0, 3'b101} => 5'b10101
{4'ha, 4'd10} => 8'b10101010 // 4'ha and 4'd10 are both 4'b1010 in binary
如果短的数据拼接到长的数据里,那么没有用到的部分会填0
它这里搞了个很复杂的拼接
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z );//
assign w[7:0]={a[4:0],b[4:2]};
assign x[7:0]={b[1:0],c[4:0],d[4]};
assign y[7:0]={d[3:0],e[4:1]};
assign z[7:0]={e[0],f[4:0],2'b11};//逐位拼接
endmodule
Vector4
拼接的高级玩法,多个一样的拼接可以这样写
{5{1'b1}} // 5'b11111 (or 5'd31 or 5'h1f) {2{a,b,c}} // The same as {a,b,c,a,b,c} {3'd5, {2{3'd6}}} // 9'b101_110_110. It's a concatenation of 101 with // the second vector, which is two copies of 3'b110.
题目是做一个8位有符号数转32位有符号数
如果第8位为1,也就是负数的时候,转换为32位数时前24位都是1,后8位就填写原8位有符号数
否则前24位都是0
module top_module (
input [7:0] in,
output [31:0] out );//
assign out = in[7] ? {{24{1'b1}}, in} : {{24{1'b0}}, in};
endmodule
Module shift8
模块级联+多路选择器
注意它是8路输入的
难点在多路选择器
这里要用case才行,不要用if-else写
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire[7:0] qa;//这里要写[7:0]!!!
wire[7:0] qb;
wire[7:0] qc;
my_dff8 a(clk,d,qa);
my_dff8 b(clk,qa,qb);
my_dff8 c(clk,qb,qc);
always @(*)begin
case(sel)
2'b00:q=d;
2'b01:q=qa;
2'b10:q=qb;
2'b11:q=qc;
endcase
end
endmodule
Module fadd
全加器
1位的全加器要这么写
module add1 ( input a, input b, input cin, output sum, output cout );
// Full adder module here
assign {cout,sum}=a+b+cin;
endmodule
assign那里要把进位和和都算上,输入两个数和上一级的进位
两个16位的加法器级联就可以得到32位的加法器,这种级联的叫行波进位加法器
这种加法器的缺点是高位的运算必须等待低位的运算完成,这样就有延时了
所以就有了下一题的超前进位加法器,也就是提前计算进位输出
Module cseladd
可以看看关于这两种加法器的对比
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
reg cin_0=0;
reg cin_1=1;
wire add_x_cout;
wire add_1_cout;
wire add_2_cout;
wire [15:0] sumx;
wire [15:0] sum1;
wire [15:0] sum2;
add16 add_x(a[15:0],b[15:0],cin_0,sumx[15:0],add_x_cout);
add16 add_1(a[31:16],b[31:16],cin_0,sum1[15:0],add_1_cout);
add16 add_2(a[31:16],b[31:16],cin_1,sum2[15:0],add_2_cout);
always@(*)begin
case(add_x_cout)
1'b0:sum[31:16]=sum1[15:0];
1'b1:sum[31:16]=sum2[15:0];
endcase
end
assign sum[15:0]=sumx[15:0];
endmodule
Module addsub
减法器
这里的难点在前面这个异或,需要逐位和要减的数异或,要用for循环来做
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire add1_cout;
wire add2_cout;
wire [31:0] xor_out;
integer i;
always@(*)
begin
for(i=0;i<32;i++)
begin
xor_out[i]=b[i]^sub;
end
end
add16 add1(a[15:0],xor_out[15:0],sub,sum[15:0],add1_cout);
add16 add2(a[31:16],xor_out[31:16],add1_cout,sum[31:16],add2_cout);
endmodule
Always if
对比assign和always实现同样的逻辑的不同
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always );
assign out_assign=((sel_b1==1'b1) &&(sel_b2==1'b1) )?b:a;
always @(*)begin
if((sel_b1==1'b1) &&(sel_b2==1'b1))
out_always = b;
else
out_always = a;
end
endmodule
Always casez
这里说的是casez的用法,这个与case是有区别的,可以忽略case中的部分位,减少代码的量
题目是一个8位数据选择器
// synthesis verilog_input_version verilog_2001
module top_module (
input [7:0] in,
output reg [2:0] pos );
always@(*) begin
casez(in)//casez注意
8'bzzzzzzz1:pos=3'd0;
8'bzzzzzz1z:pos=3'd1;
8'bzzzzz1zz:pos=3'd2;
8'bzzzz1zzz:pos=3'd3;
8'bzzz1zzzz:pos=3'd4;
8'bzz1zzzzz:pos=3'd5;
8'bz1zzzzzz:pos=3'd6;
8'b1zzzzzzz:pos=3'd7;
default:pos=3'd0;
endcase
end
endmodule
Always nolatches
避免锁存器的出现,always一定要有一个默认的输出
// synthesis verilog_input_version verilog_2001
module top_module (
input [15:0] scancode,
output reg left,
output reg down,
output reg right,
output reg up );
always@(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;//默认输出
case(scancode)
16'he06b:begin
up = 1'b0; down = 1'b0; left = 1'b1; right = 1'b0;
end
16'he072:begin
up = 1'b0; down = 1'b1; left = 1'b0; right = 1'b0;
end
16'he074:begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b1;
end
16'he075:begin
up = 1'b1; down = 1'b0; left = 1'b0; right = 1'b0;
end
default:begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
end
endcase
end
endmodule