赞
踩
最近通过HDLBits学习verilog,写下此文记录下学习过程和一些心得,文中不对之处请各位批评指正。此文仅为1 Getting Started与2 Verilog Language两章题目,更多题目请见:
【HDLBits答案及思路(仅供参考,3 Circuits)(暂未更新)】
【HDLBits答案及思路(仅供参考,4 Verification: Reading Simulations与5 Verification: Writing Testbenches)(暂未更新)】
所有代码都通过了HDLBits网站验证,但是可能在写文修改格式时出现一些问题,所以发现有不正确之处,请联系我修改。同时,我的方法不一定是最优解决方案,仅供参考,如果朋友有更好的解决思路,也希望能够不吝赐教。注:HDLBits中模块端口声明并没有指定数据类型,我也不打算修改。
文中括号外标题对应于HDLBits首页中的标题,括号内的标题对应于具体题目左上角的标题,如● Getting Started (Step one),Getting Started是进入主页面后看到的标题,Step one是做题时左上角显示的标题。
module top_module( output one );
// Insert your code here
assign one = 1'b1;
endmodule
注:verilog进行赋值时需要注意位宽问题,最好指定位宽,1'b1
表示1位二进制数1
。
module top_module(
output zero
);// Module body starts after semicolon
assign zero = 1'b0;
endmodule
module top_module(
input in,
output out );
assign out = in;
endmodule
module top_module(
input a,b,c,
output w,x,y,z );
assign w = a;
assign x = b;
assign y = b;
assign z = c;
endmodule
module top_module( input in, output out );
assign out = !in;
endmodule
module top_module(
input a,
input b,
output out );
assign out = a & b;
endmodule
module top_module(
input a,
input b,
output out );
assign out = ~(a | b);
endmodule
module top_module(
input a,
input b,
output out );
assign out = ~(a^b);
endmodule
`default_nettype none module top_module( input a, input b, input c, input d, output out, output out_n ); wire and_ab,and_cd,or1; assign and_ab = a & b; assign and_cd = c & d; assign or1 = and_ab | and_cd; assign out = or1; assign out_n = ~or1; endmodule
module top_module (
input p1a, p1b, p1c, p1d, p1e, p1f,
output p1y,
input p2a, p2b, p2c, p2d,
output p2y );
assign p1y = (p1a & p1b & p1c) | (p1d & p1e & p1f);
assign p2y = (p2a & p2b) | (p2c & p2d);
endmodule
module top_module (
input wire [2:0] vec,
output wire [2:0] outv,
output wire o2,
output wire o1,
output wire o0 ); // Module body starts after module declaration
assign outv = vec;
assign o0 = vec[0];
assign o1 = vec[1];
assign o2 = vec[2];
endmodule
`default_nettype none // Disable implicit nets. Reduces some types of bugs.
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
module top_module(
input [31:0] in,
output [31:0] out );
assign out[31:24] = in[7:0];
assign out[23:16] = in[15:8];
assign out[15:8] = in[23:16];
assign out[7:0] = in[31:24];
endmodule
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_or_logical = a||b;
assign out_not = {~b,~a};
endmodule
module top_module( input [3:0] in, output out_and, output out_or, output out_xor ); //写法一 /*assign out_and = in[3] & in[2] & in[1] & in[0]; assign out_or = in[3] | in[2] | in[1] | in[0]; assign out_xor = in[3] ^ in[2] ^ in[1] ^ in[0];*/ //写法二 assign out_and = ∈ assign out_or = |in; assign out_xor = ^in; endmodule
注:将运算符&、|、^
放在vari[msb,lsb]
左边表示从msb
位开始按位与、或、异或到lsb
位,即:&vari==vari[msb]&…&vari[lsb]
。
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z );//
assign w = {a,b[4:2]};
assign x = {b[1:0],c[4:0],d[4]};
assign y = {d[3:0],e[4:1]};
assign z = {e[0],f,2'b11};
endmodule
注:verilog的拼接操作:{in1,in2}
。
module top_module(
input [7:0] in,
output [7:0] out
);
assign out = {in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7]};
endmodule
module top_module (
input [7:0] in,
output [31:0] out );
assign out = { {24{in[7]}},in };
endmodule
注:verilog的复制操作:{n{in}}
。
module top_module (
input a, b, c, d, e,
output [24:0] out );
assign out = ~{ {5{a}},{5{b}},{5{c}},{5{d}},{5{e}} } ^ {5{a,b,c,d,e}};
endmodule
module top_module ( input a, input b, output out );
mod_a inst1(.in1(a),
.in2(b),
.out(out));
endmodule
注:通过端口名称进行模块实例化(推荐此种方式)。
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a inst2(out1,out2,a,b,c,d);
endmodule
注:通过端口位置进行模块实例化(不推荐此种方式,因为被实例化模块端口顺序改变后,实例化的端口也得改)。
module top_module ( input a, input b, input c, input d, output out1, output out2 ); mod_a inst1(.in1(a), .in2(b), .in3(c), .in4(d), .out1(out1), .out2(out2) ); endmodule
module top_module ( input clk, input d, output q ); wire wire1; wire wire2; my_dff mod_a( .clk(clk), .d(d), .q(wire1)); my_dff mod_b( .clk(clk), .d(wire1), .q(wire2)); my_dff mod_c( .clk(clk), .d(wire2), .q(q)); endmodule
module top_module ( input clk, input [7:0] d, input [1:0] sel, output [7:0] q ); wire [7:0]wire1; wire [7:0]wire2; wire [7:0]wire3; my_dff8 moda( .clk(clk), .d(d), .q(wire1)); my_dff8 modb( .clk(clk), .d(wire1), .q(wire2)); my_dff8 modc( .clk(clk), .d(wire2), .q(wire3)); always@(*) begin case(sel) 2'b00:q=d; 2'b01:q=wire1; 2'b10:q=wire2; 2'b11:q=wire3; default:q=d; endcase end endmodule
module top_module( input [31:0] a, input [31:0] b, output [31:0] sum ); wire cin_1,cin_2; assign cin_1 = 1'b0; add16 u1_add16( .a(a[15:0]), .b(b[15:0]), .cin(cin_1),//可直接写.cin(1'b0) .cout(cin_2), .sum(sum[15:0])); add16 u2_add16( .a(a[31:16]), .b(b[31:16]), .cin(cin_2), .cout(), .sum(sum[31:16])); endmodule
module top_module ( input [31:0] a, input [31:0] b, output [31:0] sum ); wire cout_l; add16 ul_add16( .a(a[15:0]), .b(b[15:0]), .sum(sum[15:0]), .cin(1'b0), .cout(cout_l)); add16 uh_add16( .a(a[31:16]), .b(b[31:16]), .sum(sum[31:16]), .cin(cout_l), .cout()); endmodule module add1 (input a,b,cin, output sum,cout ); assign {cout,sum}=a+b+cin; endmodule
module top_module( input [31:0] a, input [31:0] b, output [31:0] sum ); wire carry; wire [15:0]sum_uh1; wire [15:0]sum_uh2; add16 ul_add16( .a(a[15:0]), .b(b[15:0]), .cin(1'b0), .sum(sum[15:0]), .cout(carry)); add16 uh1_add_16( .a(a[31:16]), .b(b[31:16]), .cin(1'b0), .sum(sum_uh1), .cout()); add16 uh2_add_16( .a(a[31:16]), .b(b[31:16]), .cin(1'b1), .sum(sum_uh2), .cout()); assign sum=carry?{sum_uh2,sum[15:0]}:{sum_uh1,sum[15:0]}; endmodule
注:进位选择加法器,用面积换速度,高位加法器有两个,一个carry_in=0
,一个carry_in=1
,当低位加法器计算出carry_out
后,通过选择器“瞬间”可以得到整个输入的结果。三目运算符:?:
。
module top_module( input [31:0] a, input [31:0] b, input sub, output [31:0] sum ); wire [31:0] bxor; wire carry; assign bxor=b^{32{sub}}; add16 add16_u1( .a(a[15:0]), .b(bxor[15:0]), .cin(sub), .sum(sum[15:0]), .cout(carry)); add16 add16_u2( .a(a[31:16]), .b(bxor[31:16]), .cin(carry), .sum(sum[31:16]), .cout()); endmodule
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always@(*)
begin
out_alwaysblock = a & b;
end
endmodule
注:assign
左侧必须为线网类型,如wire
;always
过程块中左侧必须为变量类型,如reg
。
// synthesis verilog_input_version verilog_2001 module top_module( input clk, input a, input b, output wire out_assign, output reg out_always_comb, output reg out_always_ff ); assign out_assign = a ^ b; always@(*) begin out_always_comb = a ^ b; end always@(posedge clk) begin out_always_ff = a ^ b; end endmodule
注:组合电路用always@(*)
,时序电路用always@(posedge clk)
。
// 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 && sel_b2==1) ? b : a; always@(*) begin if (sel_b1==1 && sel_b2==1) begin out_always = b; end else begin out_always = a; end end endmodule
注:三目运算符等于最基础的if-else
。
// synthesis verilog_input_version verilog_2001 module top_module ( input cpu_overheated, output reg shut_off_computer, input arrived, input gas_tank_empty, output reg keep_driving ); always @(*) begin if (cpu_overheated) shut_off_computer = 1; else shut_off_computer = 0; end always @(*) begin if (arrived) keep_driving = 0; else if(gas_tank_empty) keep_driving = 0; else keep_driving = 1; end endmodule
注:verilog中if
语句必须有else
,否则容易产生锁存latch。
// synthesis verilog_input_version verilog_2001 module top_module ( input [2:0] sel, input [3:0] data0, input [3:0] data1, input [3:0] data2, input [3:0] data3, input [3:0] data4, input [3:0] data5, output reg [3:0] out ); always@(*) begin case(sel) 3'd0:out = data0; 3'd1:out = data1; 3'd2:out = data2; 3'd3:out = data3; 3'd4:out = data4; 3'd5:out = data5; default:out = 3'd0; endcase end endmodule
注:verilog中case
语句必须有default
,否则也容易产生锁存latch。
// synthesis verilog_input_version verilog_2001 module top_module ( input [3:0] in, output reg [1:0] pos ); always@(*)begin if(in[0]==1) pos = 2'd0; else if(in[1]==1) pos = 2'd1; else if(in[2]==1) pos = 2'd2; else if(in[3]==1) pos = 2'd3; else pos = 2'd0; end endmodule
// synthesis verilog_input_version verilog_2001 module top_module ( input [7:0] in, output reg [2:0] pos ); always@(*)begin casez(in) 8'bzzzz_zzz1: pos= 3'd0; 8'bzzzz_zz10: pos= 3'd1; 8'bzzzz_z100: pos= 3'd2; 8'bzzzz_1000: pos= 3'd3; 8'bzzz1_0000: pos= 3'd4; 8'bzz10_0000: pos= 3'd5; 8'bz100_0000: pos= 3'd6; 8'b1000_0000: pos= 3'd7; default: pos= 3'd0; endcase end endmodule
注:case
:完全匹配为1
,casez
:某位的值为z
则忽略,casex
:某位的值为x
或z
则忽略。一般经常用casez
,慎用casex
。
// 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 left = 0; down = 0; right = 0; up = 0; case(scancode) 16'he06b:begin left = 1; down = 0; right = 0; up = 0; end 16'he072:begin left = 0; down = 1; right = 0; up = 0; end 16'he074:begin left = 0; down = 0; right = 1; up = 0; end 16'he075:begin left = 0; down = 0; right = 0; up = 1; end default:begin left = 0; down = 0; right = 0; up = 0; end endcase end endmodule
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);
wire [7:0] compare_ab, compare_cd;
always@(*)begin
compare_ab = a<b?a:b;
compare_cd = c<d?c:d;
min = compare_ab<compare_cd?compare_ab:compare_cd;
end
endmodule
module top_module (
input [7:0] in,
output parity);
assign parity = ^in[7:0];
endmodule
注:奇偶校验,偶校验用异或:^
,奇校验用同或:~^
。
module top_module(
input [99:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = &in[99:0];
assign out_or = |in[99:0];
assign out_xor = ^in[99:0];
endmodule
module top_module(
input [99:0] in,
output [99:0] out
);
integer i;
always@(*)begin
out = 0;
for(i=0;i<100;i=i+1)begin
out[i] = in[99-i];
end
end
endmodule
注:verilog中for
循环的循环变量定义为integer
类型。
module top_module( input [254:0] in, output [7:0] out ); integer i; always@(*)begin out = 0; for(i=0;i<255;i=i+1)begin if(in[i]==1'b1)begin out = out + 1'b1; end else begin out = out; end end end endmodule
//方法一:generate-for /*module top_module( input [99:0] a, b, input cin, output [99:0] cout, output [99:0] sum ); genvar i; generate for(i=0;i<100;i=i+1)begin:RIPPLE_CARRY_ADDER if(i==0)begin full_adder_1 fadder1( .a(a[i]), .b(b[i]), .cin(cin), .sum(sum[i]), .cout(cout[i])); end else begin full_adder_1 fadder1( .a(a[i]), .b(b[i]), .cin(cout[i-1]), .sum(sum[i]), .cout(cout[i])); end end endgenerate endmodule module full_adder_1( input a,b,cin, output cout,sum); assign {cout,sum}=a+b+cin; endmodule*/ //方法二:数组实例化 module top_module( input [99:0] a, b, input cin, output [99:0] cout, output [99:0] sum ); full_adder_1 fadd1_inst[99:0]( .a(a), .b(b), .cin({cout[98:0],cin}), .sum(sum), .cout(cout)); endmodule module full_adder_1( input a,b,cin, output cout,sum); assign {cout,sum}=a+b+cin; endmodule
注:同个模块多次实例化:使用generate-for
循环结构或者使用数组实例化。generate-for
循环结构中循环变量定义为genvar
类型,且循环位于generate
块内,for
后的begin
需接名字(标识)。数组实例化与常规实例化的区别在于实例名后需接循环数组长度,后续端口矢量长度需要与之匹配。
module top_module( input [399:0] a, b, input cin, output cout, output [399:0] sum ); reg [99:0]cout_t; /*//方法一:利用generate-for genvar i; generate for(i=0;i<100;i=i+1)begin:BCDAdd100 if(i==0)begin bcd_fadd bcdfadd_inst( .a(a[3:0]), .b(b[3:0]), .cin(cin), .sum(sum[3:0]), .cout(cout_t[0])); end else begin bcd_fadd bcdfadd_inst( .a(a[i*4+3:i*4]), .b(b[i*4+3:i*4]), .cin(cout_t[i-1]), .sum(sum[i*4+3:i*4]), .cout(cout_t[i])); end end endgenerate assign cout=cout_t[99];*/ //方法二:利用数组实例化 bcd_fadd bcdfadd_inst[99:0]( .a(a[399:0]), .b(b[399:0]), .cin({cout_t[98:0],cin}), .sum(sum[399:0]), .cout(cout_t[99:0])); assign cout=cout_t[99]; endmodule
注:for
循环中的a[i*4+3:i*4]
是允许的,因为对于每次循环而言,i
为一个定值。也可以用a[i*4+3-:4]
代替。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。