Write in front
Write a new pit: recommend a very good website for practicing Verilog. There are one or two hundred questions, which basically covers all aspects of Verilog grammar. It is a very good introductory learning website. Website connection: HDLBits
The questions are all done by ourselves. They are the correct answers that have been verified. By the way, their own ideas for solving problems are attached. Each topic only lists one method, but I know that many topics have many solutions, and the time relationship is not listed one by one. Hope to help you.
Today, we will update the three sections of the Verilog Language chapter: Modules:Heirarchy, Procedures, and More Verilog Features.
2.3,Modules:Heirarchy
2.3.1,Modules
Personal thoughts:
Two ways of modularization are mainly investigated: one-to-one correspondence according to the signal name; According to the signal position of the exemplified module.
Here, just use one method to instantiate. Personally, I suggest using the instantiation method of one-to-one correspondence according to the name, which is more intuitive.
module top_module ( input a, input b, output out ); mod_a mod_a_inst( .in1 (a), .in2 (b), .out (out) ); endmodule
2.3.2,Connecting ports by position
Personal thoughts:
It mainly investigates the modularization according to the signal position of the instantiated module.
When instantiating the module here, pay attention to the order consistent with the signal order of the instantiated module. This method is usually not recommended. It is easy to be scolded by leaders in this way.
module top_module ( input a, input b, input c, input d, output out1, output out2 ); mod_a mod_a_inst(out1,out2,a,b,c,d); endmodule
2.3.3,Connecting ports by name
Personal thoughts:
It mainly investigates the modularization according to the one-to-one correspondence of the signal names of the instantiated modules.
This method is usually recommended, which is intuitive and portable.
module top_module ( input a, input b, input c, input d, output out1, output out2 ); mod_a mod_a_inst( .in1(a), .in2(b), .in3(c), .in4(d), .out1(out1), .out2(out2) ); endmodule
2.3.4,Three modules
Personal thoughts:
It mainly investigates the modularization and the ability to identify the module block diagram.
Instantiate three items according to the picture information_ DFF module is OK. Remember to make two wire variables for the two wires in the middle.
module top_module ( input clk, input d, output q ); wire q1,q2; my_dff inst1( .clk (clk), .d (d), .q (q1) ); my_dff inst2( .clk (clk), .d (q1), .q (q2) ); my_dff inst3( .clk (clk), .d (q2), .q (q) ); endmodule
2.3.5,modules and vectors
Personal thoughts:
Instantiate three items according to the picture information_ DFF module, and use the case statement to output one out of four.
module top_module ( input clk, input [7:0] d, input [1:0] sel, output [7:0] q ); wire [7:0] q1,q2,q3; always@(*)begin case(sel) 2'd0: q = d; 2'd1: q = q1; 2'd2: q = q2; 2'd3: q = q3; default:; endcase end my_dff8 inst1( .clk (clk), .d (d), .q (q1) ); my_dff8 inst2( .clk (clk), .d (q1), .q (q2) ); my_dff8 inst3( .clk (clk), .d (q2), .q (q3) ); endmodule
2.3.6,Adder 1
Personal thoughts:
The low 16 bits and high 16 bits of the input signal are instantiated respectively, and the two full adder modules are added. A wire variable connection is required for carry.
module top_module( input [31:0] a, input [31:0] b, output [31:0] sum ); wire cout_2_cin; add16 u1_add16( .a (a[15:0] ), .b (b[15:0] ), .cin (1'b0 ), .sum (sum[15:0] ), .cout (cout_2_cin ) ); add16 u2_add16( .a (a[31:16] ), .b (b[31:16] ), .cin (cout_2_cin ), .sum (sum[31:16] ), .cout ( ) ); endmodule
2.3.7,Adder 2
Personal thoughts:
Follow 2.3 6 is actually the same, just that you need to write a full adder module yourself.
module top_module ( input [31:0] a, input [31:0] b, output [31:0] sum );// wire cout_2_cin; add16 inst1( .a (a[15:0] ), .b (b[15:0] ), .cin (1'b0 ), .cout (cout_2_cin ), .sum (sum[15:0] ) ); add16 inst2( .a (a[31:16] ), .b (b[31:16] ), .cin (cout_2_cin ), .cout ( ), .sum (sum[31:16] ) ); endmodule module add1 ( input a, input b, input cin, output sum, output cout ); assign {cout,sum} = a + b + cin; endmodule
2.3.8,Carry-select adder
Personal thoughts:
A carry selection adder is implemented according to the picture information. The specific principle is not studied in depth. Here is a reference: [FPGA/IC] common test adder summary
The implementation only needs to instantiate three sub modules and add some wire variables.
module top_module( input [31:0] a, input [31:0] b, output [31:0] sum ); wire [15:0] sum1,sum2,sum3; wire cout; assign sum = cout ? {sum3,sum1} : {sum2,sum1}; add16 inst1( .a (a[15:0] ), .b (b[15:0] ), .cin (1'b0 ), .cout (cout ), .sum (sum1 ) ); add16 inst2( .a (a[31:16] ), .b (b[31:16] ), .cin (1'b0 ), .cout ( ), .sum (sum2 ) ); add16 inst3( .a (a[31:16] ), .b (b[31:16] ), .cin (1'b1 ), .cout ( ), .sum (sum3 ) ); endmodule
2.3.9,Adder subtractor
Personal thoughts:
It can be realized according to the picture information.
module top_module( input [31:0] a, input [31:0] b, input sub, output [31:0] sum ); wire [31:0] temp_b; wire cout_2_cin; assign temp_b = {32{sub}} ^ b; add16 inst1( .a (a[15:0] ), .b (temp_b[15:0] ), .cin (sub ), .cout (cout_2_cin ), .sum (sum[15:0] ) ); add16 inst2( .a (a[31:16] ), .b (temp_b[31:16] ), .cin (cout_2_cin ), .cout ( ), .sum (sum[31:16] ) ); endmodule
2.4,Procedures
2.4.1,Always blocks(combination)
Personal thoughts:
Two ways of assignment in combinatorial logic are investigated.
Use assign and always @ (*) to assign values to variables respectively.
// 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
2.4.2,Always blocks(blocked)
Personal thoughts:
Two ways of assignment of combinatorial logic are investigated; Investigate the assignment mode of temporal logic. Remember that combinatorial logic uses blocking assignment: "=" and sequential logic uses non blocking assignment: "< =". Refer to: Blocking assignment (=) and non blocking assignment (< =)
Assign and always @ (*) are used to assign values to variables in combination respectively; Use always@(clk) to assign a value to the sequential logic.
// 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
2.4.3,If statement
Personal thoughts:
The use of ternary operators of combinatorial logic assignment and if else statements are investigated;
You can assign values to variables by using the ternary operator and if else statement respectively.
// 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 ?(sel_b2 ? b : a): a; always@(*)begin if(sel_b1 && sel_b2) out_always = b; else out_always = a; end endmodule
2.4.4,If statement latches
Personal thoughts:
This paper mainly investigates how to prevent the generation of latch.
If you complete the if else in the title, there will be no latch.
// 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 = ~gas_tank_empty; else keep_driving = 0; end endmodule
2.4.5,Case statement
Personal thoughts:
Mainly focus on the use of case statements. Remember to use default to indicate other situations, otherwise latches will be generated. I suggest that even if all the situations are listed, you can also write a default + empty statement to form a good habit.
According to the corresponding relationship, use the case statement to give examples one by one.
// 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 // This is a combinational circuit 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 <= 4'd0; endcase end endmodule
2.4.6,Priority encoder
Personal thoughts:
This paper mainly investigates the use of finite decoder.
You can use a case statement. If the condition is 1, that is, the corresponding statement will be executed when the bit is 1.
// synthesis verilog_input_version verilog_2001 module top_module ( input [3:0] in, output reg [1:0] pos ); always@(*)begin case(1) in[0] : pos = 2'd0; in[1] : pos = 2'd1; in[2] : pos = 2'd2; in[3] : pos = 2'd3; default: pos = 2'd0; endcase end endmodule
2.4.7,Priority encoder with casez
Personal thoughts:
It mainly investigates the use of casez statements. The casez statement indicates that the bits set to z can be ignored and only the bits set to 1 and 0.
Use the casez statement to set the corresponding bits to 1 respectively.
// synthesis verilog_input_version verilog_2001 module top_module ( input [7:0] in, output reg [2:0] pos ); always@(*)begin casez(in) 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
2.4.8,Avoiding latches
Personal thoughts:
This paper mainly investigates how to avoid latch. Methods include: if else completion, case statement using default completion, etc.
When using the case statement, you can assign an initial default value to the variable.
// 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: left = 1'b1; 16'he072: down = 1'b1; 16'he074: right = 1'b1; 16'he075: up = 1'b1; endcase end endmodule
2.5,More Verilog Features
2.5.1,conditional ternary operator
Personal thoughts:
This paper mainly investigates the use of binocular selection operator.
You can compare the two first, and then compare the two smaller ones to find the smallest one. It seems that the program is not so bloated.
module top_module ( input [7:0] a, b, c, d, output [7:0] min);// wire [7:0] min1,min2; assign min1 = (a<b) ? a : b; assign min2 = (c<d) ? c : d; assign min = (min1<min2) ? min1 : min2; // assign intermediate_result1 = compare? true: false; endmodule
2.5.2,reduction operator
Personal thoughts:
It mainly focuses on the use of reduction operators. You can refer to: Verilog decrement operator
Use the reduction operator to bitwise XOR.
module top_module ( input [7:0] in, output parity); assign parity = ^in; endmodule
2.5.3,reduction : even wider gates
Personal thoughts:
Same as 2.5 2. It's just that the input digits are wider.
Use the reduction operator to differ by and, or, or.
module top_module( input [99:0] in, output out_and, output out_or, output out_xor ); assign out_and = ∈ assign out_or = |in; assign out_xor = ^in; endmodule
2.5.4,combinational for-loop Vector reversal 2
Personal thoughts:
Mainly investigate the use of for loop statements. Be careful not to use i + + like C language, because there is no incremental operation symbol + + in Verilog.
module top_module( input [99:0] in, output [99:0] out ); integer i; always@(*)begin for(i = 0;i < 100;i = i + 1 )begin out [i] = in[99-i]; end end endmodule
2.5.5,combinational for-loop 255-bit population count
Personal thoughts:
Mainly investigate the use of for loop statements and accumulation operation. Remember to initialize the output of accumulation operation first.
module top_module( input [254:0] in, output [7:0] out ); integer i; always@(*)begin out = 8'd0; for(i = 0;i < 255;i = i + 1 )begin out = out + in[i]; end end endmodule
2.5.6,combinational for-loop 100-bit binary adder 2
Personal thoughts:
It mainly focuses on the use of generate statements. Remember to use the begin end block (even if there is only one statement, and the begin block should be named). You can refer to: Basic understanding of generate statement in verilog syntax
When using generate to instantiate 100 full adders or perform 100 full adder operations, it should be noted that the first time is special. The carry of the first time comes from the input rather than the carry of the previous bit, so it needs to be written separately.
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:full_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
2.5.7,combinational for-loop 100-digit BCD adder
Personal thoughts:
When using generate to instantiate 100 BCD adder s, it should be noted that the first time is special. The carry of the first time comes from the input rather than the carry of the previous bit, so it needs to be written separately.
module top_module( input [399:0] a, b, input cin, output cout, output [399:0] sum ); wire[99:0] cout_to_cin; generate genvar i; for(i = 0; i <= 99; i = i + 1)begin:BCD_adder if(i == 0)begin bcd_fadd bcd_fadd_inst( .a (a[3:0] ), .b (b[3:0] ), .cin (cin ), .sum (sum[3:0] ), .cout (cout_to_cin[0] ) ); end else begin bcd_fadd bcd_fadd_inst1( .a (a[4 * i + 3: 4 * i] ), .b (b[4 * i + 3: 4 * i] ), .cin (cout_to_cin[i - 1] ), .sum (sum[4 * i + 3: 4 * i] ), .cout (cout_to_cin[i] ) ); end end assign cout = cout_to_cin[99]; endgenerate endmodule