|
There are three types of modeling in Verilog, each corresponding to a different level of abstraction.
Gate-level is rarely written by hand anymore (synthesis tools do it).
Dataflow ( |
Gate-level model |
Dataflow model |
Behavioral model |
module first_module( input a, input b, output out ); and and_gate(out,a,b); endmodule |
module first_module( input a, input b, output out ); assign out = a & b; endmodule |
module first_module( input a, input b, output out ); always @(a, b) begin out = a & b; end endmodule |
//------------------------------------------------------- // 1-bit full adder (dataflow) //------------------------------------------------------- module fadder( input a, // data in a input b, // data in b input cin, // carry in output sum_out, // sum output output c_out // carry output ); wire c1, c2, c3; assign sum_out = a ^ b ^ cin; // sum = XOR of three inputs assign c1 = a & cin; assign c2 = b & cin; assign c3 = a & b; assign c_out = c1 | c2 | c3; // majority function endmodule |
//------------------------------------------------------- // 4-to-1 MUX with 1-bit inputs (combinational) //------------------------------------------------------- module mux_4to1 ( input a, input b, input c, input d, input [1:0] sel, // 2-bit select output reg out ); always @(*) begin case (sel) 2'b00: out = a; 2'b01: out = b; 2'b10: out = c; 2'b11: out = d; endcase end endmodule //------------------------------------------------------- // 4-to-1 MUX with 4-bit wide inputs //------------------------------------------------------- module mux_4to1_4bit ( input [3:0] a, input [3:0] b, input [3:0] c, input [3:0] d, input [1:0] sel, output reg [3:0] out ); always @(*) begin case (sel) 2'b00: out = a; 2'b01: out = b; 2'b10: out = c; 2'b11: out = d; endcase end endmodule |
//------------------------------------------------------- // 3-to-8 decoder (dataflow with ternary operators) //------------------------------------------------------- module decoder_3_to_8 ( output [7:0] F, input [2:0] ABC ); assign F = (ABC == 3'b000) ? 8'b0000_0001 : (ABC == 3'b001) ? 8'b0000_0010 : (ABC == 3'b010) ? 8'b0000_0100 : (ABC == 3'b011) ? 8'b0000_1000 : (ABC == 3'b100) ? 8'b0001_0000 : (ABC == 3'b101) ? 8'b0010_0000 : (ABC == 3'b110) ? 8'b0100_0000 : (ABC == 3'b111) ? 8'b1000_0000 : 8'bxxxx_xxxx; // don't-care endmodule |
//------------------------------------------------------- // 7-segment decoder (decimal 0-9) // Segment order: abcdefg (active-high) //------------------------------------------------------- module decoder_ssd_dec ( output [6:0] SSD, input [3:0] IN ); assign SSD = (IN == 4'b0000) ? 7'b1111110 : // 0 (IN == 4'b0001) ? 7'b0110000 : // 1 (IN == 4'b0010) ? 7'b1101101 : // 2 (IN == 4'b0011) ? 7'b1111001 : // 3 (IN == 4'b0100) ? 7'b0110011 : // 4 (IN == 4'b0101) ? 7'b1011011 : // 5 (IN == 4'b0110) ? 7'b1011111 : // 6 (IN == 4'b0111) ? 7'b1110000 : // 7 (IN == 4'b1000) ? 7'b1111111 : // 8 (IN == 4'b1001) ? 7'b1111011 : // 9 7'bXXXXXXX; // don't-care endmodule |
//------------------------------------------------------- // 7-segment decoder (hexadecimal 0-F) //------------------------------------------------------- module decoder_ssd_hex ( output [6:0] SSD, input [3:0] IN ); assign SSD = (IN == 4'b0000) ? 7'b1111110 : // 0 (IN == 4'b0001) ? 7'b0110000 : // 1 (IN == 4'b0010) ? 7'b1101101 : // 2 (IN == 4'b0011) ? 7'b1111001 : // 3 (IN == 4'b0100) ? 7'b0110011 : // 4 (IN == 4'b0101) ? 7'b1011011 : // 5 (IN == 4'b0110) ? 7'b1011111 : // 6 (IN == 4'b0111) ? 7'b1110000 : // 7 (IN == 4'b1000) ? 7'b1111111 : // 8 (IN == 4'b1001) ? 7'b1111011 : // 9 (IN == 4'b1010) ? 7'b1110111 : // A (IN == 4'b1011) ? 7'b0011111 : // b (IN == 4'b1100) ? 7'b0001101 : // C (IN == 4'b1101) ? 7'b0111101 : // d (IN == 4'b1110) ? 7'b1001111 : // E (IN == 4'b1111) ? 7'b1000111 : // F 7'bXXXXXXX; endmodule |
Combinational logic (assign / always @(*)) has no memory – outputs change as soon as inputs change.
Sequential logic uses a clock edge and stores state. The fundamental building block is the D flip-flop.
//------------------------------------------------------- // Simple positive-edge D flip-flop with async reset //------------------------------------------------------- module dff ( input clk, input rst, // active-high async reset input d, output reg q ); always @(posedge clk or posedge rst) begin if (rst) q <= 1'b0; else q <= d; end endmodule |
Shift registers are among the most common sequential blocks in digital design. They convert between serial and parallel data and form the heart of many serial protocols.
//------------------------------------------------------- // 8-bit serial-in, parallel-out (SIPO) shift register // Shifts left on every rising clock edge //------------------------------------------------------- module shift_reg_8 ( input clk, input rst_n, // active-low async reset input serial_in, output reg [7:0] q ); always @(posedge clk or negedge rst_n) begin if (!rst_n) q <= 8'h00; else q <= {q[6:0], serial_in}; // shift left, new bit enters LSB end endmodule |
//------------------------------------------------------- // 16-bit serial-in, parallel-out shift register //------------------------------------------------------- module shift_reg_16 ( input clk, input rst_n, input serial_in, output reg [15:0] q ); always @(posedge clk or negedge rst_n) begin if (!rst_n) q <= 16'h0000; else q <= {q[14:0], serial_in}; end endmodule |
//------------------------------------------------------- // 8-bit shift register with parallel load // Useful when you need to load a byte then shift it out //------------------------------------------------------- module shift_reg_8_load ( input clk, input rst_n, input load, // 1 = load parallel data input [7:0] parallel_in, input serial_in, output reg [7:0] q ); always @(posedge clk or negedge rst_n) begin if (!rst_n) q <= 8'h00; else if (load) q <= parallel_in; else q <= {q[6:0], serial_in}; end endmodule |
//------------------------------------------------------- // 8-bit up-counter with enable and async reset //------------------------------------------------------- module counter_8 ( input clk, input rst_n, input en, // count enable output reg [7:0] count ); always @(posedge clk or negedge rst_n) begin if (!rst_n) count <= 8'h00; else if (en) count <= count + 1'b1; end endmodule |
Quick tips
• Prefer non-blocking assignments (<=) inside clocked always blocks.
• Prefer blocking assignments (=) inside combinational always @(*) blocks.
• Always reset your registers (async or sync – both are common).
• Use reg for anything driven inside an always block; use wire for continuous assign.