Electronics Software Development

Creating A Configurable Multifunction Logic Gate In Verilog

Configurable Multifunction Logic Gate Graphic
Written by John Woolsey

Skill Level: Intermediate

Table Of Contents


One evening, I saw a mention of the NL7SZ58 configurable multifunction gate chip. I thought it would be nice to have some extra chips around that can act as any logic gate you need, so I began researching it. While this chip wasn’t quite what I expected, it inspired me to create my own configurable multifunction logic gate design in Verilog. The difference between the NL7SZ58 and my design is that the different logic gates of the NL7SZ58 are achieved by connecting the inputs in different arrangements, whereas my design uses the same inputs for all gates, but applies the logic function via a selector.

This tutorial will guide you through creating and testing a simple configurable multifunction logic gate in Verilog. A basic understanding of digital logic design and the Verilog hardware description language is expected, however, this will be a simple design so we will not be delving into complex topics or constructs.

The resources created for this tutorial are available on GitHub for your reference.

What Is Needed

  • Linux, macOS, Or Windows Based Computer
  • APIO Toolbox
  • GTKWave Wave Viewer

Required Software

Let’s begin with making sure we have the required software installed that we will use to design and test our configurable multifunction logic gate design.

APIO is an open source multi-platform toolbox for verifying, synthesizing, simulating, and uploading Verilog based designs to a field programmable gate array (FPGA) based development board. Although we will not be using an FPGA in this tutorial, the APIO tool provides a nice interface for creating and simulating our design.

GTKWave is a fully featured GTK+ based wave viewer that reads LXT, LXT2, VZT, FST, GHW files, and standard Verilog VCD/EVCD files. It is used by APIO to display the simulated design waveforms.

Install the APIO and GTKWave utilities if you have not done so already. Installation instructions for APIO can be found in the Installation and Quick Start pages of the APIO Documentation. You can download GTKWave from the SourceForge website or follow the instructions in the Simulate section of the Quick Start page of the APIO documentation. You may also need to include the location of the gtkwave executable in your shell’s $PATH variable as we will be running it through apio on the command line. This will become apparent if you see the following error during simulation later in this tutorial.

sh: gtkwave: command not found

Designing The Configurable Multifunction Logic Gate

Now, let’s design our new configurable multifunction logic gate (cmflg).

The general goal of the design is to create a two-input single-output multifunction logic gate whose gate logic is selectable across all of the basic digital logic gates.

The design criteria I set are as follows. The device must have

  • the ability to function as any one of the basic digital logic gates: AND, NAND, OR, NOR, XOR, XNOR, buffer, or inverter,
  • two digital inputs that supply the inputs to the logic gate,
  • a single digital output that represents the result of the logic function applied to the two digital inputs, and
  • a selector input that determines the logic function applied to the digital output.

Since we have 8 possible logic functions (gates) that can be applied, this means we need a 3-bit selector input vector (23 = 8).

To summarize, the port interface of the cmflg module will have two single-ended inputs, one 3-bit vector input, and one single-ended output. The module’s implementation will apply one of the eight logic functions, based on the value presented at the vector input, to the two single-ended inputs and present the result on the single-ended output. The logic diagram shown below illustrates the intention of the design.

Logic Diagram Of The Configurable Multifunction Logic Gate
Logic Diagram Of The Configurable Multifunction Logic Gate

The diagram shows the outputs of all eight of the basic logic gates being fed to an 8-to-1 multiplexer.

Implementing The Design

Now that we understand what we want, let’s implement the configurable multifunction logic gate design. Create a new project directory, named cmflg, on your computer. This is where we will store our project files.

Open your favorite code editor and create and save a file named cmflg.v within the project directory with the contents shown below. This Verilog file will contain our design implementation.

`define DEBUG  // comment out for normal operation
`timescale 1ns/10ps

// Logic gate selection codes
`define BUF  3'b000  // buffer gate
`define INV  3'b001  // inverter gate
`define AND  3'b010  // AND gate
`define NAND 3'b011  // NAND gate
`define OR   3'b100  // OR gate
`define NOR  3'b101  // NOR gate
`define XOR  3'b110  // XOR gate
`define XNOR 3'b111  // XNOR gate

