SystemVerilog
=============
Up to this point, we specified our hardware modules through elementary logic gates.
Given an abstract description of a function, we had to manually lower it to logic gates.
This process is cumbersome, error-prone and time-consuming, especially when aiming for an optimized circuit where different realizations have to be considered.

A Hardware Description Language (HDL) allows us to "simply" specify the logical function of a module.
Computer-Aided Design (CAD) tools which understand such an HDL then perform the mapping of our abstract module description to logic gates.
This process process is called *synthesis*.
Further, we are able to test our HDL-based hardware designs through *simulation*.
Here, we apply inputs to our hardware modules and check the correctness of the outputs.

In this class we harness `SystemVerilog <https://ieeexplore.ieee.org/document/8299595>`_ as our HDL.
The following tools will allow us to test our designs:

* Simulation: `Icarus Verilog <http://iverilog.icarus.com/>`_
* Waveform visualization: `GTKWave <http://gtkwave.sourceforge.net/>`_

.. note::

  We rely on open source or at least free software if possible.
  This means that you may install and run the tools on your own machines if desired.
  However, for the regular sessions, use the provided installations.
  If you'd like to explore further and use a custom installation, we can talk in the Open Lab / Q&A.

Simple Example Module
---------------------
Our first module implements the following function:

.. math::
  :label: simple_example_function

  C = F(A,B) = \bar{A} + B,

where :math:`A` and :math:`B` are one-bit inputs and :math:`C` the one-bit output.
:numref:`tab:simple_example_function` is the truth table of this simple example function.

.. _tab:simple_example_function:

.. table:: Truth table of the simple example function in Eq. :eq:`simple_example_function`.
   :widths: 20 20 20 20 20

   +-----------+------------+-----------+
   | :math:`A` | :math:`B`  | :math:`C` |
   +===========+============+===========+
   |         0 |          0 |         1 |
   +-----------+------------+-----------+
   |         1 |          0 |         0 |
   +-----------+------------+-----------+
   |         0 |          1 |         1 |
   +-----------+------------+-----------+
   |         1 |          1 |         1 |
   +-----------+------------+-----------+

.. admonition:: Tasks

  #. Implement Eq. :eq:`simple_example_function` in the  module ``simple_example_module`` using the filename ``simple_example_module.sv``.

  #. Test your implementation in the testbench ``simple_example_module_tb``.
     Use the filename ``simple_example_module_tb.sv``.
     Verify that your module produces the correct outputs for all inputs (see :numref:`tab:simple_example_function`).

  #. Visualize the waveforms generated by your module.

.. hint::
  Use the arguments ``-Wall -Winfloop -g2012`` when invoking ``iverilog``.
  Details on using GTKWave with Icarus Verilog are available from the Icarus Verilog `Wiki <https://iverilog.fandom.com/wiki/GTKWave>`_.
  You may increase the GTKWave's font size, e.g., by using the arguments ``-A --rcvar 'fontname_signals Monospace 12' --rcvar 'fontname_waves Monospace 12'`` when invoking the GTKWave-binary.

.. _ch:one_bit_full_adder:

One-bit Full Adder
------------------
This chapter designs a one-bit full adder in SystemVerilog.
The full adder consists of the three one-bit inputs :math:`A`, :math:`B` and :math:`C_\text{in}` and has the two one-bit outputs :math:`S` and :math:`C_\text{out}`:

.. math::
  :label: full_adder

    &S = F(A,B,C_\text{in}) = A \oplus B \oplus C_\text{in}, \\
    &C_\text{out} = G(A,B,C_\text{in}) = AB + AC_\text{in} + BC_\text{in}.
  
.. _tab:full_adder_1bit:

