vhdl_workshop:lab_6

LAB 6: A Register

When an exposure time is selected by the user it has to be stored. Edge-triggered Flip-Flops are used for this purpose. The contents of the register are updated only with the rising edge of the clock signal. This way, differences in the path delay become irrelevant as long as the maximum delay is shorter than the clock period.

In addition to the clock signal a second enabling condition is needed in this case. Valid exposure times shall be stored until another exposure time is selected. Only legal button combinations are mapped to display values other than (0,0,0) by the decoder, i.e. it is sufficient to exclude this value triple from being stored.

The reset input signal is necessary to be able to bring the chip into a defined state, e.g. after power-up.

The complete interface of the register is shown in the following figure:

The exposure time latch

The reset shall be implemented asynchronously, i.e. a process with sensitivity list is the only viable option in this case. The following template for clocked processes has to be used:

if RESET
...
elsif RISING_CLOCK_EDGE
...

After a rising clock edge has been detected it must be checked whether a key was pressed. If yes, the new exposure time is stored in the register.

The exposure latch is used to store the exposure time, i.e. T_DIGITS is the appropriate type for the data signals. CLK and RESET are single bit control signals and shall therefore be of type std_ulogic.

  • Write a new file with the VHDL description of the exposure latch.
  • Write a testbench to verify the design. The periodic clock signal generation should be placed in a separate stimuli process!
  • Compile and simulate the design.
  • Synthesize the module.
EXP_FF.VHD
library ieee;
use ieee.std_logic_1164.all;
 
entity EXP_FF is
  port(CLK      : in std_ulogic;
       RESET    : in std_ulogic;
       KEY      : in T_DIGITS;
       EXP_TIME : out T_DIGITS);
end EXP_FF;
 