module cmflg (
   input a, b,     // logic inputs
   input [2:0] s,  // logic gate select inputs
   output reg y    // logic output

   // Multifunction gate implementation
   always @(*) begin
      case (s)
            `BUF: y = a;       // buffer
            `INV: y = ~a;      // inverter
            `AND: y = a & b;   // AND
           `NAND: y = a ~& b;  // NAND
             `OR: y = a | b;   // OR
            `NOR: y = a ~| b;  // NOR
            `XOR: y = a ^ b;   // XOR
           `XNOR: y = a ~^ b;  // XNOR
         default: y = 1'bx;    // undefined

   // Debug status
   `ifdef DEBUG
   always @(*) begin  // logic input values changed
      $display("%d %m: DEBUG - Input values changed to a = %b and b = %b.", $stime, a, b);
   always @(*) begin  // gate select values changed
      $display("%d %m: DEBUG - Select changed to s = %b.", $stime, s);
   always @(*) begin  // logic output value changed
      $display("%d %m: DEBUG - Output value changed to y = %b.", $stime, y);

endmodule  // cmflg

Lines 5-12 define the 3-bit codes and their associated user friendly mnemonics for all of the possible logic gate selections.

Lines 15-17 define the port interface of the cmflg module. a and b represent the two digital inputs of the gate, s represents the 3-bit logic selector input, and y represents the single digital output.

Lines 21-33 define the implementation of the configurable multifunction logic gate. Each possible logic gate selection, along with its associated bitwise logic function, is covered through the use of a case statement. The default case propagates an unknown, or undefined, value to the output in the case that the selector input itself is also undefined. The implementation is very similar to an arithmetic logic unit (ALU) design, but works on single-ended digital inputs instead of on multi-bit registers.

Lines 36-46 provide the means to display debugging information, such as when inputs or outputs change, when the DEBUG definition, on line 1, is not commented out.

Now that our Verilog design implementation is complete, let’s check it for errors.

Although we are not uploading our design to an FPGA board in this tutorial, the APIO tool still requires a board to be defined in order to use the tool. Open a terminal window and run the following command within the project directory to initialize the project with a specific board.

$ apio init --board TinyFPGA-BX

I chose the TinyFPGA-BX board as it is a board I actually own, but I believe any board can be selected for our purposes.

Now that our board is defined, let’s verify our design to make sure we did not introduce any errors. Run the following command on the command line.

$ apio verify

The following warning can be ignored as PCF files are only required when uploading to FPGAs.

---> WARNING: no PCF file found (.pcf)

Fix any typos or errors that are reported.

Creating The Testbench

Now that our configurable multifunction logic gate design is implemented, let’s test the design by creating a testbench. We want to verify that the output of each selected logic gate is as expected for all possible inputs to the module.

Within the project directory, create and save a new file, named cmflg_tb.v, with the contents shown below. This Verilog file will contain our testbench.

`timescale 1ns/10ps

module cmflg_tb;
   reg a, b;     // logic input values for cmflg module
   reg [2:0] s;  // logic gate select input values for cmflg module
   wire y;       // logic output value for cmflg module

   integer i, j;  // for loop variables
   reg [3:0] states = {1'b1, 1'b0, 1'bz, 1'bx};  // all possible logic states

   initial begin
      $dumpfile("cmflg_tb.vcd");  // waveforms file
      $dumpvars;  // save waveforms
      $display("%d %m: Starting testbench simulation...", $stime);
      $monitor("%d %m: MONITOR - a = %b, b = %b, s = %b, y = %b.", $stime, a, b, s, y);

      // Tests all gate implementations with all possible input logic states
      for (i = 0; i < $bits(states); i = i + 1) begin
         for (j = 0; j < $bits(states); j = j + 1) begin
            #1; a = states[i]; b = states[j]; s = 'bx;
            #1; test_logic("UNDEF", 'bx);  // test undefined selector inputs
            #1; s = 'bz;
            #1; test_logic("Hi-Z", 'bx);  // test high-Z selector inputs
            #1; s = `BUF;
            #1; test_logic("BUF", a);  // test buffer gate logic
            #1; s = `INV;
            #1; test_logic("INV", !a);  // test inverter gate logic
            #1; s = `AND;
            #1; test_logic("AND", a && b);  // test AND gate logic
            #1; s = `NAND;
            #1; test_logic("NAND", !(a && b));  // test NAND gate logic
            #1; s = `OR;
            #1; test_logic("OR", a || b);  // test OR gate logic
            #1; s = `NOR;
            #1; test_logic("NOR", !(a || b));  // test NOR gate logic
            #1; s = `XOR;
            #1; test_logic("XOR", a != b);  // test XOR gate logic
            #1; s = `XNOR;
            #1; test_logic("XNOR", !(a != b));  // test XNOR gate logic

      // All tests passed
      #1 $display("\n%d %m: Testbench simulation PASSED.", $stime);
      $finish;  // end simulation

   // Test the result of the logic gate
   task test_logic (
      input [5*8:1] logic_description,  // logic description string
      input logic_function              // expected logic function result

      if (y !== logic_function) begin
         $display("%d %m: ERROR - %s - Expected a result of '%b', but received '%b' instead.", $stime, logic_description, logic_function, y);
         $finish;  // end simulation

   // Instances
   cmflg cmflg_1(.a(a), .b(b), .s(s), .y(y));

endmodule  // cmflg_tb

Lines 4-6 establish our port interface connection to the cmflg module that is instantiated on line 61. The register variables a, b, and s will be set with various input values (the stimuli) and the wire variable y will be tested for the appropriate logic result.

Lines 8 and 9 define the other variables being used within our testbench. Integers i and j will be used as for-loop variables. The states vector contains all possible logic states (values) that the input variables can hold: x (undefined), z (high impedance), 0 (logic level low), and 1 (logic level high).

Lines 12 and 13 set up the name of the file where are simulated waveforms will be stored.

Line 15 monitors the a, b, s, and y variables and prints a message if any of them change.

Lines 18-41 are the heart of the testbench. The two for-loops run through all possible combinations of the logic gate input values (states) available. Line 20 delays execution for one time unit (#1) and then sets the a and b input values according to the current for-loop states along with the initial value for the gate selector input (s), undefined in this case. One delay later, line 21 calls the test_logic() task, defined beginning on line 49, to test the result of the stimuli applied on the previous line. Calls to the test_logic() task pass a text string containing a description of the test as the first argument and the expected result of the test as the second argument. Note, I am using logical operators for the expected result to test the bitwise operators used within the cmflg device itself in order to achieve a strictly true or false result. The rest of the lines in the for-loops set the next value of the gate selector input and then test the logic results for that gate logic respectively.

The timescale directive, shown on line 1, sets the time units and precision of the delays (#) used in the testbench code. In this case, 1 ns delays with a precision of 10 ps.

The test_logic() task, defined on lines 49-58, begins with defining the arguments that will be passed to the task. The logic_description parameter will contain a description of the test and the logic_function parameter will contain the expected result of the test. Strictly speaking, Verilog does not have a distinct string datatype, but it can hold ASCII characters within a register datatype. Since each ASCII character requires 8 bits of storage, the register vector needs to be a multiple of 8 bits to account for the maximum number of characters it is meant to hold. In this case, the logic_description parameter can hold up to 5 characters. Lines 54-57 perform the actual test, comparing the expected result (logic_function) to the actual result (y). If they do not match, an error message is printed and the simulation is halted. The !== identity operator, as opposed to the != equality operator, is used in order to properly compare against x and z values (states).

Once all of the tests have run, the testbench will print a message letting you know that all of the tests passed and then halt the simulation, as shown on lines 44 and 45.

Let’s verify our testbench to make sure we did not introduce any errors.

$ apio verify

Fix any typos or errors that are reported.

Simulating And Testing The Design

Now it’s time to simulate and test the design of the configurable multifunction logic gate.

$ apio sim

Upon running the simulation command above, you should see quite a few MONITOR and DEBUG messages in the terminal window detailing all of the input and output changes occurring along with the following message

321 cmflg_tb: Testbench simulation PASSED.

towards the end letting us know that the design passed the testbench simulation. The GTKWave waveform viewer should also have appeared.

If you do not want to see all of the simulation debugging messages, you can comment out one or both of the following lines within the Verilog code.

cmflg.v (line 1):

// `define DEBUG  // comment out for normal operation

cmflg_tb.v (line 15):

// $monitor("%d %m: MONITOR - a = %b, b = %b, s = %b, y = %b.", $stime, a, b, s, y);

Next, let’s take a look at the waveforms generated by the simulation in the GTKWave viewer. Increase the size of the GTKWave window to give you more room to groove.

To view the waveforms, select cmflg_tb at the bottom of the list within the top left panel of the viewer. A list of signals should appear in the bottom left panel. Select the a, b, s[2:0], and y signals and click the Insert button under that panel. The waveforms for those signals should appear in the right side panel. Only a small amount of time is currently shown for the waveforms so they probably don’t look very interesting. To view the signals for the entire simulation time, select Time > Zoom > Zoom Best Fit from the main menu. Now that’s more like it.

Let’s zoom into an area (Time > Zoom > Zoom In) a few times to see more of what is going on, say around 220 ns. Once you are there, click in the viewer around that timeframe and a vertical marker line will appear. You will also see the actual values shown for the various signals at that point in time within the Signals panel on the left. You can click again in a different spot of the viewer to move the marker and view the values at that time instead. The waveform viewer should now look like that shown below.

GTKWave Window Displaying The Configurable Multifunction Logic Gate's Simulation Signals
GTKWave Window Displaying The Configurable Multifunction Logic Gate’s Simulation Signals

At 222 ns, the digital inputs are shown as a = 0 and b = 1, and the selector is displayed as s = xxx. Since the selector is undefined, the output y is also undefined, y = x. Looking at time 224 ns, the selector has changed to zzz and y continues to be x. Looking good so far. Continuing on, at time 226 ns, the first real gate selection was set to 000 (buffer) and the y output changed to 0. That is expected for a buffer. At 228, s = 001 (inverter) and y changed from 0 to 1. At 230, s = 010 (AND) and y changed back to 0, which is expected for an AND gate. You get the idea.

Once you have looked around at the signals in the viewer, exit the GTKWave application.

You may have noticed that some extra files showed up in our project directory, e.g. hardware.out, cmflg_tb.vcd, etc. These were generated by the APIO operations we ran on the command line. If you run the simulation command again, APIO will just open GTKWave with the current waveform data without actually running the simulation again unless you change one of the Verilog files. This can come in handy if you have a complicated design that takes a long time to simulate. However, if you would like to remove them, you can clean them up with the following command.

$ apio clean

Additional Resources

The following is a list of resources I found helpful for this tutorial.


In this tutorial, we learned how to

  • design a configurable multifunction logic gate,
  • implement the design in Verilog,
  • create a testbench in Verilog to test the design, and
  • run a testbench simulation to test the design.

Now we just need to enhance this basic design into a full scale package, get it manufactured at a semiconductor fabrication plant, and viola, we now have our own configurable multifunction logic gate chips for us to use. If it were only that simple.

The final Verilog source code files used for this tutorial are available on GitHub.

Thank you for joining me on this journey and I hope you enjoyed the experience. Please feel free to share your thoughts or questions in the comments section below.

This tutorial is provided as a free service to our valued readers. Please help us continue this endeavor by considering a donation.

About the author

John Woolsey

John is an electrical engineer who loves science, math, and technology and teaching it to others even more.
He knew he wanted to work with electronics from an early age, building his first robot when he was in 8th grade. His first computer was a Timex/Sinclair 2068 followed by the Tandy 1000 TL (aka really old stuff).
He put himself through college (The University of Texas at Austin) by working at Motorola where he worked for many years afterward in the Semiconductor Products Sector in Research and Development.
John started developing mobile app software in 2010 for himself and for other companies. He has also taught programming to kids for summer school and enjoyed years of judging kids science projects at the Austin Energy Regional Science Festival.
Electronics, software, and teaching all culminate in his new venture to learn, make, and teach others via the Woolsey Workshop website.


  • Hello John,

    Skimmed through your article on configurable logic gates just now as I’ve had something related to this on my mind for a while: I need a configurable device that’s capable of replicating the function of a monostable multivibrator (one-shot). Is it possible to create that in Verilog & realize it in a small low-power package?

    • I am not sure of your definition of “small”, but since you are looking at implementing the device in Verilog, I believe you are limited to a low pin count FPGA, if you can find one. Otherwise, you would have to get someone to fabricate and package the design for you which can be very time consuming and costly. Sorry that I didn’t have a better answer.

      By the way, I found a monostable multivibrator implementation in Verilog if that is of interest to you.

  • Thanks so much for the prompt reply! I’ll take a closer look at that implementation, but first reaction is that it’s not going to do what I need. I don’t actually have a “Clock” as I’m using a 74AHC123. Perhaps a more accurate description of what I need is a logic function that produces a single pulse following a logic level change on one of the inputs?

    Best Rgds,

    • I’m sure we could figure out a design using discrete logic chips and components, but I don’t think that fits your desire for a single small low power package, especially if you want to implement it in Verilog. Perhaps you can post your design requirements on the Electronics Stack Exchange forum. That would allow you to get help and ideas from many experienced designers. Engineers love solving problems.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.