.. table:: Truth table of the full adder.
   :widths: 20 20 20 20 20

   +-----------+------------+---------------------+-----------+----------------------+
   | :math:`A` | :math:`B`  | :math:`C_\text{in}` | :math:`S` | :math:`C_\text{out}` |
   +===========+============+=====================+===========+======================+
   |         0 |          0 |                   0 |         0 |                    0 |
   +-----------+------------+---------------------+-----------+----------------------+
   |         1 |          0 |                   0 |         1 |                    0 |
   +-----------+------------+---------------------+-----------+----------------------+
   |         0 |          1 |                   0 |         1 |                    0 |
   +-----------+------------+---------------------+-----------+----------------------+
   |         0 |          0 |                   1 |         1 |                    0 |
   +-----------+------------+---------------------+-----------+----------------------+
   |         1 |          1 |                   0 |         0 |                    1 |
   +-----------+------------+---------------------+-----------+----------------------+
   |         1 |          0 |                   1 |         0 |                    1 |
   +-----------+------------+---------------------+-----------+----------------------+
   |         0 |          1 |                   1 |         0 |                    1 |
   +-----------+------------+---------------------+-----------+----------------------+
   |         1 |          1 |                   1 |         1 |                    1 |
   +-----------+------------+---------------------+-----------+----------------------+

:numref:`tab:full_adder_1bit` is the truth table of the full adder.
In your tests and waveform visualization cover all possible inputs and output.
Additionally, follow the order of the table, e.g., test/visualize the first row before the second one.

.. literalinclude:: data_system_verilog/full_adder_1.sv
    :linenos:
    :language: systemverilog
    :caption: Template for the module ``full_adder_1``.
    :name: listing:full_adder_1

.. literalinclude:: data_system_verilog/full_adder_1_tb.sv
    :linenos:
    :language: systemverilog
    :caption: Template for the testbench ``full_adder_1_tb``.
    :name: listing:full_adder_1_tb

Use the template in :numref:`listing:full_adder_1` for your implementation of the full adder in the module ``full_adder_1`` using the filename ``full_adder_1.sv``.
Use the template in :numref:`listing:full_adder_1_tb` for your implementation of the testbench ``full_adder_1_tb`` in the file ``full_adder_1_tb.sv``.

.. admonition:: Tasks

  #. Implement the module ``full_adder_1``.

  #. Test your implementation in the testbench ``full_adder_1_tb``.
     Your testbench should check the outputs for all possible inputs (see :numref:`tab:full_adder_1bit`) through ``assert()``-statements.

  #. Visualize the waveform generated by your module.
     Only show ``i_a``, ``i_b``, ``i_carry_in``, ``o_s`` and ``o_carry_out`` of the ``full_adder_1``-module in that order.

.. _ch:four_bit_ripple_carry_adder:

Four-bit Ripple-Carry Adder
---------------------------
This task covers basic modularity in SystemVerilog.
In detail, we use simple(r) SystemVerilog modules as building blocks for more complex ones.
Nothing else is done in processor design.
This means, that one would combine a "simple" module, e.g., an Arithmetic and Logic Unit (ALU), with other modules such that the combined logics executes desired instructions.
We'll cover details on ALUs and processors later in the lab.
For now, we'll stick to our adders.

Specifically, instead of adding three one-bit inputs as done in :numref:`ch:one_bit_full_adder`, we'll add two four-bit inputs :math:`A_{[3:0]}` and :math:`B_{[3:0]}`, and the carry in :math:`C_\text{in}`.
We'll use the so-called ripple-carry adder to perform this task.
A ripple-carry adder chains a series of 1-bit full adders together and is one possible implementation of a carry propagate adder.

We obtain a respective formula for the ripple-carry adder by repeatedly applying the two functions :math:`F` and :math:`G` of Eq. :eq:`full_adder` to our input:

.. math::
  :label: four_bit_ripple_carry

   S_0          = F(A_0,B_0,C_\text{in}), \\
   C_0          = G(A_0,B_0,C_\text{in}), \\
   S_1          = F(A_1,B_1,C_0),         \\
   C_1          = G(A_1,B_1,C_0),         \\
   S_2          = F(A_2,B_2,C_1),         \\
   C_2          = G(A_2,B_2,C_1),         \\
   S_3          = F(A_3,B_3,C_2),         \\
   C_\text{out} = G(A_3,B_3,C_2).         \\

Combined the equations :eq:`four_bit_ripple_carry` compute the four-bit output :math:`S_{[3:0]}` and the one-bit carry out :math:`C_\text{out}` from the inputs.
:math:`C_{[2:0]}` are intermediate carries through which we harness to connect our one-bit full adders: The carry *ripples* through the obtained multi-bit adder.

.. _tab:ripple_carry_adder_4:

.. table:: Truth table of the four-bit ripple carry adder.

  +-------------------+-------------------+---------------------+-------------------+----------------------+
  | :math:`A_{[3:0]}` | :math:`B_{[3:0]}` | :math:`C_\text{in}` | :math:`S_{[3:0]}` | :math:`C_\text{out}` |
  +===================+===================+=====================+===================+======================+
  |              0000 |              0000 |                   0 |              0000 |                    0 |
  +-------------------+-------------------+---------------------+-------------------+----------------------+
  |              1010 |              0001 |                   0 |              1011 |                    0 |
  +-------------------+-------------------+---------------------+-------------------+----------------------+
  |              1100 |              0000 |                   1 |                   |                      |
  +-------------------+-------------------+---------------------+-------------------+----------------------+
  |              0101 |              1010 |                   1 |                   |                      |
  +-------------------+-------------------+---------------------+-------------------+----------------------+
  |              0111 |              1100 |                   0 |                   |                      |
  +-------------------+-------------------+---------------------+-------------------+----------------------+
  |              1111 |              1111 |                   1 |                   |                      |
  +-------------------+-------------------+---------------------+-------------------+----------------------+

Once again we have to to think about reasonable unit tests for our testbench.
Now, we have to deal with an excessive amount of potential inputs due to the increased size of the inputs.
Thus, we limit ourselves for the mandatory tests to the small subset given in :numref:`tab:ripple_carry_adder_4`.

.. note::
   :numref:`tab:ripple_carry_adder_4` only gives the required tests for a successful completion of this task.
   Feel free to try additional inputs and implement further test if you see a need for this.

.. literalinclude:: data_system_verilog/ripple_carry_adder_4.sv
    :linenos:
    :language: systemverilog
    :caption: Template for the module ``ripple_carry_adder_4``.
    :name: listing:ripple_carry_adder_4

.. literalinclude:: data_system_verilog/ripple_carry_adder_4_tb.sv
    :linenos:
    :language: systemverilog
    :caption: Template for the testbench ``ripple_carry_adder_4_tb``.
    :name: listing:ripple_carry_adder_4_tb

.. admonition:: Tasks

  #. Draw the schematic of the four-bit ripple-carry adder as a sequence of one-bit full adders.

  #. Derive the total number of possible inputs for the four-bit ripple-carry adder!
     How would this change if we were to implement a 32-bit ripple-carry adder?

  #. Complete :numref:`tab:ripple_carry_adder_4`!

  #. Implement the module ``ripple_carry_adder_4`` by completing the module in :numref:`listing:ripple_carry_adder_4`.

  #. Test your implementation in the testbench ``ripple_carry_adder_4_tb`` by completing the module in :numref:`listing:ripple_carry_adder_4_tb`.
     Your testbench should check the outputs for all inputs in :numref:`tab:ripple_carry_adder_4` through ``assert()``-statements.

  #. Visualize the waveform generated by your module for  :numref:`tab:ripple_carry_adder_4`'s inputs.
     Only show the four-bit inputs ``i_a``, ``i_b``, the carry in ``i_carry_in``, the four-bit output ``o_s`` and the carry out ``o_carry_out`` of the ``ripple_carry_adder_4`` module in that order.