architecture RTL of EXP_FF is
begin
  process(CLK)
  begin
    if (RESET = '1') then
      -- Assign a default value
    elsif (CLK'event and CLK = '1') then
      -- Check for new input values
    end if;
  end process;
end RTL;
TB_EXP_FF.VHD
library ieee;
USE std.textio.ALL;
use ieee.std_logic_1164.all;
use work.P_DISPLAY.all;
 
entity TB_EXP_FF is
end TB_EXP_FF;
 
architecture TEST of TB_EXP_FF is
  component EXP_FF
    port(CLK      : in std_ulogic;
         RESET    : in std_ulogic;
         KEY      : in T_DIGITS;
         EXP_TIME : out T_DIGITS);
  end component;
 
  signal W_CLK      : std_ulogic := '0';
  signal W_RESET    : std_ulogic;
  signal W_KEY      : T_DIGITS;
  signal W_EXP_TIME : T_DIGITS;
 
begin
  DUT : EXP_FF
    port map(
      CLK      => W_CLK,
      RESET    => W_RESET,
      KEY      => W_KEY,
      EXP_TIME => W_EXP_TIME);
 
  W_CLK <= not W_CLK after 10 ns;
 
  STIMULI : process
  begin
    W_KEY <= (0,0,0);
    W_RESET <= '1';
    -- EXP_TIME = (0,0,1)
    wait for 5 ns;
 
    W_RESET <= '0';
    -- no changes (all 0 shall be ignored)
    wait for 15 ns;
 
    W_KEY <= (1,2,3);
    -- no changes (no active clock edge)
    wait for 5 ns;
 
    W_KEY <= (2,2,3);
    -- EXP_TIME = (2,2,3)
    wait for 15 ns;
 
    W_KEY <= (0,3,5);
    -- EXP_TIME = (0,3,5)
    wait for 5 ns;
 
    assert false report "End of stimuli reached"
                 severity failure;
  end process STIMULI;
 
  SAMPLE : process(W_EXP_TIME)
    constant SPACE     : string := " ";
    variable FILE_LINE : line;
    FILE     OUT_FILE  : text IS OUT "lab_6.trace";
  begin
    write(FILE_LINE, W_EXP_TIME(2));
    write(FILE_LINE, SPACE);
    write(FILE_LINE, W_EXP_TIME(1));
    write(FILE_LINE, SPACE);
    write(FILE_LINE, W_EXP_TIME(0));
 
    writeline(OUT_FILE, FILE_LINE);
  end process SAMPLE;
end TEST;
 
configuration CFG_TB_EXP_FF of TB_EXP_FF is
  for TEST
  end for;
end CFG_TB_EXP_FF;

LAB 4, 5, 6, 7, 8, 9, 10, 11

P_DISPLAY.VHD
library ieee;
use ieee.std_logic_1164.all;
 
package P_DISPLAY is
  type T_DIGITS  is array (2 downto 0) of integer range 0 to 10;
  type T_DISPLAY is array (2 downto 0) of std_ulogic_vector(6 downto 0);
 
  constant SEG_0 : std_ulogic_vector(6 downto 0):= "0111111";
  constant SEG_1 : std_ulogic_vector(6 downto 0):= "0000011";
  constant SEG_2 : std_ulogic_vector(6 downto 0):= "1101101";
  constant SEG_3 : std_ulogic_vector(6 downto 0):= "1100111";
  constant SEG_4 : std_ulogic_vector(6 downto 0):= "1010011";
  constant SEG_5 : std_ulogic_vector(6 downto 0):= "1110110";
  constant SEG_6 : std_ulogic_vector(6 downto 0):= "1111110";
  constant SEG_7 : std_ulogic_vector(6 downto 0):= "0100011";
  constant SEG_8 : std_ulogic_vector(6 downto 0):= "1111111";
  constant SEG_9 : std_ulogic_vector(6 downto 0):= "1110111";
  constant SEG_E : std_ulogic_vector(6 downto 0):= "1111100";
 
  -- pragma translate_off
  procedure DISPLAY_DIGIT(signal DISPLAY:T_DISPLAY);
  -- pragma translate_on
end P_DISPLAY;
 
-- pragma translate_off
use std.textio.all;
package body P_DISPLAY is
  ------------------------------
  --
  --            111111111112222
  --   123456789012345678901234
  --  1  #5##    ####    ####
  --  2 #    #  #    #  #    #
  --  3 4    0  #    #  #    #
  --  4 #    #  #    #  #    #
  --  5  #6##    ####    ####
  --  6 #    #  #    #  #    #
  --  7 3    1  #    #  #    #
  --  8 #    #  #    #  #    #
  --  9  #2##    ####    ####
  --
  ------------------------------
 
  constant ACTIVE_SEG: character := '#';
  constant EMPTY_SEG:  character := ' ';
 
  -- Width and height of a digit
  constant WIDTH:  integer := 8;
  constant HEIGHT: integer := 9;
 
  -- Datatypes to store the complete display in a matrix
  subtype T_MATRIX_ROW  is bit_vector (1 to 3*WIDTH);
  type    T_DISP_MATRIX is array (1 to HEIGHT) of T_MATRIX_ROW;
 
  -- Definition of the appearance of the 6 segments
  subtype T_DIGIT_ROW is bit_vector(1 to WIDTH);
  type    T_SEG_DEF   is array (1 to HEIGHT) of T_DIGIT_ROW;
  type    T_DIGIT_DEF is array (0 to 6) of T_SEG_DEF;
  constant DIGIT_DEF: T_DIGIT_DEF :=(("00000000", --   ....
                                      "00000010", --  .    #
                                      "00000010", --  .    0
                                      "00000010", --  .    #
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "00000010", --  .    #
                                      "00000010", --  .    1
                                      "00000010", --  .    #
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00111100"),--   #2##
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "01000000", --  #    .
                                      "01000000", --  3    .
                                      "01000000", --  #    .
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "01000000", --  #    .
                                      "01000000", --  4    .
                                      "01000000", --  #    .
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"),--   ....
 
                                     ("00111100", --   #5##
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00111100", --   #6##
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"));--  ....
 
  procedure DISPLAY_DIGIT(signal DISPLAY:T_DISPLAY) is
    file OUTFILE : TEXT is out "display.txt";
 
    variable L : line;
    variable DISP_TEXT: string(T_MATRIX_ROW'range);
 
    variable DISP_MATRIX: T_DISP_MATRIX;
    variable COL_L: integer;
    variable COL_R: integer;
 
  begin
    -- Clear the display
    DISP_MATRIX := (others => (others => '0'));
 
    -- Loop over all digits
    for DIGIT in T_DISPLAY'range loop
      -- Calculate the left- and rightmost columns
      COL_L := DIGIT*WIDTH + 1;
      COL_R := DIGIT*WIDTH + WIDTH;
 
      -- Loop over all segments
      for SEGMENT in 0 to 6 loop
        if DISPLAY(DIGIT)(SEGMENT) = '1' then
          -- Copy the matrix to the final display
          -- Loop over all rows of the display
          for ROW in T_SEG_DEF'range loop
            DISP_MATRIX(ROW)(COL_L to COL_R) :=
              DISP_MATRIX(ROW)(COL_L to COL_R) or
              DIGIT_DEF(SEGMENT)(ROW);
          end loop;
        end if;
      end loop;
    end loop;
 
    -- Write the matrix to a textfile
    for I in T_DISP_MATRIX'range loop
      -- Start with an empty line
      DISP_TEXT := (others => EMPTY_SEG);
 
      for J in T_MATRIX_ROW'range loop
        if DISP_MATRIX(I)(J) = '1' then
          DISP_TEXT(J) := ACTIVE_SEG;
        end if;
      end loop;
 
      -- Write the line
      write(L, DISP_TEXT);
      writeline(OUTFILE, L);
    end loop;
 
  end DISPLAY_DIGIT;
end P_DISPLAY;
-- pragma translate_on