OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [util.vhd] - Diff between revs 3 and 5

Show entire file | Details | Blame | View Log

Rev 3 Rev 5
Line 1... Line 1...
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--| @file util.vhd
--| @file util.vhd
--| @brief A collection of utilities and simple components. The components
--| @brief A collection of utilities and simple components. The components
--| should be synthesizable, and the functions can be used within synthesizable
--| should be synthesizable, and the functions can be used within synthesizable
--| components, unless marked with a "_tb" suffix (or is the function n_bits).
--| components, unless marked with a "_tb" suffix (or if the function n_bits).
 
--|
 
--| Other modules to implement; CRC core (reuse LFSR), Count
 
--| Leading Zeros, Count Trailing Zeros, Manchester CODEC, Wishbone interface
 
--| types and Wishbone Bus Arbitrator. Also SPI, a H2 core with an eForth image
 
--| read to go, and UART.
 
--|
 
--| More exotic modules would include; encryption, compression, sorting networks,
 
--| switching networks, Reed-Solomon CODEC, Discrete Fourier Transform/Discrete
 
--| Cosine Transform, Pulse Width/Code/Position Modulation modules, so long as
 
--| they are fairly generic and synthesizable.
 
--|
 
--| Potential improvements to the library:
 
--| - Optional registers on either input or output, selectable by a generic
 
--| - Better timing models
 
--| - More assertions
 
--| - See 'A Structured VHDL design' by Jiri Gaisler,
 
--|   <http://gaisler.com/doc/vhdl2proc.pdf> and apply methodology.
 
--|
--| @author         Richard James Howe
--| @author         Richard James Howe
--| @copyright      Copyright 2017 Richard James Howe
--| @copyright      Copyright 2017, 2019 Richard James Howe
--| @license        MIT
--| @license        MIT
--| @email          howe.r.j.89@gmail.com
--| @email          howe.r.j.89@gmail.com
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.textio.all;
 
 
package util is
package util is
 
        -- Not all modules will need every generic specified here, even so it
 
        -- is easier to group the common generics in one structure.
 
        type common_generics is record
 
                clock_frequency:    positive; -- clock frequency of module clock
 
                delay:              time;     -- gate delay for simulation purposes
 
                asynchronous_reset: boolean;  -- use asynchronous reset if true
 
        end record;
 
 
 
        constant default_settings: common_generics := (
 
                clock_frequency    => 100_000_000,
 
                delay              => 10 ns,
 
                asynchronous_reset => true
 
        );
 
 
        component util_tb is
        component util_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component clock_source_tb is
        component clock_source_tb is
                generic(clock_frequency: positive; hold_rst: positive := 1);
                generic (g: common_generics; hold_rst: positive := 1);
                port(
                port(
                        stop:            in     std_ulogic := '0';
                        stop:            in     std_ulogic := '0';
                        clk:             buffer std_ulogic;
                        clk:             out    std_ulogic;
                        clk_with_jitter: out    std_ulogic := '0';
                        clk_with_jitter: out    std_ulogic := '0';
                        rst:             out    std_ulogic := '0');
                        rst:             out    std_ulogic := '0');
        end component;
        end component;
 
 
        component reg
        component reg
                generic(N: positive);
                generic (g: common_generics; N: positive);
                port(
                port(
                        clk: in  std_ulogic;
                        clk: in  std_ulogic;
                        rst: in  std_ulogic;
                        rst: in  std_ulogic;
                        we:  in  std_ulogic;
                        we:  in  std_ulogic;
                        di:  in  std_ulogic_vector(N - 1 downto 0);
                        di:  in  std_ulogic_vector(N - 1 downto 0);
                        do:  out std_ulogic_vector(N - 1 downto 0));
                        do:  out std_ulogic_vector(N - 1 downto 0));
        end component;
        end component;
 
 
        component shift_register
        component shift_register
                generic(N: positive);
                generic (g: common_generics; N: positive);
                port(
                port(
                        clk:     in  std_ulogic;
                        clk:     in  std_ulogic;
                        rst:     in  std_ulogic;
                        rst:     in  std_ulogic;
                        we:      in  std_ulogic;
                        we:      in  std_ulogic;
                        di:      in  std_ulogic;
                        di:      in  std_ulogic;
Line 51... Line 83...
                        load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
                        load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
                        load_o:  out std_ulogic_vector(N - 1 downto 0));
                        load_o:  out std_ulogic_vector(N - 1 downto 0));
        end component;
        end component;
 
 
        component shift_register_tb
        component shift_register_tb
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component timer_us
        component timer_us
                generic(clock_frequency: positive; timer_period_us: natural);
                generic (g: common_generics; timer_period_us: natural);
                port(
                port(
                        clk: in  std_ulogic;
                        clk: in  std_ulogic;
                        rst: in  std_ulogic;
                        rst: in  std_ulogic;
                        co:  out std_ulogic);
                        co:  out std_ulogic);
        end component;
        end component;
 
 
        component timer_us_tb
        component timer_us_tb
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component rising_edge_detector is
        component rising_edge_detector is
 
                generic (g: common_generics);
        port(
        port(
                clk:    in  std_ulogic;
                clk:    in  std_ulogic;
                rst:    in  std_ulogic;
                rst:    in  std_ulogic;
                di:     in  std_ulogic;
                di:     in  std_ulogic;
                do:     out std_ulogic);
                do:     out std_ulogic);
        end component;
        end component;
 
 
        component rising_edge_detector_tb is
        component rising_edge_detector_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component rising_edge_detectors is
        component rising_edge_detectors is
        generic(N: positive);
                generic (g: common_generics; N: positive);
        port(
        port(
                clk:    in  std_ulogic;
                clk:    in  std_ulogic;
                rst:    in  std_ulogic;
                rst:    in  std_ulogic;
                di:     in  std_ulogic_vector(N - 1 downto 0);
                di:     in  std_ulogic_vector(N - 1 downto 0);
                do:     out std_ulogic_vector(N - 1 downto 0));
                do:     out std_ulogic_vector(N - 1 downto 0));
        end component;
        end component;
 
 
 
        -- NB. 'half_adder' test bench is folded in to 'full_adder_tb'
        -- @note half_adder test bench is folded in to full_adder_tb
 
        component half_adder is
        component half_adder is
 
                generic (g: common_generics); -- simulation only
                port(
                port(
                        a:     in  std_ulogic;
                        a:     in  std_ulogic;
                        b:     in  std_ulogic;
                        b:     in  std_ulogic;
                        sum:   out std_ulogic;
                        sum:   out std_ulogic;
                        carry: out std_ulogic);
                        carry: out std_ulogic);
        end component;
        end component;
 
 
        component full_adder is
        component full_adder is
 
                generic (g: common_generics); -- simulation only
                port(
                port(
                        x:     in    std_ulogic;
                        x:     in    std_ulogic;
                        y:     in    std_ulogic;
                        y:     in    std_ulogic;
                        z:     in    std_ulogic;
                        z:     in    std_ulogic;
                        sum:   out   std_ulogic;
                        sum:   out   std_ulogic;
                        carry: out   std_ulogic);
                        carry: out   std_ulogic);
        end component;
        end component;
 
 
        component full_adder_tb is
        component full_adder_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component fifo is
        component fifo is
                generic (data_width: positive;
                generic (g: common_generics;
                        fifo_depth: positive);
                        data_width:  positive;
 
                        fifo_depth:  positive;
 
                        read_first:  boolean := true);
                port (
                port (
                        clk:   in  std_ulogic;
                        clk:   in  std_ulogic;
                        rst:   in  std_ulogic;
                        rst:   in  std_ulogic;
                        di:    in  std_ulogic_vector(data_width - 1 downto 0);
                        di:    in  std_ulogic_vector(data_width - 1 downto 0);
                        we:    in  std_ulogic;
                        we:    in  std_ulogic;
Line 127... Line 163...
                        full:  out std_ulogic := '0';
                        full:  out std_ulogic := '0';
                        empty: out std_ulogic := '1');
                        empty: out std_ulogic := '1');
        end component;
        end component;
 
 
        component fifo_tb is
        component fifo_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component counter is
        component counter is
                generic(
                generic (g: common_generics; N: positive);
                        N: positive);
 
                port(
                port(
                        clk:     in  std_ulogic;
                        clk:     in  std_ulogic;
                        rst:     in  std_ulogic;
                        rst:     in  std_ulogic;
                        ce:      in  std_ulogic;
                        ce:      in  std_ulogic;
                        cr:      in  std_ulogic;
                        cr:      in  std_ulogic;
Line 146... Line 181...
                        load_we: in  std_ulogic := '0';
                        load_we: in  std_ulogic := '0';
                        load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
                        load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
        end component;
        end component;
 
 
        component counter_tb is
        component counter_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component lfsr is
        component lfsr is
                generic(constant tap: std_ulogic_vector);
                generic (g: common_generics; constant tap: std_ulogic_vector);
                port
                port (
                (
 
                        clk: in  std_ulogic;
                        clk: in  std_ulogic;
                        rst: in  std_ulogic;
                        rst: in  std_ulogic;
                        ce:  in  std_ulogic := '1';
                        ce:  in  std_ulogic := '1';
                        we:  in  std_ulogic;
                        we:  in  std_ulogic;
                        di:  in  std_ulogic_vector(tap'high + 1 to tap'low);
                        di:  in  std_ulogic_vector(tap'high + 1 downto tap'low);
                        do:  out std_ulogic_vector(tap'high + 1 to tap'low));
                        do:  out std_ulogic_vector(tap'high + 1 downto tap'low));
        end component;
        end component;
 
 
        component lfsr_tb is
        component lfsr_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component io_pins is
        component io_pins is
                generic(
                generic (g: common_generics; N: positive);
                        N: positive);
                port (
                port
 
                (
 
                        clk:         in    std_ulogic;
                        clk:         in    std_ulogic;
                        rst:         in    std_ulogic;
                        rst:         in    std_ulogic;
                        control:     in    std_ulogic_vector(N - 1 downto 0);
                        control:     in    std_ulogic_vector(N - 1 downto 0);
                        control_we:  in    std_ulogic;
                        control_we:  in    std_ulogic;
                        din:         in    std_ulogic_vector(N - 1 downto 0);
                        din:         in    std_ulogic_vector(N - 1 downto 0);
                        din_we:      in    std_ulogic;
                        din_we:      in    std_ulogic;
                        dout:        out   std_ulogic_vector(N - 1 downto 0);
                        dout:        out   std_ulogic_vector(N - 1 downto 0);
                        pins:        inout std_logic_vector(N - 1 downto 0));
                        pins:        inout std_logic_vector(N - 1 downto 0)); -- NB!
        end component;
        end component;
 
 
        component io_pins_tb is
        component io_pins_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        type file_format is (FILE_HEX, FILE_BINARY, FILE_NONE);
        type file_format is (FILE_HEX, FILE_BINARY, FILE_NONE);
 
 
        component dual_port_block_ram is
        component dual_port_block_ram is
        generic(addr_length: positive    := 12;
        generic (g: common_generics;
 
                addr_length: positive    := 12;
                data_length: positive    := 16;
                data_length: positive    := 16;
                file_name:   string      := "memory.bin";
                file_name:   string      := "memory.bin";
                file_type:   file_format := FILE_BINARY);
                file_type:   file_format := FILE_BINARY);
        port(
        port(
                -- port A of dual port RAM
                -- port A of dual port RAM
Line 209... Line 242...
                b_din:  in  std_ulogic_vector(data_length - 1 downto 0);
                b_din:  in  std_ulogic_vector(data_length - 1 downto 0);
                b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
                b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
        end component;
        end component;
 
 
        component single_port_block_ram is
        component single_port_block_ram is
        generic(addr_length: positive    := 12;
        generic (g: common_generics;
 
                addr_length: positive    := 12;
                data_length: positive    := 16;
                data_length: positive    := 16;
                file_name:   string      := "memory.bin";
                file_name:   string      := "memory.bin";
                file_type:   file_format := FILE_BINARY);
                file_type:   file_format := FILE_BINARY);
        port(
        port(
                clk:  in  std_ulogic;
                clk:  in  std_ulogic;
Line 223... Line 257...
                din:  in  std_ulogic_vector(data_length - 1 downto 0);
                din:  in  std_ulogic_vector(data_length - 1 downto 0);
                dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
                dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
        end component;
        end component;
 
 
        component data_source is
        component data_source is
                generic(addr_length: positive    := 12;
                generic (g: common_generics;
 
                        addr_length: positive    := 12;
                        data_length: positive    := 16;
                        data_length: positive    := 16;
                        file_name:   string      := "memory.bin";
                        file_name:   string      := "memory.bin";
                        file_type:   file_format := FILE_BINARY);
                        file_type:   file_format := FILE_BINARY);
                port(
                port(
                        clk:     in  std_ulogic;
                        clk:     in  std_ulogic;
Line 241... Line 276...
 
 
                        dout:    out std_ulogic_vector(data_length - 1 downto 0));
                        dout:    out std_ulogic_vector(data_length - 1 downto 0));
        end component;
        end component;
 
 
        component ucpu is
        component ucpu is
                generic(width: positive range 8 to 32 := 8);
                generic (
 
                        asynchronous_reset:  boolean := true; -- use asynchronous reset if true, synchronous if false
 
                        delay:               time    := 0 ns; -- simulation only
 
 
 
                        width:               positive range 8 to 32 := 8);
                port(
                port(
                        clk, rst: in  std_ulogic;
                        clk, rst: in  std_ulogic;
 
 
                        pc:       out std_ulogic_vector(width - 3 downto 0);
                        pc:       out std_ulogic_vector(width - 3 downto 0);
                        op:       in  std_ulogic_vector(width - 1 downto 0);
                        op:       in  std_ulogic_vector(width - 1 downto 0);
Line 255... Line 294...
                        re, we:   out std_ulogic;
                        re, we:   out std_ulogic;
                        do:       out std_ulogic_vector(width - 1 downto 0));
                        do:       out std_ulogic_vector(width - 1 downto 0));
        end component;
        end component;
 
 
        component ucpu_tb is
        component ucpu_tb is
                generic(
                generic (g: common_generics; file_name: string := "ucpu.bin");
                        clock_frequency: positive;
 
                        file_name: string := "ucpu.bin");
 
        end component;
        end component;
 
 
        component restoring_divider is
        component restoring_divider is
                generic(N: positive);
                generic (g: common_generics; N: positive);
                port(
                port(
                        clk:   in  std_ulogic;
                        clk:   in  std_ulogic;
                        rst:   in  std_ulogic := '0';
                        rst:   in  std_ulogic := '0';
 
 
                        a:     in  std_ulogic_vector(N - 1 downto 0);
                        a:     in  std_ulogic_vector(N - 1 downto 0);
Line 274... Line 311...
                        done:  out std_ulogic;
                        done:  out std_ulogic;
                        c:     out std_ulogic_vector(N - 1 downto 0));
                        c:     out std_ulogic_vector(N - 1 downto 0));
        end component;
        end component;
 
 
        component restoring_divider_tb is
        component restoring_divider_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component debounce_us is
        component debounce_us is
                generic(clock_frequency: positive; timer_period_us: natural);
                generic (g: common_generics; timer_period_us: natural);
                port(
                port(
                        clk:   in  std_ulogic;
                        clk:   in  std_ulogic;
                        di:    in  std_ulogic;
                        di:    in  std_ulogic;
                        do:    out std_ulogic);
                        do:    out std_ulogic);
        end component;
        end component;
 
 
        component debounce_block_us is
        component debounce_block_us is
                generic(N: positive; clock_frequency: positive; timer_period_us: natural);
                generic (g: common_generics; N: positive; timer_period_us: natural);
                port(
                port(
                        clk:   in  std_ulogic;
                        clk:   in  std_ulogic;
                        di:    in  std_ulogic_vector(N - 1 downto 0);
                        di:    in  std_ulogic_vector(N - 1 downto 0);
                        do:    out std_ulogic_vector(N - 1 downto 0));
                        do:    out std_ulogic_vector(N - 1 downto 0));
        end component;
        end component;
 
 
        component debounce_us_tb is
        component debounce_us_tb is
                generic(clock_frequency: positive);
                generic (g: common_generics);
        end component;
        end component;
 
 
        component state_changed is
        component state_changed is
 
                generic (g: common_generics);
                port(
                port(
                        clk: in  std_ulogic;
                        clk: in  std_ulogic;
                        rst: in  std_ulogic;
                        rst: in  std_ulogic;
                        di:  in  std_ulogic;
                        di:  in  std_ulogic;
                        do:  out std_ulogic);
                        do:  out std_ulogic);
        end component;
        end component;
 
 
        component state_block_changed is
        component state_block_changed is
                generic(N: positive);
                generic (g: common_generics; N: positive);
                port(
                port(
                        clk: in  std_ulogic;
                        clk: in  std_ulogic;
                        rst: in  std_ulogic;
                        rst: in  std_ulogic;
                        di:  in  std_ulogic_vector(N - 1 downto 0);
                        di:  in  std_ulogic_vector(N - 1 downto 0);
                        do:  out std_ulogic_vector(N - 1 downto 0));
                        do:  out std_ulogic_vector(N - 1 downto 0));
        end component;
        end component;
 
 
 
        component reset_generator is
 
                generic (g: common_generics; reset_period_us: natural := 1);
 
                port (
 
                        clk: in  std_logic := 'X';
 
                        rst: out std_logic := '0'); -- reset out!
 
        end component;
 
 
 
        component reset_generator_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
 
        function n_bits(x: natural) return natural;           -- Not synthesizable
 
        function n_bits(x: std_ulogic_vector) return natural; -- Not synthesizable
 
 
 
        component bit_count is
 
                generic (g: common_generics; N: positive);
 
                port (
 
                        bits:   in std_ulogic_vector(N - 1 downto 0);
 
                        count: out std_ulogic_vector(n_bits(N) downto 0));
 
        end component;
 
 
 
        component bit_count_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
 
        component majority is
 
                generic (g: common_generics; N: positive; even_wins: boolean := false);
 
                port (
 
                        bits: in std_ulogic_vector(N - 1 downto 0);
 
                        vote: out std_ulogic;
 
                        tie: out std_ulogic);
 
        end component;
 
 
 
        component majority_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
 
        component delay_line is
 
                generic (g: common_generics; width: positive; depth: natural);
 
                port (
 
                        clk: in std_ulogic;
 
                        rst: in std_ulogic;
 
                        ce:  in std_ulogic := '1';
 
                        di:  in std_ulogic_vector(width - 1 downto 0);
 
                        do: out std_ulogic_vector(width - 1 downto 0));
 
        end component;
 
 
 
        component delay_line_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
 
        component gray_encoder is
 
                generic (g: common_generics; N: positive);
 
                port (di: in std_ulogic_vector(N - 1 downto 0);
 
                     do: out std_ulogic_vector(N - 1 downto 0));
 
        end component;
 
 
 
        component gray_decoder is
 
                generic (g: common_generics; N: positive);
 
                port (di: in std_ulogic_vector(N - 1 downto 0);
 
                     do: out std_ulogic_vector(N - 1 downto 0));
 
        end component;
 
 
 
        component gray_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
 
        component parity_module is
 
                generic (g: common_generics; N: positive; even: boolean);
 
                port (di: in std_ulogic_vector(N - 1 downto 0);
 
                        do: out std_ulogic);
 
        end component;
 
 
 
        component hamming_7_4_encoder is
 
                generic (g: common_generics);
 
                port (
 
                        di:      in std_ulogic_vector(3 downto 0);
 
                        do:     out std_ulogic_vector(6 downto 0);
 
                        parity: out std_ulogic -- parity over 'di'
 
                );
 
        end component;
 
 
 
        component hamming_7_4_decoder is
 
                generic (g: common_generics; secdec: boolean := true);
 
                port (
 
                        di:      in std_ulogic_vector(6 downto 0);
 
                        parity:  in std_ulogic;
 
                        do:     out std_ulogic_vector(3 downto 0);
 
                        single, double: out std_ulogic);
 
        end component;
 
 
 
        component hamming_7_4_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
 
        type vga_configuration is record
 
                clock_frequency: positive;   -- pixel clock frequency
 
                h_pulse:         integer;    -- horizontal sync pulse width in pixels
 
                h_back_porch:    integer;    -- horizontal back porch width in pixels
 
                h_pixels:        integer;    -- horizontal display width in pixels
 
                h_front_porch:   integer;    -- horizontal front porch width in pixels
 
                h_polarity:      std_ulogic; -- horizontal sync pulse polarity (1 = positive, 0 = negative)
 
 
 
                v_pulse:         integer;    -- vertical sync pulse width in rows
 
                v_back_porch:    integer;    -- vertical back porch width in rows
 
                v_pixels:        integer;    -- vertical display width in rows
 
                v_front_porch:   integer;    -- vertical front porch width in rows
 
                v_polarity:      std_ulogic; -- vertical sync pulse polarity (1 = positive, 0 = negative)
 
        end record;
 
 
 
        constant vga_640x480: vga_configuration := (
 
                clock_frequency => 25_175_000,
 
                h_pulse =>  96, h_back_porch =>  48, h_pixels =>  640, h_front_porch =>  16, h_polarity => '0',
 
                v_pulse =>   2, v_back_porch =>  33, v_pixels =>  480, v_front_porch =>  10, v_polarity => '0');
 
 
 
        constant vga_800x600: vga_configuration := (
 
                clock_frequency => 40_000_000,
 
                h_pulse => 128, h_back_porch =>  88, h_pixels =>  800, h_front_porch =>  40, h_polarity => '1',
 
                v_pulse =>   4, v_back_porch =>  23, v_pixels =>  600, v_front_porch =>   1, v_polarity => '1');
 
 
 
        constant vga_1024x768: vga_configuration := (
 
                clock_frequency => 44_900_000,
 
                h_pulse => 176, h_back_porch =>  56, h_pixels => 1024, h_front_porch =>   8, h_polarity => '1',
 
                v_pulse => 8,   v_back_porch =>  41, v_pixels =>  800, v_front_porch =>   0, v_polarity => '1');
 
 
 
        constant vga_1920x1200: vga_configuration := (
 
                clock_frequency => 193_160_000,
 
                h_pulse => 208, h_back_porch => 336, h_pixels => 1920, h_front_porch => 128, h_polarity => '0',
 
                v_pulse => 3,   v_back_porch => 38,  v_pixels => 1200, v_front_porch =>   1, v_polarity => '1');
 
 
 
        component vga_controller is
 
        generic (
 
                g: common_generics;
 
                pixel_clock_frequency:  positive := 25_000_000;
 
                constant cfg: vga_configuration  := vga_640x480);
 
        port (
 
                clk, rst:          in std_ulogic;  -- pixel clock, must run at configured frequency
 
                h_sync, v_sync:   out std_ulogic;  -- sync pulses
 
                h_blank, v_blank: out std_ulogic;
 
                column, row:      out integer);   -- pixel coordinates
 
        end component;
 
 
 
        component vga_tb is
 
                generic (g: common_generics; pixel_clock_frequency: positive := 25_000_000; simulation_us: time := 20000 us);
 
        end component;
 
 
 
        constant led_7_segment_character_length: positive := 4;
 
        subtype led_7_segment_character is std_ulogic_vector(led_7_segment_character_length - 1 downto 0);
 
        subtype led_7_segment is std_ulogic_vector(7 downto 0);
 
 
 
        component led_7_segment_display is
 
                generic (g: common_generics;
 
                        use_bcd_not_hex:         boolean := true;
 
                        refresh_rate_us:         natural := 1500;
 
                        number_of_led_displays: positive := 4);
 
                port (
 
                        clk:      in   std_ulogic;
 
                        rst:      in   std_ulogic;
 
 
 
                        leds_we:  in   std_ulogic;
 
                        leds:     in   std_ulogic_vector((number_of_led_displays * led_7_segment_character_length) - 1 downto 0);
 
 
 
                        -- Physical outputs
 
                        an:       out  std_ulogic_vector(number_of_led_displays - 1 downto 0);  -- anodes, controls on/off
 
                        ka:       out  std_ulogic_vector(7 downto 0)); -- cathodes, data on display
 
        end component;
 
 
 
        component led_7_segment_display_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
 
        component sine is
 
                generic (g: common_generics; pipeline: boolean := true);
 
                port (
 
                        clk, rst, xwe: in std_ulogic;
 
                        x:  in  std_ulogic_vector(15 downto 0);
 
                        s:  out std_ulogic_vector(15 downto 0));
 
        end component;
 
 
 
        component cosine is
 
                generic (g: common_generics; pipeline: boolean := true);
 
                port (
 
                        clk, rst, xwe: in std_ulogic;
 
                        x:  in  std_ulogic_vector(15 downto 0);
 
                        s:  out std_ulogic_vector(15 downto 0));
 
        end component;
 
 
 
        component sine_tb is
 
                generic (g: common_generics);
 
        end component;
 
 
        function max(a: natural; b: natural) return natural;
        function max(a: natural; b: natural) return natural;
        function min(a: natural; b: natural) return natural;
        function min(a: natural; b: natural) return natural;
        function n_bits(x: natural) return natural;
 
        function n_bits(x: std_ulogic_vector) return natural;
 
        function reverse (a: in std_ulogic_vector) return std_ulogic_vector;
        function reverse (a: in std_ulogic_vector) return std_ulogic_vector;
        function invert(slv:std_ulogic_vector) return std_ulogic_vector;
        function invert(slv:std_ulogic_vector) return std_ulogic_vector;
        function parity(slv:std_ulogic_vector; even: boolean) return std_ulogic;
        function parity(slv:std_ulogic_vector; even: boolean) return std_ulogic;
 
        function parity(slv:std_ulogic_vector; even: std_ulogic) return std_ulogic;
 
        function or_reduce(slv:std_ulogic_vector) return std_ulogic;
 
        function and_reduce(slv:std_ulogic_vector) return std_ulogic;
        function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic;
        function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic;
        function priority(order: std_ulogic_vector; high: boolean) return natural;
        function priority(order: std_ulogic_vector; high: boolean) return natural;
        function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector;
        function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector;
        function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector;
        function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector;
        function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic;
        function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic;
        function mux(a, b : std_ulogic_vector) return std_ulogic;
        function mux(a, b : std_ulogic_vector) return std_ulogic;
        function decode(encoded: std_ulogic_vector) return std_ulogic_vector;
        function decode(encoded: std_ulogic_vector) return std_ulogic_vector;
        function hex_char_to_std_ulogic_vector(hc: character) return std_ulogic_vector;
 
        function to_std_ulogic_vector(s: string) return std_ulogic_vector;
        function to_std_ulogic_vector(s: string) return std_ulogic_vector;
 
        function logical(b: boolean) return std_ulogic;
 
        function bit_count_f(s: std_ulogic_vector) return integer;
 
        function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector;
 
 
        type ulogic_string is array(integer range <>) of std_ulogic_vector(7 downto 0);
        type ulogic_string is array(integer range <>) of std_ulogic_vector(7 downto 0);
        function to_std_ulogic_vector(s: string) return ulogic_string;
        function to_std_ulogic_vector(s: string) return ulogic_string;
 
 
        --- Not synthesizable ---
        -- synthesis translate_off
 
 
        subtype configuration_name is string(1 to 8);
        subtype configuration_name is string(1 to 8);
 
 
        type configuration_item is record
        type configuration_item is record
                name:  configuration_name;
                name:  configuration_name;
                value: integer;
                value: integer;
Line 348... Line 579...
        type configuration_items is array(integer range <>) of configuration_item;
        type configuration_items is array(integer range <>) of configuration_item;
 
 
        function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer;
        function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer;
        procedure read_configuration_tb(file_name:  string; ci: inout configuration_items);
        procedure read_configuration_tb(file_name:  string; ci: inout configuration_items);
        procedure write_configuration_tb(file_name: string; ci: configuration_items);
        procedure write_configuration_tb(file_name: string; ci: configuration_items);
 
        -- synthesis translate_on
end;
end;
 
 
package body util is
package body util is
 
 
        function max(a: natural; b: natural) return natural is
        function max(a: natural; b: natural) return natural is
Line 363... Line 594...
        function min(a: natural; b: natural) return natural is
        function min(a: natural; b: natural) return natural is
        begin
        begin
                if (a < b) then return a; else return b; end if;
                if (a < b) then return a; else return b; end if;
        end function;
        end function;
 
 
        function n_bits(x: natural) return natural is
        function n_bits(x: natural) return natural is -- Not synthesizable
                variable x1: natural := max(x, 1) - 1;
                variable x1: natural := max(x, 1) - 1;
                variable n:  natural := 1;
                variable n:  natural := 1;
        begin
        begin
                while x1 > 1 loop
                while x1 > 1 loop
                        x1 := x1 / 2;
                        x1 := x1 / 2;
                        n  := n + 1;
                        n  := n + 1;
                end loop;
                end loop;
                return n;
                return n;
        end function;
        end function;
 
 
        function n_bits(x: std_ulogic_vector) return natural is
        function n_bits(x: std_ulogic_vector) return natural is -- Not synthesizable
        begin
        begin
                return n_bits(x'high);
                return n_bits(x'high);
        end function;
        end function;
 
 
        -- https://stackoverflow.com/questions/13584307
        -- <https://stackoverflow.com/questions/13584307>
        function reverse (a: in std_ulogic_vector) return std_ulogic_vector is
        function reverse (a: in std_ulogic_vector) return std_ulogic_vector is
                variable result: std_ulogic_vector(a'range);
                variable result: std_ulogic_vector(a'range);
                alias aa: std_ulogic_vector(a'reverse_range) is a;
                alias aa: std_ulogic_vector(a'reverse_range) is a;
        begin
        begin
                for i in aa'range loop
                for i in aa'range loop
Line 411... Line 642...
                        z := z xor slv(i);
                        z := z xor slv(i);
                end loop;
                end loop;
                return z;
                return z;
        end;
        end;
 
 
 
        function parity(slv:std_ulogic_vector; even: std_ulogic) return std_ulogic is
 
                variable z: boolean := false;
 
        begin
 
                if even = '1' then
 
                        z := true;
 
                end if;
 
                return parity(slv, z);
 
        end;
 
 
 
        function or_reduce(slv:std_ulogic_vector) return std_ulogic is
 
                variable z: std_ulogic := '0';
 
        begin
 
                for i in slv'range loop
 
                        z := z or slv(i);
 
                end loop;
 
                return z;
 
        end;
 
 
 
        function and_reduce(slv:std_ulogic_vector) return std_ulogic is
 
                variable z: std_ulogic := '1';
 
        begin
 
                for i in slv'range loop
 
                        z := z and slv(i);
 
                end loop;
 
                return z;
 
        end;
 
 
        function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic is
        function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic is
                variable z: std_ulogic := 'X';
                variable z: std_ulogic := 'X';
        begin
        begin
                assert n_bits(indexed) = selector'high + 1 severity failure;
                assert n_bits(indexed) = selector'high + 1 severity failure;
                for i in indexed'range loop
                for i in indexed'range loop
Line 480... Line 738...
                i    := to_integer(unsigned(encoded));
                i    := to_integer(unsigned(encoded));
                r(i) := '1';
                r(i) := '1';
                return r;
                return r;
        end;
        end;
 
 
        function hex_char_to_std_ulogic_vector(hc: character) return std_ulogic_vector is
        function logical(b: boolean) return std_ulogic is
 
        begin
 
                if b then return '1'; else return '0'; end if;
 
        end;
 
 
 
        function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector is
                variable slv: std_ulogic_vector(3 downto 0);
                variable slv: std_ulogic_vector(3 downto 0);
        begin
        begin
                case hc is
                case hc is
                when '0' => slv := "0000";
                when '0' => slv := "0000";
                when '1' => slv := "0001";
                when '1' => slv := "0001";
Line 512... Line 775...
                end case;
                end case;
                assert (slv /= "XXXX") report " not a valid hex character: " & hc  severity failure;
                assert (slv /= "XXXX") report " not a valid hex character: " & hc  severity failure;
                return slv;
                return slv;
        end;
        end;
 
 
 
        function bit_count_f(s : std_ulogic_vector) return integer is
 
                variable count: natural := 0;
 
        begin
 
                for i in s'range loop
 
                        if s(i) = '1' then
 
                                count := count + 1;
 
                        end if;
 
                end loop;
 
                return count;
 
        end;
 
 
        -- <https://stackoverflow.com/questions/30519849/vhdl-convert-string-to-std-logic-vector>
        -- <https://stackoverflow.com/questions/30519849/vhdl-convert-string-to-std-logic-vector>
        function to_std_ulogic_vector(s: string) return std_ulogic_vector is
        function to_std_ulogic_vector(s: string) return std_ulogic_vector is
            variable ret: std_ulogic_vector(s'length*8-1 downto 0);
            variable ret: std_ulogic_vector(s'length*8-1 downto 0);
        begin
        begin
            for i in s'range loop
            for i in s'range loop
Line 531... Line 805...
                        ret(i) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
                        ret(i) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
                end loop;
                end loop;
                return ret;
                return ret;
        end;
        end;
 
 
        --- Not synthesizable ---
        -- synthesis translate_off
 
 
        -- Find a string in a configuration items array, or returns -1 on
        -- Find a string in a configuration items array, or returns -1 on
        -- failure to find the string.
        -- failure to find the string.
        function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer is
        function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer is
        begin
        begin
Line 606... Line 880...
                        write(out_line, ci(i).value);
                        write(out_line, ci(i).value);
                        writeline(out_file, out_line);
                        writeline(out_file, out_line);
                end loop;
                end loop;
        end procedure;
        end procedure;
 
 
 
        -- synthesis translate_on
end;
end;
 
 
------------------------- Utility Test Bench ----------------------------------------
------------------------- Utility Test Bench ----------------------------------------
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use work.util.all;
use work.util.all;
 
 
entity util_tb is
entity util_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture behav of util_tb is
architecture behav of util_tb is
begin
begin
        uut_shiftReg: work.util.shift_register_tb    generic map(clock_frequency => clock_frequency);
        -- The "io_pins_tb" works correctly, however in GHDL 0.29, compiled under
        uut_timer_us: work.util.timer_us_tb          generic map(clock_frequency => clock_frequency);
        -- Windows, fails to simulate this component correctly, resulting
        uut_full_add: work.util.full_adder_tb        generic map(clock_frequency => clock_frequency);
        -- in a crash. This does not affect the Linux build of GHDL. It has
        uut_fifo:     work.util.fifo_tb              generic map(clock_frequency => clock_frequency);
        -- something to do with 'Z' values for std_logic types.
        uut_counter:  work.util.counter_tb           generic map(clock_frequency => clock_frequency);
        uut_io_pins:  work.util.io_pins_tb              generic map (g => g);
        uut_lfsr:     work.util.lfsr_tb              generic map(clock_frequency => clock_frequency);
        uut_timer_us: work.util.timer_us_tb             generic map (g => g);
        uut_ucpu:     work.util.ucpu_tb              generic map(clock_frequency => clock_frequency);
        uut_full_add: work.util.full_adder_tb           generic map (g => g);
        uut_rdivider: work.util.restoring_divider_tb generic map(clock_frequency => clock_frequency);
        uut_fifo:     work.util.fifo_tb                 generic map (g => g);
        uut_debounce: work.util.debounce_us_tb       generic map(clock_frequency => clock_frequency);
        uut_counter:  work.util.counter_tb              generic map (g => g);
        uut_rising_edge_detector: work.util.rising_edge_detector_tb generic map(clock_frequency => clock_frequency);
        uut_ucpu:     work.util.ucpu_tb                 generic map (g => g);
 
        uut_rdivider: work.util.restoring_divider_tb    generic map (g => g);
 
        uut_debounce: work.util.debounce_us_tb          generic map (g => g);
 
        uut_rst_gen:  work.util.reset_generator_tb      generic map (g => g);
 
        uut_bit_cnt:  work.util.bit_count_tb            generic map (g => g);
 
        uut_majority: work.util.majority_tb             generic map (g => g);
 
        uut_delay_ln: work.util.delay_line_tb           generic map (g => g);
 
        uut_rising:   work.util.rising_edge_detector_tb generic map (g => g);
 
        uut_shiftReg: work.util.shift_register_tb       generic map (g => g);
 
        uut_lfsr:     work.util.lfsr_tb                 generic map (g => g);
 
        uut_gray:     work.util.gray_tb                 generic map (g => g);
 
        uut_ham:      work.util.hamming_7_4_tb          generic map (g => g); -- Oink!
 
        uut_vga:      work.util.vga_tb                  generic map (g => g, simulation_us => 1 us);
 
        uut_sine:     work.util.sine_tb                 generic map (g => g);
 
        uut_7_seg:   work.util.led_7_segment_display_tb generic map (g => g);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                assert max(5, 4)                 =  5      severity failure;
                assert max(5, 4)                 =  5      severity failure;
                assert work.util.min(5, 4)       =  4      severity failure;
                assert work.util.min(5, 4)       =  4      severity failure;
Line 656... Line 945...
                assert parity("1010001", true)   =  '1'    severity failure;
                assert parity("1010001", true)   =  '1'    severity failure;
                assert parity("0", false)        =  '1'    severity failure;
                assert parity("0", false)        =  '1'    severity failure;
                assert parity("1", false)        =  '0'    severity failure;
                assert parity("1", false)        =  '0'    severity failure;
                assert parity("11", false)       =  '1'    severity failure;
                assert parity("11", false)       =  '1'    severity failure;
                assert parity("1010001", false)  =  '0'    severity failure;
                assert parity("1010001", false)  =  '0'    severity failure;
 
                assert or_reduce("0000")         =  '0'    severity failure;
 
                assert or_reduce("0")            =  '0'    severity failure;
 
                assert or_reduce("1")            =  '1'    severity failure;
 
                assert or_reduce("11")           =  '1'    severity failure;
 
                assert or_reduce("10")           =  '1'    severity failure;
 
                assert or_reduce("01")           =  '1'    severity failure;
 
                assert and_reduce("01")          =  '0'    severity failure;
 
                assert and_reduce("11")          =  '1'    severity failure;
 
                assert and_reduce("1")           =  '1'    severity failure;
 
                assert and_reduce("0")           =  '0'    severity failure;
 
                assert and_reduce("10")          =  '0'    severity failure;
                assert priority("01001", false)  =  1      severity failure;
                assert priority("01001", false)  =  1      severity failure;
                assert mux("1010", "0101", '0')  =  "1010" severity failure;
                assert mux("1010", "0101", '0')  =  "1010" severity failure;
                assert mux("1010", "0101", '1')  =  "0101" severity failure;
                assert mux("1010", "0101", '1')  =  "0101" severity failure;
                assert decode("00")              =  "0001" severity failure;
                assert decode("00")              =  "0001" severity failure;
                assert decode("01")              =  "0010" severity failure;
                assert decode("01")              =  "0010" severity failure;
                assert decode("10")              =  "0100" severity failure;
                assert decode("10")              =  "0100" severity failure;
                assert decode("11")              =  "1000" severity failure;
                assert decode("11")              =  "1000" severity failure;
                -- n_bits(x: std_ulogic_vector) return natural;
 
                -- mux(a, b : std_ulogic_vector) return std_ulogic;
 
                wait;
                wait;
        end process;
        end process;
end architecture;
end architecture;
 
 
------------------------- Function Test Bench ---------------------------------------
------------------------- Function Test Bench ---------------------------------------
 
 
------------------------- Test bench clock source -----------------------------------
------------------------- Test bench clock source -----------------------------------
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use ieee.math_real.all;
 
use work.util.common_generics;
 
 
entity clock_source_tb is
entity clock_source_tb is
        generic(clock_frequency: positive; hold_rst: positive := 1);
        generic (g: common_generics; hold_rst: positive);
        port(
        port(
                stop:            in     std_ulogic := '0';
                stop:            in     std_ulogic := '0';
                clk:             buffer std_ulogic;
                clk:             out    std_ulogic;
                clk_with_jitter: out    std_ulogic := '0';
                clk_with_jitter: out    std_ulogic := '0';
                rst:             out    std_ulogic := '0');
                rst:             out    std_ulogic := '0');
end entity;
end entity;
 
 
architecture rtl of clock_source_tb is
architecture rtl of clock_source_tb is
        constant clock_period: time      :=  1000 ms / clock_frequency;
        constant clock_period: time      :=  1000 ms / g.clock_frequency;
        signal jitter_delay:   time      := 0 ns;
        signal jitter_delay:   time      := 0 ns;
        signal jitter_clk:     std_ulogic := '0';
        signal jitter_clk:     std_ulogic := '0';
begin
begin
        clk_process: process
        jitter_clk_process: process
                variable seed1, seed2 : positive;
                variable seed1, seed2 : positive;
                variable r : real;
                variable r : real;
 
                variable jit_high, jit_low: time  := 0 ns;
        begin
        begin
                while stop = '0' loop
                while stop = '0' loop
                        uniform(seed1, seed2, r);
                        uniform(seed1, seed2, r);
                        jitter_delay <= r * 1 ns;
                        jit_high := r * g.delay;
 
                        uniform(seed1, seed2, r);
 
                        jit_low := r * g.delay;
 
                        uniform(seed1, seed2, r);
 
                        if r < 0.5 then jit_high := -jit_high; end if;
 
                        uniform(seed1, seed2, r);
 
                        if r < 0.5 then jit_low := -jit_low; end if;
 
                        clk_with_jitter <= '1';
 
                        wait for (clock_period / 2) + jit_high;
 
                        clk_with_jitter <= '0';
 
                        wait for (clock_period / 2) + jit_low;
 
                end loop;
 
                wait;
 
        end process;
 
 
 
        clk_process: process
 
        begin
 
                while stop = '0' loop
                        clk <= '1';
                        clk <= '1';
                        wait for clock_period / 2;
                        wait for clock_period / 2;
                        clk <= '0';
                        clk <= '0';
                        wait for clock_period / 2;
                        wait for clock_period / 2;
                end loop;
                end loop;
                wait;
                wait;
        end process;
        end process;
 
 
        clk_with_jitter <= transport clk after jitter_delay;
 
 
 
        rst_process: process
        rst_process: process
        begin
        begin
                rst <= '1';
                rst <= '1';
                wait for clock_period * hold_rst;
                wait for clock_period * hold_rst;
                rst <= '0';
                rst <= '0';
Line 722... Line 1036...
 
 
end architecture;
end architecture;
 
 
------------------------- Generic Register of std_ulogic_vector ----------------------
------------------------- Generic Register of std_ulogic_vector ----------------------
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity reg is
entity reg is
        generic(
        generic (g: common_generics; N: positive);
                N: positive);
        port (
        port
 
        (
 
                clk: in  std_ulogic;
                clk: in  std_ulogic;
                rst: in  std_ulogic;
                rst: in  std_ulogic;
                we:  in  std_ulogic;
                we:  in  std_ulogic;
                di:  in  std_ulogic_vector(N - 1 downto 0);
                di:  in  std_ulogic_vector(N - 1 downto 0);
                do:  out std_ulogic_vector(N - 1 downto 0));
                do:  out std_ulogic_vector(N - 1 downto 0));
end entity;
end entity;
 
 
architecture rtl of reg is
architecture rtl of reg is
        signal r_c, r_n: std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal r_c, r_n: std_ulogic_vector(N - 1 downto 0) := (others => '0');
begin
begin
        do <= r_c;
        do <= r_c after g.delay;
 
 
        process(rst, clk)
        process(rst, clk)
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        r_c <= (others => '0');
                        r_c <= (others => '0') after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        r_c <= r_n;
                        if rst = '1' and not g.asynchronous_reset then
 
                                r_c <= (others => '0') after g.delay;
 
                        else
 
                                r_c <= r_n after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        process(r_c, di, we)
        process(r_c, di, we)
        begin
        begin
                r_n <= r_c;
 
                if we = '1' then
                if we = '1' then
                        r_n <= di;
                        r_n <= di after g.delay;
 
                else
 
                        r_n <= r_c after g.delay;
                end if;
                end if;
        end process;
        end process;
end;
end;
 
 
------------------------- Generic Register of std_ulogic_vector ----------------------
------------------------- Generic Register of std_ulogic_vector ----------------------
 
 
------------------------- Shift register --------------------------------------------
------------------------- Shift register --------------------------------------------
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util.common_generics;
 
 
-- https://stackoverflow.com/questions/36342960/optional-ports-in-vhdl
-- https://stackoverflow.com/questions/36342960/optional-ports-in-vhdl
entity shift_register is
entity shift_register is
        generic(N: positive);
        generic (g: common_generics; N: positive);
        port
        port (
        (
 
                clk:     in  std_ulogic;
                clk:     in  std_ulogic;
                rst:     in  std_ulogic;
                rst:     in  std_ulogic;
                we:      in  std_ulogic;
                we:      in  std_ulogic;
                di:      in  std_ulogic;
                di:      in  std_ulogic;
                do:      out std_ulogic;
                do:      out std_ulogic;
 
 
 
                -- optional
                load_we: in  std_ulogic := '0';
                load_we: in  std_ulogic := '0';
                load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
                load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
                load_o:  out std_ulogic_vector(N - 1 downto 0));
                load_o:  out std_ulogic_vector(N - 1 downto 0));
end entity;
end entity;
 
 
Line 792... Line 1110...
        do     <= r_c(0);
        do     <= r_c(0);
        load_o <= r_c;
        load_o <= r_c;
 
 
        process(rst, clk)
        process(rst, clk)
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        r_c <= (others => '0');
                        r_c <= (others => '0') after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        r_c <= r_n;
                        if rst = '1' and not g.asynchronous_reset then
 
                                r_c <= (others => '0') after g.delay;
 
                        else
 
                                r_c <= r_n after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        process(r_c, di, we, load_i, load_we)
        process(r_c, di, we, load_i, load_we)
        begin
        begin
                if load_we = '1' then
                if load_we = '1' then
                        r_n <= load_i;
                        r_n <= load_i after g.delay;
                else
                else
                        r_n <= "0" & r_c(N - 1 downto 1);
                        r_n <= "0" & r_c(N - 1 downto 1) after g.delay;
                        if we = '1' then
                        if we = '1' then
                                r_n(N-1) <= di;
                                r_n(N-1) <= di after g.delay;
                        end if;
                        end if;
                end if;
                end if;
        end process;
        end process;
end;
end;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util.common_generics;
 
 
entity shift_register_tb is
entity shift_register_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture behav of shift_register_tb is
architecture behav of shift_register_tb is
        constant N: positive := 8;
        constant N: positive := 8;
        constant clock_period: time :=  1000 ms / clock_frequency;
        constant clock_period: time :=  1000 ms / g.clock_frequency;
        signal we: std_ulogic := '0';
        signal we: std_ulogic := '0';
        signal di: std_ulogic := '0';
        signal di: std_ulogic := '0';
        signal do: std_ulogic := '0';
        signal do: std_ulogic := '0';
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop: std_ulogic := '0';
        signal stop: std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.shift_register
        uut: entity work.shift_register
        generic map(N => N) port map(clk => clk, rst => rst, we => we, di => di, do => do);
        generic map (g => g, N => N) port map (clk => clk, rst => rst, we => we, di => di, do => do);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                -- put a bit into the shift register and wait
                -- Put a bit into the shift register and wait
                -- for it to come out the other size
                -- for it to come out the other size.
                wait until rst = '0';
                wait until rst = '0';
                di <= '1';
                di <= '1';
                we <= '1';
                we <= '1';
                wait for clock_period;
                wait for clock_period;
                di <= '0';
                di <= '0';
Line 861... Line 1183...
        end process;
        end process;
end;
end;
------------------------- Shift register --------------------------------------------
------------------------- Shift register --------------------------------------------
 
 
------------------------- Microsecond Timer -----------------------------------------
------------------------- Microsecond Timer -----------------------------------------
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use work.util.max;
use work.util.max;
use work.util.n_bits;
use work.util.n_bits;
 
use work.util.common_generics;
 
 
entity timer_us is
entity timer_us is
        generic(
        generic (g: common_generics; timer_period_us: natural);
                clock_frequency: positive;
 
                timer_period_us: positive := 1);
 
        port(
        port(
                clk:  in std_ulogic := 'X';
                clk: in  std_ulogic;
                rst:  in std_ulogic := 'X';
                rst: in  std_ulogic;
                co:  out std_ulogic := '0');
                co:  out std_ulogic);
end timer_us;
end timer_us;
 
 
architecture rtl of timer_us is
architecture rtl of timer_us is
        constant cycles:   natural := (clock_frequency / 1000000) * timer_period_us;
        constant cycles:   natural := (g.clock_frequency / 1000000) * timer_period_us;
        subtype  counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
        subtype  counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
        signal   c_c, c_n: counter := (others => '0');
        signal   c_c, c_n: counter := (others => '0');
begin
begin
        process (clk, rst)
        process (clk, rst)
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        c_c <= (others => '0');
                        c_c <= (others => '0') after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        c_c <= c_n;
                        if rst = '1' and not g.asynchronous_reset then
 
                                c_c <= (others => '0') after g.delay;
 
                        else
 
                                c_c <= c_n after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        process (c_c)
        process (c_c)
        begin
        begin
                if c_c = (cycles - 1) then
                if c_c = (cycles - 1) then
                        c_n <= (others => '0');
                        c_n <= (others => '0') after g.delay;
                        co  <= '1';
                        co  <= '1' after g.delay;
                else
                else
                        c_n <= c_c + 1;
                        c_n <= c_c + 1 after g.delay;
                        co  <= '0';
                        co  <= '0' after g.delay;
                end if;
                end if;
        end process;
        end process;
end;
end;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity timer_us_tb is
entity timer_us_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end;
end;
 
 
architecture behav of timer_us_tb is
architecture behav of timer_us_tb is
        constant clock_period: time := 1000 ms / clock_frequency;
        constant clock_period: time := 1000 ms / g.clock_frequency;
        signal co: std_ulogic        := 'X';
        signal co: std_ulogic        := 'X';
        signal clk, rst: std_ulogic  := '0';
        signal clk, rst: std_ulogic  := '0';
        signal stop: std_ulogic      := '0';
        signal stop: std_ulogic      := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.timer_us
        uut: entity work.timer_us
                generic map(clock_frequency => clock_frequency, timer_period_us => 1)
                generic map (g => g, timer_period_us => 1)
                port map(clk => clk, rst => rst, co => co);
                port map(clk => clk, rst => rst, co => co);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                wait for 1 us;
                wait for 1 us;
Line 939... Line 1265...
end;
end;
 
 
------------------------- Microsecond Timer -----------------------------------------
------------------------- Microsecond Timer -----------------------------------------
 
 
------------------------- Rising Edge Detector --------------------------------------
------------------------- Rising Edge Detector --------------------------------------
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
 
use work.util.common_generics;
 
 
entity rising_edge_detector is
entity rising_edge_detector is
 
        generic (g: common_generics);
port(
port(
        clk:    in  std_ulogic;
        clk:    in  std_ulogic;
        rst:    in  std_ulogic;
        rst:    in  std_ulogic;
        di:     in  std_ulogic;
        di:     in  std_ulogic;
        do:     out std_ulogic);
        do:     out std_ulogic);
Line 956... Line 1284...
        signal sin_0: std_ulogic := '0';
        signal sin_0: std_ulogic := '0';
        signal sin_1: std_ulogic := '0';
        signal sin_1: std_ulogic := '0';
begin
begin
        red: process(clk, rst)
        red: process(clk, rst)
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        sin_0 <= '0';
                        sin_0 <= '0' after g.delay;
                        sin_1 <= '0';
                        sin_1 <= '0' after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        sin_0 <= di;
                        if rst = '1' and not g.asynchronous_reset then
                        sin_1 <= sin_0;
                                sin_0 <= '0' after g.delay;
 
                                sin_1 <= '0' after g.delay;
 
                        else
 
                                sin_0 <=    di after g.delay;
 
                                sin_1 <= sin_0 after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
        do <= not sin_1 and sin_0;
        do <= not sin_1 and sin_0;
end architecture;
end architecture;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util.common_generics;
 
 
entity rising_edge_detector_tb is
entity rising_edge_detector_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end;
end;
 
 
architecture behav of rising_edge_detector_tb is
architecture behav of rising_edge_detector_tb is
        constant clock_period: time := 1000 ms / clock_frequency;
        constant clock_period: time := 1000 ms / g.clock_frequency;
        signal di:  std_ulogic := '0';
        signal di:  std_ulogic := '0';
        signal do: std_ulogic := 'X';
        signal do: std_ulogic := 'X';
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop: std_ulogic := '0';
        signal stop: std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.rising_edge_detector
        uut: entity work.rising_edge_detector
 
                generic map (g => g)
                port map(clk => clk, rst => rst, di => di, do => do);
                port map(clk => clk, rst => rst, di => di, do => do);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                wait for clock_period * 5;
                wait for clock_period * 5;
Line 1010... Line 1344...
                stop <= '1';
                stop <= '1';
                wait;
                wait;
        end process;
        end process;
end architecture;
end architecture;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
 
use work.util.common_generics;
 
 
entity rising_edge_detectors is
entity rising_edge_detectors is
generic(N: positive);
        generic (g: common_generics; N: positive);
port(
port(
        clk:    in  std_ulogic;
        clk:    in  std_ulogic;
        rst:    in  std_ulogic;
        rst:    in  std_ulogic;
        di:     in  std_ulogic_vector(N - 1 downto 0);
        di:     in  std_ulogic_vector(N - 1 downto 0);
        do:     out std_ulogic_vector(N - 1 downto 0));
        do:     out std_ulogic_vector(N - 1 downto 0));
Line 1026... Line 1361...
 
 
architecture structural of rising_edge_detectors is
architecture structural of rising_edge_detectors is
begin
begin
        changes: for i in N - 1 downto 0 generate
        changes: for i in N - 1 downto 0 generate
                d_instance: work.util.rising_edge_detector
                d_instance: work.util.rising_edge_detector
 
                        generic map (g => g)
                        port map(clk => clk, rst => rst, di => di(i), do => do(i));
                        port map(clk => clk, rst => rst, di => di(i), do => do(i));
        end generate;
        end generate;
end architecture;
end architecture;
 
 
------------------------- Rising Edge Detector --------------------------------------
------------------------- Rising Edge Detector --------------------------------------
 
 
------------------------- Half Adder ------------------------------------------------
------------------------- Half Adder ------------------------------------------------
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
 
use work.util.common_generics;
 
 
entity half_adder is
entity half_adder is
 
        generic (g: common_generics);
        port(
        port(
                a:     in  std_ulogic;
                a:     in  std_ulogic;
                b:     in  std_ulogic;
                b:     in  std_ulogic;
                sum:   out std_ulogic;
                sum:   out std_ulogic;
                carry: out std_ulogic);
                carry: out std_ulogic);
end entity;
end entity;
 
 
architecture rtl of half_adder is
architecture rtl of half_adder is
begin
begin
        sum   <= a xor b;
        sum   <= a xor b after g.delay;
        carry <= a and b;
        carry <= a and b after g.delay;
end architecture;
end architecture;
 
 
------------------------- Half Adder ------------------------------------------------
------------------------- Half Adder ------------------------------------------------
 
 
------------------------- Full Adder ------------------------------------------------
------------------------- Full Adder ------------------------------------------------
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
 
use work.util.common_generics;
 
 
entity full_adder is
entity full_adder is
 
        generic (g: common_generics);
        port(
        port(
                x:     in    std_ulogic;
                x:     in    std_ulogic;
                y:     in    std_ulogic;
                y:     in    std_ulogic;
                z:     in    std_ulogic;
                z:     in    std_ulogic;
                sum:   out   std_ulogic;
                sum:   out   std_ulogic;
Line 1069... Line 1409...
end entity;
end entity;
 
 
architecture rtl of full_adder is
architecture rtl of full_adder is
        signal carry1, carry2, sum1: std_ulogic;
        signal carry1, carry2, sum1: std_ulogic;
begin
begin
        ha1: entity work.half_adder port map(a => x,    b => y, sum => sum1, carry => carry1);
        ha1: entity work.half_adder generic map (g => g) port map (a => x,    b => y, sum => sum1, carry => carry1);
        ha2: entity work.half_adder port map(a => sum1, b => z, sum => sum,  carry => carry2);
        ha2: entity work.half_adder generic map (g => g) port map (a => sum1, b => z, sum => sum,  carry => carry2);
        carry <= carry1 or carry2;
        carry <= carry1 or carry2 after g.delay;
end architecture;
end architecture;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
 
use work.util.common_generics;
 
 
entity full_adder_tb is
entity full_adder_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture behav of full_adder_tb is
architecture behav of full_adder_tb is
        constant clock_period: time  := 1000 ms / clock_frequency;
        constant clock_period: time  := 1000 ms / g.clock_frequency;
        signal x, y, z:    std_ulogic := '0';
        signal x, y, z:    std_ulogic := '0';
        signal sum, carry: std_ulogic := '0';
        signal sum, carry: std_ulogic := '0';
 
 
        type stimulus_data   is array (0 to 7)              of std_ulogic_vector(2 downto 0);
        type stimulus_data   is array (0 to 7)              of std_ulogic_vector(2 downto 0);
        type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to     1);
        type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to     1);
Line 1105... Line 1446...
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop: std_ulogic     := '0';
        signal stop: std_ulogic     := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.full_adder port map(x => x, y => y, z => z, sum => sum, carry => carry);
        uut: entity work.full_adder
 
                generic map (g => g)
 
                port map (x => x, y => y, z => z, sum => sum, carry => carry);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                wait for clock_period;
                wait for clock_period;
                for i in data'range loop
                for i in data'range loop
Line 1135... Line 1478...
end architecture;
end architecture;
 
 
------------------------- Full Adder ------------------------------------------------
------------------------- Full Adder ------------------------------------------------
 
 
------------------------- FIFO ------------------------------------------------------
------------------------- FIFO ------------------------------------------------------
 
library ieee, work;
-- Originally from http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/
 
-- @copyright Public Domain
 
-- @todo Add more comments about the FIFOs origin, add assertions test
 
-- synthesis, make this more generic (with empty FIFO and FIFO count signals)
 
--
 
-- The code can be used freely and appears to be public domain, comment
 
-- from author is: "You can use any code posted here freely, there is no copyright."
 
--
 
-- @note The FIFO has been modified from the original to bring it in line with
 
-- this projects coding standards.
 
 
 
library ieee;
 
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity fifo is
entity fifo is
        generic(
        generic (g: common_generics;
                data_width: positive;
                data_width: positive;
                fifo_depth: positive);
                fifo_depth: positive;
 
                read_first: boolean := true);
        port(
        port(
                clk:   in  std_ulogic;
                clk:   in  std_ulogic;
                rst:   in  std_ulogic;
                rst:   in  std_ulogic;
                we:    in  std_ulogic;
 
                di:    in  std_ulogic_vector (data_width - 1 downto 0);
                di:    in  std_ulogic_vector (data_width - 1 downto 0);
 
                we:    in  std_ulogic;
                re:    in  std_ulogic;
                re:    in  std_ulogic;
                do:    out std_ulogic_vector (data_width - 1 downto 0);
                do:    out std_ulogic_vector (data_width - 1 downto 0);
                empty: out std_ulogic := '1';
 
                full:  out std_ulogic := '0');
 
end fifo;
 
 
 
architecture behavioral of fifo is
 
begin
 
 
 
        -- memory pointer process
 
        fifo_proc: process (clk, rst)
 
                type fifo_memory is array (0 to fifo_depth - 1) of std_ulogic_vector (data_width - 1 downto 0);
 
                variable memory: fifo_memory;
 
 
 
                variable head: natural range 0 to fifo_depth - 1;
                -- optional
                variable tail: natural range 0 to fifo_depth - 1;
                full:  out std_ulogic := '0';
 
                empty: out std_ulogic := '1');
 
end fifo;
 
 
                variable looped: boolean;
architecture behavior of fifo is
 
        type fifo_data_t is array (0 to fifo_depth - 1) of std_ulogic_vector(di'range);
 
        signal data: fifo_data_t := (others => (others => '0'));
 
        function rindex_init return integer is
        begin
        begin
                if rst = '1' then
                if read_first then
                        head := 0;
                        return 0;
                        tail := 0;
                end if;
 
                return fifo_depth - 1;
                        looped := false;
        end function;
 
 
                        full  <= '0';
        signal count:  integer range 0 to fifo_depth := 0;
                        empty <= '1';
        signal windex: integer range 0 to fifo_depth - 1 := 0;
                        do    <= (others => '0');
        signal rindex: integer range 0 to fifo_depth - 1 := rindex_init;
 
 
 
        signal is_full:  std_ulogic := '0';
 
        signal is_empty: std_ulogic := '1';
 
begin
 
        do       <= data(rindex) after g.delay;
 
        full     <= is_full after g.delay;  -- buffer these bad boys
 
        empty    <= is_empty after g.delay;
 
        is_full  <= '1' when count = fifo_depth else '0' after g.delay;
 
        is_empty <= '1' when count = 0          else '0' after g.delay;
 
 
 
        process (rst, clk) is
 
        begin
 
                if rst = '1' and g.asynchronous_reset then
 
                        windex <= 0 after g.delay;
 
                        count  <= 0 after g.delay;
 
                        rindex <= rindex_init after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        do    <= (others => '0');
                        if rst = '1' and not g.asynchronous_reset then
                        if re = '1' then
                                windex <= 0 after g.delay;
                                if looped = true or head /= tail then
                                count  <= 0 after g.delay;
                                        -- update data output
                                rindex <= rindex_init after g.delay;
                                        do <= memory(tail);
 
 
 
                                        -- update tail pointer as needed
 
                                        if tail = fifo_depth - 1 then
 
                                                tail   := 0;
 
                                                looped := false;
 
                                        else
                                        else
                                                tail := tail + 1;
                                if we = '1' and re = '0' then
 
                                        if is_full = '0' then
 
                                                count <= count + 1 after g.delay;
                                        end if;
                                        end if;
 
                                elsif we = '0' and re = '1' then
 
                                        if is_empty = '0' then
 
                                                count <= count - 1 after g.delay;
                                end if;
                                end if;
                        end if;
                        end if;
 
 
                        if we = '1' then
                                if re = '1' and is_empty = '0' then
                                if looped = false or head /= tail then
                                        if rindex = (fifo_depth - 1) then
                                        -- write data to memory
                                                rindex <= 0 after g.delay;
                                        memory(head) := di;
 
 
 
                                        -- increment head pointer as needed
 
                                        if head = fifo_depth - 1 then
 
                                                head := 0;
 
 
 
                                                looped := true;
 
                                        else
                                        else
                                                head := head + 1;
                                                rindex <= rindex + 1 after g.delay;
                                        end if;
 
                                end if;
                                end if;
                        end if;
                        end if;
 
 
                        -- update empty and full flags
                                if we = '1' and is_full = '0' then
                        if head = tail then
                                        if windex = (fifo_depth - 1) then
                                if looped then
                                                windex <= 0 after g.delay;
                                        full  <= '1';
 
                                else
                                else
                                        empty <= '1';
                                                windex <= windex + 1 after g.delay;
 
                                        end if;
 
                                        data(windex) <= di after g.delay;
                                end if;
                                end if;
                        else
 
                                empty   <= '0';
 
                                full    <= '0';
 
                        end if;
                        end if;
                end if;
                end if;
        end process;
        end process;
end architecture;
end behavior;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity fifo_tb is
entity fifo_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture behavior of fifo_tb is
architecture behavior of fifo_tb is
        constant clock_period: time  := 1000 ms / clock_frequency;
        constant clock_period: time  := 1000 ms / g.clock_frequency;
        constant data_width: positive := 8;
        constant data_width: positive := 8;
        constant fifo_depth: positive := 16;
        constant fifo_depth: positive := 16;
 
 
        signal di:      std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
        signal di:      std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
        signal re:       std_ulogic := '0';
        signal re:       std_ulogic := '0';
Line 1263... Line 1596...
        signal stop_w:   std_ulogic := '0';
        signal stop_w:   std_ulogic := '0';
        signal stop_r:   std_ulogic := '0';
        signal stop_r:   std_ulogic := '0';
        signal stop:     std_ulogic := '0';
        signal stop:     std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        stop <= '1' when stop_w = '1' and stop_r = '1' else '0';
        stop <= '1' when stop_w = '1' and stop_r = '1' else '0';
 
 
        uut: entity work.fifo
        uut: entity work.fifo
                generic map(data_width => data_width, fifo_depth => fifo_depth)
                generic map (g => g, data_width => data_width, fifo_depth => fifo_depth)
                port map (
                port map (
                        clk   => clk,
                        clk   => clk,
                        rst   => rst,
                        rst   => rst,
                        di    => di,
                        di    => di,
                        we    => we,
                        we    => we,
Line 1327... Line 1660...
 
 
------------------------- FIFO ------------------------------------------------------
------------------------- FIFO ------------------------------------------------------
 
 
------------------------- Free running counter --------------------------------------
------------------------- Free running counter --------------------------------------
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity counter is
entity counter is
        generic(
        generic (g: common_generics;
                N: positive);
                N: positive);
        port(
        port(
                clk:     in  std_ulogic;
                clk:     in  std_ulogic;
                rst:     in  std_ulogic;
                rst:     in  std_ulogic;
                ce:      in  std_ulogic;
                ce:      in  std_ulogic;
                cr:      in  std_ulogic;
                cr:      in  std_ulogic;
                dout:    out std_ulogic_vector(N - 1 downto 0);
                dout:    out std_ulogic_vector(N - 1 downto 0);
 
 
 
                -- optional
                load_we: in  std_ulogic := '0';
                load_we: in  std_ulogic := '0';
                load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
                load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
end entity;
end entity;
 
 
architecture rtl of counter is
architecture rtl of counter is
        signal c_c, c_n: unsigned(N - 1 downto 0) := (others => '0');
        signal c_c, c_n: unsigned(N - 1 downto 0) := (others => '0');
begin
begin
        dout <= std_ulogic_vector(c_c);
        dout <= std_ulogic_vector(c_c) after g.delay;
 
 
        process(clk, rst)
        process(clk, rst)
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        c_c <= (others => '0');
                        c_c <= (others => '0') after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        c_c <= c_n;
                        if rst = '1' and not g.asynchronous_reset then
 
                                c_c <= (others => '0') after g.delay;
 
                        else
 
                                c_c <= c_n after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        process(c_c, cr, ce, load_we, load_i)
        process(c_c, cr, ce, load_we, load_i)
        begin
        begin
                c_n <= c_c;
                c_n <= c_c;
                if load_we = '1' then
                if load_we = '1' then
                        c_n <= unsigned(load_i);
                        c_n <= unsigned(load_i) after g.delay;
                else
                else
                        if cr = '1' then
                        if cr = '1' then
                                c_n <= (others => '0');
                                c_n <= (others => '0') after g.delay;
                        elsif ce = '1' then
                        elsif ce = '1' then
                                c_n <= c_c + 1;
                                c_n <= c_c + 1 after g.delay;
                        end if;
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
end architecture;
end architecture;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity counter_tb is
entity counter_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture behavior of counter_tb is
architecture behavior of counter_tb is
        constant clock_period: time     := 1000 ms / clock_frequency;
        constant clock_period: time     := 1000 ms / g.clock_frequency;
        constant length:       positive := 2;
        constant length:       positive := 2;
 
 
        -- inputs
        -- inputs
        signal ce: std_ulogic := '0';
        signal ce: std_ulogic := '0';
        signal cr: std_ulogic := '0';
        signal cr: std_ulogic := '0';
Line 1424... Line 1764...
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop:     std_ulogic := '0';
        signal stop:     std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.counter
        uut: entity work.counter
                generic map(
                generic map (g => g, N => length)
                        N => length)
 
                port map(
                port map(
                        clk   => clk,
                        clk   => clk,
                        rst   => rst,
                        rst   => rst,
                        ce    => ce,
                        ce    => ce,
                        cr    => cr,
                        cr    => cr,
Line 1479... Line 1818...
-- Number of bits   Taps      Cycle Time
-- Number of bits   Taps      Cycle Time
--      8           1,2,3,7    255
--      8           1,2,3,7    255
--      16          1,2,4,15   65535
--      16          1,2,4,15   65535
--      32          1,5,6,31   4294967295
--      32          1,5,6,31   4294967295
--
--
-- This component could be improved a lot, and it could also be used to
-- This component could also be used to calculate CRCs, which are basically
-- calculate CRCs, which are basically the same computation. Its interface
-- the same computation.
-- is not the best either, being a free running counter.
 
--
--
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util.common_generics;
 
 
entity lfsr is
entity lfsr is
        generic(constant tap: std_ulogic_vector);
        generic (g: common_generics; constant tap: std_ulogic_vector);
        port
        port
        (
        (
                clk: in  std_ulogic;
                clk: in  std_ulogic;
                rst: in  std_ulogic;
                rst: in  std_ulogic;
                we:  in  std_ulogic;
 
                ce:  in  std_ulogic := '1';
                ce:  in  std_ulogic := '1';
 
                we:  in  std_ulogic;
                di:  in  std_ulogic_vector(tap'high + 1 downto tap'low);
                di:  in  std_ulogic_vector(tap'high + 1 downto tap'low);
                do:  out std_ulogic_vector(tap'high + 1 downto tap'low));
                do:  out std_ulogic_vector(tap'high + 1 downto tap'low));
end entity;
end entity;
 
 
architecture rtl of lfsr is
architecture rtl of lfsr is
        signal r_c, r_n : std_ulogic_vector(di'range) := (others => '0');
        signal r_c, r_n : std_ulogic_vector(di'range) := (others => '0');
begin
begin
        do <= r_c;
        do <= r_c after g.delay;
 
 
        process(rst, clk)
        process(rst, clk)
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        r_c <= (others => '0');
                        r_c <= (others => '0') after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        r_c <= r_n;
                        if rst = '1' and not g.asynchronous_reset then
 
                                r_c <= (others => '0') after g.delay;
 
                        else
 
                                r_c <= r_n after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        process(r_c, di, we, ce)
        process(r_c, di, we, ce)
        begin
        begin
                if we = '1' then
                if we = '1' then
                        r_n <= di;
                        r_n <= di after g.delay;
                elsif ce = '1' then
                elsif ce = '1' then
 
 
                        r_n(r_n'high) <= r_c(r_c'low);
                        r_n(r_n'high) <= r_c(r_c'low);
 
 
                        for i in tap'high downto tap'low loop
                        for i in tap'high downto tap'low loop
                                if tap(i) = '1' then
                                if tap(i) = '1' then
                                        r_n(i) <= r_c(r_c'low) xor r_c(i+1);
                                        r_n(i) <= r_c(r_c'low) xor r_c(i+1) after g.delay;
                                else
                                else
                                        r_n(i) <= r_c(i+1);
                                        r_n(i) <= r_c(i+1) after g.delay;
                                end if;
                                end if;
                        end loop;
                        end loop;
                else
                else
                        r_n <= r_c;
                        r_n <= r_c;
                end if;
                end if;
        end process;
        end process;
end architecture;
end architecture;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util.common_generics;
 
 
entity lfsr_tb is
entity lfsr_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture behavior of lfsr_tb is
architecture behavior of lfsr_tb is
        constant clock_period: time     := 1000 ms / clock_frequency;
        constant clock_period: time     := 1000 ms / g.clock_frequency;
        signal we: std_ulogic := '0';
        signal we: std_ulogic := '0';
        signal do, di: std_ulogic_vector(7 downto 0) := (others => '0');
        signal do, di: std_ulogic_vector(7 downto 0) := (others => '0');
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop:     std_ulogic := '0';
        signal stop:     std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.lfsr
        uut: entity work.lfsr
                generic map(tap => "0111001")
                generic map (g => g, tap => "0111001")
                port map(clk => clk,
                port map(clk => clk,
                         rst => rst,
                         rst => rst,
                         we => we,
                         we => we,
                         di => di,
                         di => di,
                         do => do);
                         do => do);
Line 1579... Line 1919...
end architecture;
end architecture;
 
 
------------------------- Linear Feedback Shift Register ----------------------------
------------------------- Linear Feedback Shift Register ----------------------------
 
 
------------------------- I/O Pin Controller ----------------------------------------
------------------------- I/O Pin Controller ----------------------------------------
-- @todo Test this in hardware
 
--
--
-- This is a simple I/O pin control module, there is a control register which
-- This is a simple I/O pin control module, there is a control register which
-- sets whether the pins are to be read in (control = '0') or set to the value written to
-- sets whether the pins are to be read in (control = '0') or set to the value written to
-- "din" (control = '1').
-- "din" (control = '1').
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util.common_generics;
 
 
entity io_pins is
entity io_pins is
        generic(
        generic (g: common_generics; N: positive);
                N: positive);
 
        port
        port
        (
        (
                clk:         in    std_ulogic;
                clk:         in    std_ulogic;
                rst:         in    std_ulogic;
                rst:         in    std_ulogic;
                control:     in    std_ulogic_vector(N - 1 downto 0);
                control:     in    std_ulogic_vector(N - 1 downto 0);
Line 1609... Line 1947...
architecture rtl of io_pins is
architecture rtl of io_pins is
        signal control_o: std_ulogic_vector(control'range) := (others => '0');
        signal control_o: std_ulogic_vector(control'range) := (others => '0');
        signal din_o:     std_ulogic_vector(din'range)     := (others => '0');
        signal din_o:     std_ulogic_vector(din'range)     := (others => '0');
begin
begin
 
 
        control_r: entity work.reg generic map(N => N) port map(clk => clk, rst => rst, di => control, we => control_we, do => control_o);
        control_r: entity work.reg generic map (g => g, N => N)
        din_r:     entity work.reg generic map(N => N) port map(clk => clk, rst => rst, di => din,     we => din_we,     do => din_o);
                                port map (clk => clk, rst => rst, di => control, we => control_we, do => control_o);
 
        din_r:     entity work.reg generic map (g => g, N => N)
 
                                port map (clk => clk, rst => rst, di => din,     we => din_we,     do => din_o);
 
 
        pins_i: for i in control_o'range generate
        pins_i: for i in control_o'range generate
                dout(i) <= pins(i)  when control_o(i) = '0' else '0';
                dout(i) <= pins(i)  when control_o(i) = '0' else '0' after g.delay;
                pins(i) <= din_o(i) when control_o(i) = '1' else 'Z';
                pins(i) <= din_o(i) when control_o(i) = '1' else 'Z' after g.delay;
        end generate;
        end generate;
 
 
end architecture;
end architecture;
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util.common_generics;
 
 
entity io_pins_tb is
entity io_pins_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture behavior of io_pins_tb is
architecture behavior of io_pins_tb is
        constant clock_period: time := 1000 ms / clock_frequency;
        constant clock_period: time := 1000 ms / g.clock_frequency;
        constant N: positive := 8;
        constant N: positive := 8;
 
 
        signal control: std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal control: std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal din:     std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal din:     std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal dout:    std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal dout:    std_ulogic_vector(N - 1 downto 0) := (others => '0');
Line 1644... Line 1984...
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop:     std_ulogic := '0';
        signal stop:     std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.io_pins
        uut: entity work.io_pins
                generic map(N => N)
                generic map (g => g, N => N)
                port map(
                port map(
                        clk         =>  clk,
                        clk         =>  clk,
                        rst         =>  rst,
                        rst         =>  rst,
                        control     =>  control,
                        control     =>  control,
                        control_we  =>  control_we,
                        control_we  =>  control_we,
Line 1681... Line 2021...
end architecture;
end architecture;
 
 
------------------------- I/O Pin Controller ----------------------------------------
------------------------- I/O Pin Controller ----------------------------------------
 
 
------------------------- Single and Dual Port Block RAM ----------------------------
------------------------- Single and Dual Port Block RAM ----------------------------
--|
 
--| @warning The function initialize_ram has to be present in each architecture
--| @warning The function initialize_ram has to be present in each architecture
--| block ram that uses it (as far as I am aware) which means they could fall
--| block ram that uses it (as far as I am aware) which means they could fall
--| out of sync. This could be remedied with VHDL-2008.
--| out of sync. This could be remedied with VHDL-2008.
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
 
 
--- Dual Port Model ---
--- Dual Port Model ---
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.textio.all;
use work.util.all;
use work.util.all;
 
 
Line 1708... Line 2047...
        -- FILE_BINARY - A binary file (ASCII '0' and '1', one number per line)
        -- FILE_BINARY - A binary file (ASCII '0' and '1', one number per line)
        -- FILE_HEX    - A Hex file (ASCII '0-9' 'a-f', 'A-F', one number per line)
        -- FILE_HEX    - A Hex file (ASCII '0-9' 'a-f', 'A-F', one number per line)
        -- FILE_NONE   - RAM contents will be defaulted to all zeros, no file will
        -- FILE_NONE   - RAM contents will be defaulted to all zeros, no file will
        --               be read from
        --               be read from
        --
        --
        -- @todo Read in actual binary data files, see: https://stackoverflow.com/questions/14173652
 
        --
 
        -- The data length must be divisible by 4 if the "hex" option is
        -- The data length must be divisible by 4 if the "hex" option is
        -- given.
        -- given.
        --
        --
        -- These default values for addr_length and data_length have been
        -- These default values for addr_length and data_length have been
        -- chosen so as to fill the block RAM available on a Spartan 6.
        -- chosen so as to fill the block RAM available on a Spartan 6.
        --
        --
        generic(addr_length: positive    := 12;
        generic (g: common_generics;
 
                addr_length: positive    := 12;
                data_length: positive    := 16;
                data_length: positive    := 16;
                file_name:   string      := "memory.bin";
                file_name:   string      := "memory.bin";
                file_type:   file_format := FILE_BINARY);
                file_type:   file_format := FILE_BINARY);
        port(
        port(
                --| Port A of dual port RAM
                --| Port A of dual port RAM
Line 1742... Line 2080...
architecture behav of dual_port_block_ram is
architecture behav of dual_port_block_ram is
        constant ram_size: positive := 2 ** addr_length;
        constant ram_size: positive := 2 ** addr_length;
 
 
        type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
        type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
 
 
        impure function initialize_ram(file_name: in string; file_type: in file_format) return ram_type is
        impure function initialize_ram(the_file_name: in string; the_file_type: in file_format) return ram_type is
                variable ram_data:   ram_type;
                variable ram_data:   ram_type;
                file     in_file:    text is in file_name;
                file     in_file:    text is in the_file_name;
                variable input_line: line;
                variable input_line: line;
                variable tmp:        bit_vector(data_length - 1 downto 0);
                variable tmp:        bit_vector(data_length - 1 downto 0);
                variable c:          character;
                variable c:          character;
                variable slv:        std_ulogic_vector(data_length - 1 downto 0);
                variable slv:        std_ulogic_vector(data_length - 1 downto 0);
        begin
        begin
                for i in 0 to ram_size - 1 loop
                for i in 0 to ram_size - 1 loop
                        if file_type = FILE_NONE then
                        if the_file_type = FILE_NONE then
                                ram_data(i):=(others => '0');
                                ram_data(i):=(others => '0');
                        elsif not endfile(in_file) then
                        elsif not endfile(in_file) then
                                readline(in_file,input_line);
                                readline(in_file,input_line);
                                if file_type = FILE_BINARY then
                                if the_file_type = FILE_BINARY then
                                        read(input_line, tmp);
                                        read(input_line, tmp);
                                        ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
                                        ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
                                elsif file_type = FILE_HEX then
                                elsif the_file_type = FILE_HEX then
                                        assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
                                        assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
                                        for j in 1 to (data_length/4) loop
                                        for j in 1 to (data_length/4) loop
                                                c:= input_line((data_length/4) - j + 1);
                                                c:= input_line((data_length/4) - j + 1);
                                                slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector(c);
                                                slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector_tb(c);
                                        end loop;
                                        end loop;
                                        ram_data(i) := slv;
                                        ram_data(i) := slv;
                                else
                                else
                                        report "Incorrect file type given: " & file_format'image(file_type) severity failure;
                                        report "Incorrect file type given: " & file_format'image(the_file_type) severity failure;
                                end if;
                                end if;
                        else
                        else
                                ram_data(i) := (others => '0');
                                ram_data(i) := (others => '0');
                        end if;
                        end if;
                end loop;
                end loop;
Line 1786... Line 2124...
                if rising_edge(a_clk) then
                if rising_edge(a_clk) then
                        if a_dwe = '1' then
                        if a_dwe = '1' then
                                ram(to_integer(unsigned(a_addr))) := a_din;
                                ram(to_integer(unsigned(a_addr))) := a_din;
                        end if;
                        end if;
                        if a_dre = '1' then
                        if a_dre = '1' then
                                a_dout <= ram(to_integer(unsigned(a_addr)));
                                a_dout <= ram(to_integer(unsigned(a_addr))) after g.delay;
                        else
                        else
                                a_dout <= (others => '0');
                                a_dout <= (others => '0') after g.delay;
                        end if;
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        b_ram: process(b_clk)
        b_ram: process(b_clk)
Line 1800... Line 2138...
                if rising_edge(b_clk) then
                if rising_edge(b_clk) then
                        if b_dwe = '1' then
                        if b_dwe = '1' then
                                ram(to_integer(unsigned(b_addr))) := b_din;
                                ram(to_integer(unsigned(b_addr))) := b_din;
                        end if;
                        end if;
                        if b_dre = '1' then
                        if b_dre = '1' then
                                b_dout <= ram(to_integer(unsigned(b_addr)));
                                b_dout <= ram(to_integer(unsigned(b_addr))) after g.delay;
                        else
                        else
                                b_dout <= (others => '0');
                                b_dout <= (others => '0') after g.delay;
                        end if;
                        end if;
                end if;
                end if;
        end process;
        end process;
end architecture;
end architecture;
 
 
--- Single Port Model ---
--- Single Port Model ---
 
 
library ieee;
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.textio.all;
use work.util.all;
use work.util.all;
 
 
entity single_port_block_ram is
entity single_port_block_ram is
        generic(addr_length: positive    := 12;
        generic (g: common_generics;
 
                addr_length: positive    := 12;
                data_length: positive    := 16;
                data_length: positive    := 16;
                file_name:   string      := "memory.bin";
                file_name:   string      := "memory.bin";
                file_type:   file_format := FILE_BINARY);
                file_type:   file_format := FILE_BINARY);
        port(
        port(
                clk:  in  std_ulogic;
                clk:  in  std_ulogic;
Line 1835... Line 2174...
architecture behav of single_port_block_ram is
architecture behav of single_port_block_ram is
        constant ram_size: positive := 2 ** addr_length;
        constant ram_size: positive := 2 ** addr_length;
 
 
        type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
        type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
 
 
        impure function initialize_ram(file_name: in string; file_type: in file_format) return ram_type is
        impure function initialize_ram(the_file_name: in string; the_file_type: in file_format) return ram_type is
                variable ram_data:   ram_type;
                variable ram_data:   ram_type;
                file     in_file:    text is in file_name;
                file     in_file:    text is in the_file_name;
                variable input_line: line;
                variable input_line: line;
                variable tmp:        bit_vector(data_length - 1 downto 0);
                variable tmp:        bit_vector(data_length - 1 downto 0);
                variable c:          character;
                variable c:          character;
                variable slv:        std_ulogic_vector(data_length - 1 downto 0);
                variable slv:        std_ulogic_vector(data_length - 1 downto 0);
        begin
        begin
                for i in 0 to ram_size - 1 loop
                for i in 0 to ram_size - 1 loop
                        if file_type = FILE_NONE then
                        if the_file_type = FILE_NONE then
                                ram_data(i):=(others => '0');
                                ram_data(i):=(others => '0');
                        elsif not endfile(in_file) then
                        elsif not endfile(in_file) then
                                readline(in_file,input_line);
                                readline(in_file,input_line);
                                if file_type = FILE_BINARY then
                                if the_file_type = FILE_BINARY then
                                        read(input_line, tmp);
                                        read(input_line, tmp);
                                        ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
                                        ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
                                elsif file_type = FILE_HEX then -- hexadecimal
                                elsif the_file_type = FILE_HEX then -- hexadecimal
                                        assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
                                        assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
                                        for j in 1 to (data_length/4) loop
                                        for j in 1 to (data_length/4) loop
                                                c:= input_line((data_length/4) - j + 1);
                                                c:= input_line((data_length/4) - j + 1);
                                                slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector(c);
                                                slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector_tb(c);
                                        end loop;
                                        end loop;
                                        ram_data(i) := slv;
                                        ram_data(i) := slv;
                                else
                                else
                                        report "Incorrect file type given: " & file_format'image(file_type) severity failure;
                                        report "Incorrect file type given: " & file_format'image(the_file_type) severity failure;
                                end if;
                                end if;
                        else
                        else
                                ram_data(i) := (others => '0');
                                ram_data(i) := (others => '0');
                        end if;
                        end if;
                end loop;
                end loop;
                file_close(in_file);
                file_close(in_file);
                return ram_data;
                return ram_data;
        end function;
        end function;
 
 
        shared variable ram: ram_type := initialize_ram(file_name, file_type);
        shared variable ram: ram_type := initialize_ram(file_name, file_type);
 
 
begin
begin
        block_ram: process(clk)
        block_ram: process(clk)
        begin
        begin
                if rising_edge(clk) then
                if rising_edge(clk) then
                        if dwe = '1' then
                        if dwe = '1' then
                                ram(to_integer(unsigned(addr))) := din;
                                ram(to_integer(unsigned(addr))) := din;
                        end if;
                        end if;
 
 
                        if dre = '1' then
                        if dre = '1' then
                                dout <= ram(to_integer(unsigned(addr)));
                                dout <= ram(to_integer(unsigned(addr))) after g.delay;
                        else
                        else
                                dout <= (others => '0');
                                dout <= (others => '0') after g.delay;
                        end if;
                        end if;
                end if;
                end if;
        end process;
        end process;
end architecture;
end architecture;
 
 
------------------------- Single and Dual Port Block RAM ----------------------------
------------------------- Single and Dual Port Block RAM ----------------------------
 
 
------------------------- Data Source -----------------------------------------------
------------------------- Data Source -----------------------------------------------
--|
--|
--| This module spits out a bunch of data
--| This module spits out a bunch of data.
--|
 
--| @todo Create a single module that can be used to capture and replay data at
 
--| a configurable rate. This could be used as a logger or as a waveform
 
--| generator. Depending on the generics used this should synthesize to either
 
--| logger, or a data source, or both. A pre-divider could also be supplied as
 
--| generic options, to lower the clock rate.
 
--|
--|
 
 
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use work.util.single_port_block_ram;
use work.util.single_port_block_ram;
use work.util.counter;
use work.util.counter;
use work.util.all;
use work.util.all;
 
 
entity data_source is
entity data_source is
        generic(addr_length: positive    := 12;
        generic (g: common_generics;
 
                addr_length: positive    := 12;
                data_length: positive    := 16;
                data_length: positive    := 16;
                file_name:   string      := "memory.bin";
                file_name:   string      := "memory.bin";
                file_type:   file_format := FILE_BINARY);
                file_type:   file_format := FILE_BINARY);
        port(
        port(
                clk:     in  std_ulogic;
                clk:     in  std_ulogic;
Line 1929... Line 2264...
 
 
architecture structural of data_source is
architecture structural of data_source is
        signal addr: std_ulogic_vector(addr_length - 1 downto 0);
        signal addr: std_ulogic_vector(addr_length - 1 downto 0);
begin
begin
        count: work.util.counter
        count: work.util.counter
                generic map(
                generic map (g => g, N => addr_length)
                        N => addr_length)
 
                port map(
                port map(
                        clk      =>  clk,
                        clk      =>  clk,
                        rst      =>  rst,
                        rst      =>  rst,
                        ce       =>  ce,
                        ce       =>  ce,
                        cr       =>  cr,
                        cr       =>  cr,
Line 1942... Line 2276...
                        load_i   =>  load,
                        load_i   =>  load,
                        load_we  =>  load_we);
                        load_we  =>  load_we);
 
 
        ram: work.util.single_port_block_ram
        ram: work.util.single_port_block_ram
                generic map(
                generic map(
 
                        g           => g,
                        addr_length => addr_length,
                        addr_length => addr_length,
                        data_length => data_length,
                        data_length => data_length,
                        file_name   => file_name,
                        file_name   => file_name,
                        file_type   => file_type)
                        file_type   => file_type)
                port map(
                port map(
Line 1979... Line 2314...
-- instructions could be customized based upon what. Another interesting
-- instructions could be customized based upon what. Another interesting
-- possibility is making a simple assembler purely in VHDL, which should
-- possibility is making a simple assembler purely in VHDL, which should
-- be possible, but difficult. A single port version would require another
-- be possible, but difficult. A single port version would require another
-- state to fetch the operand and another register, or more states.
-- state to fetch the operand and another register, or more states.
--
--
-- @todo Test in hardware, document, make assembler, and a project that
-- I have another small, bit serial CPU, available at:
-- just contains an instantiation of this core.
--   <https://github.com/howerj/bit-serial>
 
-- Which is also tiny, but potentially much more useful. It is currently in
 
-- a state of flux though.
--
--
 
 
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
 
entity ucpu is
entity ucpu is
        generic(width: positive range 8 to 32 := 8);
        generic (
 
                asynchronous_reset:  boolean := true;  -- use asynchronous reset if true, synchronous if false
 
                delay:               time    := 0 ns; -- simulation only
 
 
 
                width:               positive range 8 to 32 := 8);
        port(
        port(
                clk, rst: in  std_ulogic;
                clk, rst: in  std_ulogic;
 
 
                pc:       out std_ulogic_vector(width - 3 downto 0);
                pc:       out std_ulogic_vector(width - 3 downto 0);
                op:       in  std_ulogic_vector(width - 1 downto 0);
                op:       in  std_ulogic_vector(width - 1 downto 0);
Line 2007... Line 2348...
        signal a_c,   a_n:       unsigned(di'high + 1 downto di'low) := (others => '0'); -- accumulator
        signal a_c,   a_n:       unsigned(di'high + 1 downto di'low) := (others => '0'); -- accumulator
        signal pc_c,  pc_n:      unsigned(pc'range)                  := (others => '0');
        signal pc_c,  pc_n:      unsigned(pc'range)                  := (others => '0');
        signal alu:              std_ulogic_vector(1 downto 0)        := (others => '0');
        signal alu:              std_ulogic_vector(1 downto 0)        := (others => '0');
        signal state_c, state_n: std_ulogic                           := '0'; -- FETCH/Single cycle instruction or EXECUTE
        signal state_c, state_n: std_ulogic                           := '0'; -- FETCH/Single cycle instruction or EXECUTE
begin
begin
        pc          <= std_ulogic_vector(pc_n);
        pc          <= std_ulogic_vector(pc_n) after delay;
        do          <= std_ulogic_vector(a_c(do'range));
        do          <= std_ulogic_vector(a_c(do'range)) after delay;
        alu         <= op(op'high downto op'high - 1);
        alu         <= op(op'high downto op'high - 1) after delay;
        adr         <= op(adr'range);
        adr         <= op(adr'range) after delay;
        we          <= '1' when alu = "10" else '0'; -- STORE
        we          <= '1' when alu = "10" else '0' after delay; -- STORE
        re          <= alu(1) nor state_c;           -- FETCH for ADD and NOR
        re          <= alu(1) nor state_c after delay;           -- FETCH for ADD and NOR
        state_n     <= alu(1) nor state_c;           -- FETCH not taken or FETCH done
        state_n     <= alu(1) nor state_c after delay;           -- FETCH not taken or FETCH done
        pc_n        <= unsigned(op(pc_n'range)) when (alu = "11"    and a_c(a_c'high) = '0') else -- Jump when carry set
        pc_n        <= unsigned(op(pc_n'range)) when (alu = "11"    and a_c(a_c'high) = '0') else -- Jump when carry set
                        pc_c                    when (state_c = '0' and alu(1) = '0')        else -- FETCH
                        pc_c                    when (state_c = '0' and alu(1) = '0')        else -- FETCH
                        pc_c + 1; -- EXECUTE
                        (pc_c + 1) after delay; -- EXECUTE
 
 
        process(clk, rst)
        process(clk, rst)
        begin
        begin
                if rst = '1' then
                if rst = '1' and asynchronous_reset then
                        a_c     <= (others => '0');
                        a_c     <= (others => '0') after delay;
                        pc_c    <= (others => '0');
                        pc_c    <= (others => '0') after delay;
                        state_c <= '0';
                        state_c <= '0' after delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        a_c     <= a_n;
                        if rst = '1' and not asynchronous_reset then
                        pc_c    <= pc_n;
                                a_c     <= (others => '0') after delay;
                        state_c <= state_n;
                                pc_c    <= (others => '0') after delay;
 
                                state_c <= '0' after delay;
 
                        else
 
                                a_c     <= a_n after delay;
 
                                pc_c    <= pc_n after delay;
 
                                state_c <= state_n after delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        process(op, alu, di, a_c, state_c)
        process(op, alu, di, a_c, state_c)
        begin
        begin
                a_n     <= a_c;
                a_n     <= a_c after delay;
 
 
                if alu = "11" and a_c(a_c'high) = '0' then a_n(a_n'high) <= '0'; end if;
                if alu = "11" and a_c(a_c'high) = '0' then a_n(a_n'high) <= '0' after delay; end if;
 
 
                if state_c = '1' then -- EXECUTE for ADD and NOR
                if state_c = '1' then -- EXECUTE for ADD and NOR
                        assert alu(1) = '0' severity failure;
                        assert alu(1) = '0' severity failure;
                        if alu(0) = '0' then a_n <= '0' & a_c(di'range) + unsigned('0' & di); end if;
                        if alu(0) = '0' then a_n <= '0' & a_c(di'range) + unsigned('0' & di) after delay; end if;
                        if alu(0) = '1' then a_n <= a_c nor '0' & unsigned(di); end if;
                        if alu(0) = '1' then a_n <= a_c nor '0' & unsigned(di) after delay; end if;
                end if;
                end if;
        end process;
        end process;
end architecture;
end architecture;
 
 
library ieee,work;
library ieee,work;
Line 2052... Line 2399...
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use ieee.math_real.all;
use work.util.all;
use work.util.all;
 
 
entity ucpu_tb is
entity ucpu_tb is
        generic(
        generic (g: common_generics;
                clock_frequency: positive;
 
                file_name: string := "ucpu.bin");
                file_name: string := "ucpu.bin");
end entity;
end entity;
 
 
architecture testing of ucpu_tb is
architecture testing of ucpu_tb is
        constant clk_period:      time     := 1000 ms / clock_frequency;
        constant clock_period:      time     := 1000 ms / g.clock_frequency;
 
 
        constant data_length: positive := 8;
        constant data_length: positive := 8;
        constant addr_length: positive := data_length - 2;
        constant addr_length: positive := data_length - 2;
 
 
        signal a_addr: std_ulogic_vector(addr_length - 1 downto 0);
        signal a_addr: std_ulogic_vector(addr_length - 1 downto 0);
Line 2076... Line 2422...
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop:     std_ulogic := '0';
        signal stop:     std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        bram_0: entity work.dual_port_block_ram
        bram_0: entity work.dual_port_block_ram
        generic map(
        generic map (g => g,
                addr_length => addr_length,
                addr_length => addr_length,
                data_length => data_length,
                data_length => data_length,
                file_name   => file_name,
                file_name   => file_name,
                file_type   => FILE_BINARY)
                file_type   => FILE_BINARY)
        port map(
        port map(
Line 2101... Line 2447...
                b_addr  =>  b_addr,
                b_addr  =>  b_addr,
                b_din   =>  b_din,
                b_din   =>  b_din,
                b_dout  =>  b_dout);
                b_dout  =>  b_dout);
 
 
        ucpu_0: entity work.ucpu
        ucpu_0: entity work.ucpu
        generic map(width => data_length)
        generic map (delay => g.delay, width => data_length)
        port map(
        port map(
                clk => clk,
                clk => clk,
                rst => rst,
                rst => rst,
                pc  => a_addr,
                pc  => a_addr,
                op  => a_dout,
                op  => a_dout,
Line 2116... Line 2462...
                do  => b_din,
                do  => b_din,
                adr => b_addr);
                adr => b_addr);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                wait for clk_period * 1000;
                wait for clock_period * 1000;
                stop <= '1';
                stop <= '1';
                wait;
                wait;
        end process;
        end process;
 
 
end architecture;
end architecture;
 
 
------------------------- uCPU ------------------------------------------------------
------------------------- uCPU ------------------------------------------------------
 
 
------------------------- Restoring Division ----------------------------------------
------------------------- Restoring Division ----------------------------------------
-- @todo Add remainder to output, rename signals, make a
 
-- better test bench, add non-restoring division, and describe module
 
--
--
-- Computes a/b in N cycles
-- Computes a/b in N cycles
--
--
-- https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
-- https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
--
--
--
 
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity restoring_divider is
entity restoring_divider is
        generic(N: positive);
        generic (g: common_generics; N: positive);
        port(
        port(
                clk:   in  std_ulogic;
                clk:   in  std_ulogic;
                rst:   in  std_ulogic := '0';
                rst:   in  std_ulogic := '0';
 
 
                a:     in  unsigned(N - 1 downto 0);
                a:     in  std_ulogic_vector(N - 1 downto 0);
                b:     in  unsigned(N - 1 downto 0);
                b:     in  std_ulogic_vector(N - 1 downto 0);
                start: in  std_ulogic;
                start: in  std_ulogic;
                done:  out std_ulogic;
                done:  out std_ulogic;
                c:     out unsigned(N - 1 downto 0));
                c:     out std_ulogic_vector(N - 1 downto 0));
end entity;
end entity;
 
 
architecture rtl of restoring_divider is
architecture rtl of restoring_divider is
        signal a_c, a_n: unsigned(a'range) := (others => '0');
        signal a_c, a_n: unsigned(a'range) := (others => '0');
        signal b_c, b_n: unsigned(b'range) := (others => '0');
        signal b_c, b_n: unsigned(b'range) := (others => '0');
        signal m_c, m_n: unsigned(b'range) := (others => '0');
        signal m_c, m_n: unsigned(b'range) := (others => '0');
        signal o_c, o_n: unsigned(c'range) := (others => '0');
        signal o_c, o_n: unsigned(c'range) := (others => '0');
        signal e_c, e_n: std_ulogic         := '0';
        signal e_c, e_n: std_ulogic         := '0';
        signal count_c, count_n: unsigned(work.util.n_bits(N) downto 0) := (others => '0');
        signal count_c, count_n: unsigned(work.util.n_bits(N) downto 0) := (others => '0');
begin
begin
        c <= o_n;
        c <= std_ulogic_vector(o_n);
 
 
        process(clk, rst)
        process(clk, rst)
 
                procedure reset is
 
                begin
 
                        a_c      <=  (others  =>  '0') after g.delay;
 
                        b_c      <=  (others  =>  '0') after g.delay;
 
                        m_c      <=  (others  =>  '0') after g.delay;
 
                        o_c      <=  (others  =>  '0') after g.delay;
 
                        e_c      <=  '0' after g.delay;
 
                        count_c  <=  (others  =>  '0') after g.delay;
 
                end procedure;
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        a_c      <=  (others  =>  '0');
                        reset;
                        b_c      <=  (others  =>  '0');
 
                        m_c      <=  (others  =>  '0');
 
                        o_c      <=  (others  =>  '0');
 
                        e_c      <=  '0';
 
                        count_c  <=  (others  =>  '0');
 
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        a_c      <=  a_n;
                        if rst = '1' and not g.asynchronous_reset then
                        b_c      <=  b_n;
                                reset;
                        m_c      <=  m_n;
                        else
                        o_c      <=  o_n;
                                a_c      <=  a_n after g.delay;
                        e_c      <=  e_n;
                                b_c      <=  b_n after g.delay;
                        count_c  <=  count_n;
                                m_c      <=  m_n after g.delay;
 
                                o_c      <=  o_n after g.delay;
 
                                e_c      <=  e_n after g.delay;
 
                                count_c  <=  count_n after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        divide: process(a, b, start, a_c, b_c, m_c, e_c, o_c, count_c)
        divide: process(a, b, start, a_c, b_c, m_c, e_c, o_c, count_c)
                variable m_v: unsigned(b'range) := (others => '0');
                variable m_v: unsigned(b'range) := (others => '0');
Line 2191... Line 2544...
                m_v      :=  m_c;
                m_v      :=  m_c;
                e_n      <=  e_c;
                e_n      <=  e_c;
                o_n      <=  o_c;
                o_n      <=  o_c;
                count_n  <=  count_c;
                count_n  <=  count_c;
                if start = '1' then
                if start = '1' then
                        a_n   <= a;
                        a_n   <= unsigned(a) after g.delay;
                        b_n   <= b;
                        b_n   <= unsigned(b) after g.delay;
                        m_v   := (others => '0');
                        m_v   := (others => '0');
                        e_n   <= '1';
                        e_n   <= '1' after g.delay;
                        o_n   <= (others => '0');
                        o_n   <= (others => '0') after g.delay;
                        count_n <= (others => '0');
                        count_n <= (others => '0') after g.delay;
                elsif e_c = '1' then
                elsif e_c = '1' then
                        if count_c(count_c'high) = '1' then
                        if count_c(count_c'high) = '1' then
                                done  <= '1';
                                done  <= '1' after g.delay;
                                e_n   <= '0';
                                e_n   <= '0' after g.delay;
                                o_n   <= a_c;
                                o_n   <= a_c after g.delay;
                                count_n <= (others => '0');
                                count_n <= (others => '0') after g.delay;
                        else
                        else
                                m_v(b'high downto 1) := m_v(b'high - 1 downto 0);
                                m_v(b'high downto 1) := m_v(b'high - 1 downto 0);
                                m_v(0) := a_c(a'high);
                                m_v(0) := a_c(a'high);
                                a_n(a'high downto 1) <= a_c(a'high - 1 downto 0);
                                a_n(a'high downto 1) <= a_c(a'high - 1 downto 0) after g.delay;
                                m_v := m_v - b_c;
                                m_v := m_v - b_c;
                                if m_v(m_v'high) = '1' then
                                if m_v(m_v'high) = '1' then
                                        m_v := m_v + b_c;
                                        m_v := m_v + b_c;
                                        a_n(0) <= '0';
                                        a_n(0) <= '0' after g.delay;
                                else
                                else
                                        a_n(0) <= '1';
                                        a_n(0) <= '1' after g.delay;
                                end if;
                                end if;
                                count_n <= count_c + 1;
                                count_n <= count_c + 1 after g.delay;
                        end if;
                        end if;
                else
                else
                        count_n <= (others => '0');
                        count_n <= (others => '0') after g.delay;
                end if;
                end if;
                m_n <= m_v;
                m_n <= m_v after g.delay;
        end process;
        end process;
end architecture;
end architecture;
 
 
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use ieee.math_real.all;
 
use work.util.common_generics;
 
 
entity restoring_divider_tb is
entity restoring_divider_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture testing of restoring_divider_tb is
architecture testing of restoring_divider_tb is
        constant clk_period: time     := 1000 ms / clock_frequency;
        constant clock_period: time     := 1000 ms / g.clock_frequency;
        constant N:          positive := 8;
        constant N:          positive := 8;
 
 
        signal a: unsigned(N - 1 downto 0) := (others => '0');
        signal a: std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal b: unsigned(N - 1 downto 0) := (others => '0');
        signal b: std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal c: unsigned(N - 1 downto 0) := (others => '0');
        signal c: std_ulogic_vector(N - 1 downto 0) := (others => '0');
        signal start, done: std_ulogic := '0';
        signal start, done: std_ulogic := '0';
 
 
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop:     std_ulogic := '0';
        signal stop:     std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: entity work.restoring_divider
        uut: entity work.restoring_divider
                generic map(N => N)
                generic map (g => g, N => N)
                port map(
                port map(
                        clk   => clk,
                        clk   => clk,
                        rst   => rst,
                        rst   => rst,
                        a     => a,
                        a     => a,
                        b     => b,
                        b     => b,
Line 2261... Line 2615...
                        done  => done,
                        done  => done,
                        c     => c);
                        c     => c);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                wait for clk_period * 2;
                wait for clock_period * 2;
 
 
                a <= x"64";
                a <= x"64";
                b <= x"0A";
                b <= x"0A";
                start <= '1';
                start <= '1';
                wait for clk_period * 1;
                wait for clock_period * 1;
                start <= '0';
                start <= '0';
                wait until done = '1';
                wait until done = '1';
                --assert c = x"0A" severity failure;
                --assert c = x"0A" severity failure;
 
 
                wait for clk_period * 10;
                wait for clock_period * 10;
                b     <= x"05";
                b     <= x"05";
                start <= '1';
                start <= '1';
                wait for clk_period * 1;
                wait for clock_period * 1;
                start <= '0';
                start <= '0';
                wait until done = '1';
                wait until done = '1';
                --assert c = x"14" severity failure;
                --assert c = x"14" severity failure;
 
 
                stop <= '1';
                stop <= '1';
Line 2291... Line 2645...
------------------------- Debouncer -----------------------------------------------------------
------------------------- Debouncer -----------------------------------------------------------
 
 
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity debounce_us is
entity debounce_us is
        generic(clock_frequency: positive; timer_period_us: natural);
        generic (g: common_generics; timer_period_us: natural);
        port(
        port(
                clk:   in  std_ulogic;
                clk:   in  std_ulogic;
                di:    in  std_ulogic;
                di:    in  std_ulogic;
                do:    out std_ulogic := '0');
                do:    out std_ulogic := '0');
end entity;
end entity;
Line 2305... Line 2660...
architecture rtl of debounce_us is
architecture rtl of debounce_us is
        signal ff: std_ulogic_vector(1 downto 0) := (others => '0');
        signal ff: std_ulogic_vector(1 downto 0) := (others => '0');
        signal rst, done: std_ulogic             := '0';
        signal rst, done: std_ulogic             := '0';
begin
begin
        timer: work.util.timer_us
        timer: work.util.timer_us
                generic map(
                generic map (g => g, timer_period_us => timer_period_us)
                        clock_frequency => clock_frequency,
 
                        timer_period_us => timer_period_us)
 
                port map(
                port map(
                        clk => clk,
                        clk => clk,
                        rst => rst,
                        rst => rst,
                        co  => done);
                        co  => done);
 
 
        process(clk)
        process(clk)
        begin
        begin
                if rising_edge(clk) then
                if rising_edge(clk) then
                        ff(0) <= di;
                        ff(0) <= di    after g.delay;
                        ff(1) <= ff(0);
                        ff(1) <= ff(0) after g.delay;
                        rst   <= '0';
 
                        if (ff(0) xor ff(1)) = '1' then
                        if (ff(0) xor ff(1)) = '1' then
                                rst <= '1';
                                rst <= '1' after g.delay;
                        elsif done = '1' then
                        elsif done = '1' then
                                do  <= ff(1);
                                do  <= ff(1) after g.delay;
 
                        else
 
                                rst   <= '0';
                        end if;
                        end if;
                end if;
                end if;
        end process;
        end process;
end architecture;
end architecture;
 
 
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity debounce_us_tb is
entity debounce_us_tb is
        generic(clock_frequency: positive);
        generic (g: common_generics);
end entity;
end entity;
 
 
architecture testing of debounce_us_tb is
architecture testing of debounce_us_tb is
        constant clk_period: time     := 1000 ms / clock_frequency;
        constant clock_period: time := 1000 ms / g.clock_frequency;
 
 
        signal di,  do:  std_ulogic := '0';
        signal di,  do:  std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal clk, rst: std_ulogic := '0';
        signal stop:     std_ulogic := '0';
        signal stop:     std_ulogic := '0';
begin
begin
        cs: entity work.clock_source_tb
        cs: entity work.clock_source_tb
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
                generic map (g => g, hold_rst => 2)
                port map(stop => stop, clk => clk, rst => rst);
                port map(stop => stop, clk => clk, rst => rst);
 
 
        uut: work.util.debounce_us
        uut: work.util.debounce_us
                generic map(clock_frequency => clock_frequency, timer_period_us => 1)
                generic map (g => g, timer_period_us => 1)
                port map(clk => clk, di => di, do => do);
                port map(clk => clk, di => di, do => do);
 
 
        stimulus_process: process
        stimulus_process: process
        begin
        begin
                wait for clk_period * 2;
                wait for clock_period * 2;
                di <= '1';
                di <= '1';
 
 
                wait for 1.5 us;
                wait for 1.5 us;
 
 
                stop <= '1';
                stop <= '1';
Line 2369... Line 2724...
------------------------- Debouncer Block -----------------------------------------------------
------------------------- Debouncer Block -----------------------------------------------------
 
 
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity debounce_block_us is
entity debounce_block_us is
        generic(N: positive; clock_frequency: positive; timer_period_us: natural);
        generic (g: common_generics; N: positive; timer_period_us: natural);
        port(
        port(
                clk:   in  std_ulogic;
                clk:   in  std_ulogic;
                di:    in  std_ulogic_vector(N - 1 downto 0);
                di:    in  std_ulogic_vector(N - 1 downto 0);
                do:    out std_ulogic_vector(N - 1 downto 0));
                do:    out std_ulogic_vector(N - 1 downto 0));
end entity;
end entity;
 
 
architecture structural of debounce_block_us is
architecture structural of debounce_block_us is
begin
begin
        debouncer: for i in N - 1 downto 0 generate
        debouncer: for i in (N - 1) downto 0 generate
                d_instance: work.util.debounce_us
                d_instance: work.util.debounce_us
                        generic map(
                        generic map (g => g, timer_period_us => timer_period_us)
                                clock_frequency => clock_frequency,
 
                                timer_period_us => timer_period_us)
 
                        port map(clk => clk, di => di(i), do => do(i));
                        port map(clk => clk, di => di(i), do => do(i));
        end generate;
        end generate;
end architecture;
end architecture;
 
 
------------------------- Debouncer Block -----------------------------------------------------
------------------------- Debouncer Block -----------------------------------------------------
 
 
------------------------- State Changed -------------------------------------------------------
------------------------- State Changed -------------------------------------------------------
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity state_changed is
entity state_changed is
 
        generic (g: common_generics);
        port(
        port(
                clk: in  std_ulogic;
                clk: in  std_ulogic;
                rst: in  std_ulogic;
                rst: in  std_ulogic;
                di:  in  std_ulogic;
                di:  in  std_ulogic;
                do:  out std_ulogic);
                do:  out std_ulogic);
Line 2409... Line 2765...
architecture rtl of state_changed is
architecture rtl of state_changed is
        signal state_c, state_n: std_ulogic_vector(1 downto 0) := (others => '0');
        signal state_c, state_n: std_ulogic_vector(1 downto 0) := (others => '0');
begin
begin
        process(clk, rst)
        process(clk, rst)
        begin
        begin
                if rst = '1' then
                if rst = '1' and g.asynchronous_reset then
                        state_c <= (others => '0');
                        state_c <= (others => '0') after g.delay;
                elsif rising_edge(clk) then
                elsif rising_edge(clk) then
                        state_c <= state_n;
                        if rst = '1' and not g.asynchronous_reset then
 
                                state_c <= (others => '0') after g.delay;
 
                        else
 
                                state_c <= state_n after g.delay;
 
                        end if;
                end if;
                end if;
        end process;
        end process;
 
 
        do <= '1' when (state_c(0) xor state_c(1)) = '1' else '0';
        do <= '1' when (state_c(0) xor state_c(1)) = '1' else '0';
 
 
        process(di, state_c)
        process(di, state_c)
        begin
        begin
                state_n(0) <= state_c(1);
                state_n(0) <= state_c(1) after g.delay;
                state_n(1) <= di;
                state_n(1) <= di after g.delay;
        end process;
        end process;
end architecture;
end architecture;
 
 
------------------------- Change State --------------------------------------------------------
------------------------- Change State --------------------------------------------------------
 
 
------------------------- Change State Block --------------------------------------------------
------------------------- Change State Block --------------------------------------------------
library ieee,work;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
 
use work.util.common_generics;
 
 
entity state_block_changed is
entity state_block_changed is
        generic(N: positive);
        generic (g: common_generics; N: positive);
        port(
        port(
                clk: in  std_ulogic;
                clk: in  std_ulogic;
                rst: in  std_ulogic;
                rst: in  std_ulogic;
                di:  in  std_ulogic_vector(N - 1 downto 0);
                di:  in  std_ulogic_vector(N - 1 downto 0);
                do:  out std_ulogic_vector(N - 1 downto 0));
                do:  out std_ulogic_vector(N - 1 downto 0));
end entity;
end entity;
 
 
architecture structural of state_block_changed is
architecture structural of state_block_changed is
begin
begin
        changes: for i in N - 1 downto 0 generate
        changes: for i in (N - 1) downto 0 generate
                d_instance: work.util.state_changed
                d_instance: work.util.state_changed
 
                        generic map (g => g)
                        port map(clk => clk, rst => rst, di => di(i), do => do(i));
                        port map(clk => clk, rst => rst, di => di(i), do => do(i));
        end generate;
        end generate;
end architecture;
end architecture;
 
 
------------------------- Change State Block --------------------------------------------------
------------------------- Change State Block --------------------------------------------------
 
 
 No newline at end of file
 No newline at end of file
 
------------------------- Reset Signal Generator ----------------------------------------------
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity reset_generator is
 
        generic (g: common_generics; reset_period_us:  natural := 0);
 
        port (
 
                clk: in  std_logic := 'X';
 
                rst: out std_logic := '0'); -- reset out!
 
end entity;
 
 
 
architecture behavior of reset_generator is
 
        constant cycles:  natural := (g.clock_frequency / 1000000) * reset_period_us;
 
        subtype  counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
 
        signal   c_c, c_n: counter := (others => '0');
 
begin
 
        process (clk)
 
        begin
 
                if rising_edge(clk) then
 
                        c_c <= c_n after g.delay;
 
                end if;
 
        end process;
 
 
 
        process (c_c)
 
        begin
 
                if c_c = (cycles - 1) then
 
                        c_n <= c_c after g.delay;
 
                        rst <= '0' after g.delay;
 
                else
 
                        c_n <= c_c + 1 after g.delay;
 
                        rst <= '1' after g.delay;
 
                end if;
 
        end process;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.common_generics;
 
 
 
entity reset_generator_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of reset_generator_tb is
 
        constant clock_period:      time     := 1000 ms / g.clock_frequency;
 
        signal stop, clk, rst: std_ulogic := '0';
 
begin
 
        cs: entity work.clock_source_tb
 
                generic map (g => g, hold_rst => 2)
 
                port map (stop => stop, clk => clk, rst => open);
 
 
 
        uut: entity work.reset_generator
 
                generic map (g => g, reset_period_us => 1)
 
                port map (clk => clk, rst => rst);
 
 
 
        stimulus_process: process
 
        begin
 
                wait for clock_period;
 
                assert rst = '1' severity failure;
 
                wait for 1 us;
 
                assert rst = '0' severity failure;
 
                stop <= '1';
 
                wait;
 
        end process;
 
 
 
end architecture;
 
 
 
------------------------- Reset Signal Generator ----------------------------------------------
 
 
 
------------------------- Bit Count -----------------------------------------------------------
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.n_bits;
 
use work.util.common_generics;
 
 
 
entity bit_count is
 
        generic (g: common_generics; N: positive);
 
        port (
 
                bits:   in std_ulogic_vector(N - 1 downto 0);
 
                count: out std_ulogic_vector(n_bits(N) downto 0));
 
end entity;
 
 
 
architecture behavior of bit_count is
 
begin
 
        process (bits)
 
                constant zero: unsigned(count'high - 1 downto count'low)  := (others => '0');
 
                variable t: unsigned(count'range) := (others => '0');
 
        begin
 
                t := (others => '0');
 
                for i in bits'low to bits'high loop
 
                        t := t + (zero & bits(i));
 
                end loop;
 
                count <= std_ulogic_vector(t) after g.delay;
 
        end process;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.n_bits;
 
use work.util.common_generics;
 
 
 
entity bit_count_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of bit_count_tb is
 
        constant clock_period: time     := 1000 ms / g.clock_frequency;
 
        constant N:            positive := 3;
 
        signal bits:  std_ulogic_vector(N - 1 downto 0)     := (others => '0');
 
        signal count: std_ulogic_vector(n_bits(N) downto 0) := (others => '0');
 
begin
 
        uut: entity work.bit_count
 
                generic map (g => g, N => N)
 
                port map (bits => bits, count => count);
 
 
 
        stimulus_process: process
 
                procedure test(b: std_ulogic_vector; c: std_ulogic_vector)  is
 
                begin
 
                        bits <= b;
 
                        wait for clock_period;
 
                        assert count = c severity failure;
 
                end procedure;
 
        begin
 
                test("000", "000");
 
                test("001", "001");
 
                test("010", "001");
 
                test("011", "010");
 
                test("100", "001");
 
                test("101", "010");
 
                test("110", "010");
 
                test("111", "011");
 
                wait;
 
        end process;
 
 
 
end architecture;
 
 
 
------------------------- Bit Count -----------------------------------------------------------
 
 
 
------------------------- Majority Voter ------------------------------------------------------
 
--
 
-- NB. This could be constructed from a more generic 'assert output if bit
 
-- count greater than N' module.
 
--
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity majority is
 
        generic (g: common_generics; N: positive; even_wins: boolean := false);
 
        port (
 
                bits: in std_ulogic_vector(N - 1 downto 0);
 
                vote: out std_ulogic;
 
                tie:  out std_ulogic);
 
end entity;
 
 
 
architecture behavior of majority is
 
        signal count: std_ulogic_vector(n_bits(N) downto 0) := (others => '0');
 
        -- It might be worth handling up to five or so bits in combinatorial
 
        -- logic, or it might not.
 
begin
 
        majority_1: if N = 1 generate
 
                vote <= bits(0) after g.delay;
 
                tie  <= '0' after g.delay;
 
        end generate;
 
 
 
        majority_2: if N = 2 generate
 
                ew_2:  if     even_wins generate vote <= bits(0)  or bits(1) after g.delay; end generate;
 
                enw_2: if not even_wins generate vote <= bits(0) and bits(1) after g.delay; end generate;
 
                tie  <= bits(0) or bits(1);
 
        end generate;
 
 
 
        majority_3: if N = 3 generate
 
                vote <= (bits(0) and bits(1)) or (bits(1) and bits(2)) or (bits(0) and bits(2)) after g.delay;
 
                tie  <= '0' after g.delay;
 
        end generate;
 
 
 
        majority_n: if N > 3 generate
 
                bit_counter: entity work.bit_count
 
                        generic map (g => g, N => N)
 
                        port map (bits => bits, count => count);
 
 
 
                tie <= '1' when (unsigned(count) = N/2) and (N mod 2) = 0 else '0' after g.delay;
 
 
 
                process (count)
 
                begin
 
                        if even_wins and (N mod 2) = 0 then
 
                                if unsigned(count) >= (N/2) then
 
                                        vote <= '1' after g.delay;
 
                                else
 
                                        vote <= '0' after g.delay;
 
                                end if;
 
                        else
 
                                if unsigned(count) > (N/2) then
 
                                        vote <= '1' after g.delay;
 
                                else
 
                                        vote <= '0' after g.delay;
 
                                end if;
 
                        end if;
 
                end process;
 
        end generate;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity majority_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of majority_tb is
 
        constant clock_period: time := 1000 ms / g.clock_frequency;
 
 
 
        constant N_3:    positive := 3;
 
        constant N_4_t:  positive := 4;
 
        constant N_4_m:  positive := 4;
 
 
 
        signal bits_3:   std_ulogic_vector(N_3   - 1 downto 0) := (others => '0');
 
        signal bits_4_t: std_ulogic_vector(N_4_t - 1 downto 0) := (others => '0');
 
        signal bits_4_m: std_ulogic_vector(N_4_m - 1 downto 0) := (others => '0');
 
 
 
        signal vote_3,     tie_3: std_ulogic := '0';
 
        signal vote_4_t, tie_4_t: std_ulogic := '0';
 
        signal vote_4_m, tie_4_m: std_ulogic := '0';
 
begin
 
        uut_3: entity work.majority
 
                generic map (g => g, N => N_3)
 
                port map (bits => bits_3, vote => vote_3, tie => tie_3);
 
 
 
        uut_4_t: entity work.majority
 
                generic map (g => g, N => N_4_t, even_wins => true)
 
                port map (bits => bits_4_t, vote => vote_4_t, tie => tie_4_t);
 
 
 
        uut_4_m: entity work.majority
 
                generic map (g => g, N => N_4_m)
 
                port map (bits => bits_4_m, vote => vote_4_m, tie => tie_4_m);
 
 
 
        stimulus_process: process
 
                procedure test_3(b: std_ulogic_vector; vote, tie: std_ulogic)  is
 
                begin
 
                        bits_3 <= b;
 
                        wait for clock_period;
 
                        assert vote_3 = vote and tie_3 = tie severity failure;
 
                end procedure;
 
 
 
                procedure test_4_t(b: std_ulogic_vector; vote, tie: std_ulogic)  is
 
                begin
 
                        bits_4_t <= b;
 
                        wait for clock_period;
 
                        assert vote_4_t = vote and tie_4_t = tie severity failure;
 
                end procedure;
 
 
 
                procedure test_4_m(b: std_ulogic_vector; vote, tie: std_ulogic)  is
 
                begin
 
                        bits_4_m <= b;
 
                        wait for clock_period;
 
                        assert vote_4_m = vote and tie_4_m = tie severity failure;
 
                end procedure;
 
        begin
 
                test_3("000", '0', '0');
 
                test_3("001", '0', '0');
 
                test_3("010", '0', '0');
 
                test_3("011", '1', '0');
 
                test_3("100", '0', '0');
 
                test_3("101", '1', '0');
 
                test_3("110", '1', '0');
 
                test_3("111", '1', '0');
 
 
 
                test_4_t("0000", '0', '0');
 
                test_4_t("0001", '0', '0');
 
                test_4_t("0010", '0', '0');
 
                test_4_t("0011", '1', '1');
 
                test_4_t("0100", '0', '0');
 
                test_4_t("0101", '1', '1');
 
                test_4_t("0110", '1', '1');
 
                test_4_t("0111", '1', '0');
 
                test_4_t("1000", '0', '0');
 
                test_4_t("1001", '1', '1');
 
                test_4_t("1010", '1', '1');
 
                test_4_t("1011", '1', '0');
 
                test_4_t("1100", '1', '1');
 
                test_4_t("1101", '1', '0');
 
                test_4_t("1110", '1', '0');
 
                test_4_t("1111", '1', '0');
 
 
 
                test_4_m("0000", '0', '0');
 
                test_4_m("0001", '0', '0');
 
                test_4_m("0010", '0', '0');
 
                test_4_m("0011", '0', '1');
 
                test_4_m("0100", '0', '0');
 
                test_4_m("0101", '0', '1');
 
                test_4_m("0110", '0', '1');
 
                test_4_m("0111", '1', '0');
 
                test_4_m("1000", '0', '0');
 
                test_4_m("1001", '0', '1');
 
                test_4_m("1010", '0', '1');
 
                test_4_m("1011", '1', '0');
 
                test_4_m("1100", '0', '1');
 
                test_4_m("1101", '1', '0');
 
                test_4_m("1110", '1', '0');
 
                test_4_m("1111", '1', '0');
 
 
 
                wait;
 
        end process;
 
end architecture;
 
 
 
------------------------- Majority Voter ------------------------------------------------------
 
 
 
------------------------- Delay Line ----------------------------------------------------------
 
-- 'DEPTH' * clock period delay line. Minimum delay of 0.
 
--
 
-- NB. It would be possible to create a delay line that would allow you to delay samples by
 
-- varying amounts with a FIFO and a counter, which is sort of line a Run
 
-- Length Compression Decoder. A sample and a counter would be pushed to the
 
-- FIFO, the delay line mechanism would pull a sample/counter and hold the value
 
-- for that amount of time.
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity delay_line is
 
        generic (g: common_generics; width: positive; depth: natural);
 
        port (
 
                clk:  in std_ulogic;
 
                rst:  in std_ulogic;
 
                ce:   in std_ulogic := '1';
 
                di:   in std_ulogic_vector(width - 1 downto 0);
 
                do:  out std_ulogic_vector(width - 1 downto 0));
 
end entity;
 
 
 
architecture behavior of delay_line is
 
        type delay_line_t is array(integer range 0 to depth) of std_ulogic_vector(di'range);
 
        signal sigs: delay_line_t := (others => (others => '0'));
 
begin
 
        sigs(0) <= di;
 
        delay_line_generate: for i in 0 to depth generate
 
                rest: if i > 0 generate
 
                        ux: work.util.reg
 
                                generic map (g => g, N => width)
 
                                port map (clk => clk, rst => rst, we => ce, di => sigs(i - 1), do => sigs(i));
 
                end generate;
 
        end generate;
 
        do <= sigs(depth);
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity delay_line_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of delay_line_tb is
 
        constant clock_period:  time     := 1000 ms / g.clock_frequency;
 
        constant depth:       natural    := 2;
 
        constant width:       positive   := 8;
 
        signal clk, rst:      std_ulogic := '0';
 
        signal stop:          std_ulogic := '0';
 
 
 
        signal di, do: std_ulogic_vector(width - 1 downto 0) := (others => '0');
 
begin
 
        cs: entity work.clock_source_tb
 
                generic map (g => g, hold_rst => 2)
 
                port map (stop => stop, clk => clk, rst => rst);
 
 
 
        uut: entity work.delay_line
 
        generic map (g => g, depth => depth, width => width) port map (clk => clk, rst => rst, di => di, do => do, ce => '1');
 
 
 
        stimulus_process: process
 
        begin
 
                -- put a bit into the shift register and wait
 
                -- for it to come out the other size
 
                wait until rst = '0';
 
                di <= x"AA";
 
                wait for clock_period * 1;
 
                di <= x"55";
 
                wait for clock_period * 1;
 
                di <= x"CC";
 
                wait for clock_period * 1;
 
                di <= x"DD";
 
                assert do = x"AA" severity failure;
 
                wait for clock_period * 1;
 
                di <= x"00";
 
                assert do = x"55" severity failure;
 
                wait for clock_period * 1;
 
                assert do = x"CC" severity failure;
 
                wait for clock_period * 1;
 
                assert do = x"DD" severity failure;
 
                wait for clock_period * 1;
 
                assert do = x"00" severity failure;
 
                stop <= '1';
 
                wait;
 
        end process;
 
end architecture;
 
 
 
------------------------- Delay Line ----------------------------------------------------------
 
 
 
------------------------- Gray CODEC ----------------------------------------------------------
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity gray_encoder is
 
        generic (g: common_generics; N: positive);
 
        port (di: in std_ulogic_vector(N - 1 downto 0);
 
             do: out std_ulogic_vector(N - 1 downto 0));
 
end entity;
 
 
 
architecture behavior of gray_encoder is
 
begin
 
        gry: for i in N - 1 downto 0 generate
 
                first: if i = (N - 1) generate
 
                        do(i) <= di(i);
 
                end generate;
 
 
 
                rest: if i < (N - 1) generate
 
                        do(i) <= di(i + 1) xor di(i);
 
                end generate;
 
        end generate;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity gray_decoder is
 
        generic (g: common_generics; N: positive);
 
        port (di: in std_ulogic_vector(N - 1 downto 0);
 
             do: out std_ulogic_vector(N - 1 downto 0));
 
end entity;
 
 
 
architecture behavior of gray_decoder is
 
begin
 
        gry: for i in N - 1 downto 0 generate
 
                first: if i = (N - 1) generate
 
                        do(i) <= di(i) after g.delay;
 
                end generate;
 
 
 
                rest: if i < (N - 1) generate
 
                        do(i) <= parity(di(N - 1 downto i), true) after g.delay;
 
                end generate;
 
        end generate;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity gray_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of gray_tb is
 
        constant clock_period:  time     := 1000 ms / g.clock_frequency;
 
        constant n:           positive   := 3;
 
        signal clk, rst:      std_ulogic := '0';
 
        signal stop:          std_ulogic := '0';
 
 
 
        signal di, gray, do: std_ulogic_vector(n - 1 downto 0) := (others => '0');
 
begin
 
        cs: entity work.clock_source_tb
 
                generic map (g => g, hold_rst => 2)
 
                port map (stop => stop, clk => clk, rst => rst);
 
 
 
        uut_encode: entity work.gray_encoder
 
        generic map (g => g, n => n) port map (di => di, do => gray);
 
 
 
        uut_decode: entity work.gray_decoder
 
        generic map (g => g, n => n) port map (di => gray, do => do);
 
 
 
        stimulus_process: process
 
                procedure test(slv: std_ulogic_vector) is
 
                begin
 
                        di <= slv;
 
                        wait for clock_period * 1;
 
                        assert di = do severity failure;
 
                        wait for clock_period * 1;
 
                end procedure;
 
        begin
 
                di <= (others => '0');
 
                wait until rst = '0';
 
                test("000");
 
                test("001");
 
                test("010");
 
                test("011");
 
                test("100");
 
                test("101");
 
                test("110");
 
                test("111");
 
                stop <= '1';
 
                wait;
 
        end process;
 
end architecture;
 
 
 
------------------------- Gray CODEC ----------------------------------------------------------
 
 
 
------------------------- Parity Module -------------------------------------------------------
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity parity_module is
 
        generic (g: common_generics; N: positive; even: boolean);
 
        port (di: in std_ulogic_vector(N - 1 downto 0); do: out std_ulogic);
 
end entity;
 
 
 
architecture behavior of parity_module is
 
begin
 
        do <= parity(di, even) after g.delay;
 
end architecture;
 
 
 
------------------------- Parity Module -------------------------------------------------------
 
 
 
------------------------- Hamming CODEC  ------------------------------------------------------
 
-- This is a Hamming encoder/decoder, with an extra parity bit. This can be used for error
 
-- correction and detection across a noisy line.
 
--
 
-- See <https://en.wikipedia.org/wiki/Hamming_code> for more information.
 
--
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity hamming_7_4_encoder is
 
        generic (g: common_generics);
 
        port (
 
                di:      in std_ulogic_vector(3 downto 0);
 
                do:     out std_ulogic_vector(6 downto 0);
 
                parity: out std_ulogic);
 
end entity;
 
 
 
architecture behavior of hamming_7_4_encoder is
 
        signal p1, p2, p3: std_ulogic := '0';
 
begin
 
        p1 <= di(0) xor di(1) xor di(3) after g.delay;
 
        p2 <= di(0) xor di(2) xor di(3) after g.delay;
 
        p3 <= di(1) xor di(2) xor di(3) after g.delay;
 
        do(0) <= p1    after g.delay;
 
        do(1) <= p2    after g.delay;
 
        do(2) <= di(0) after g.delay;
 
        do(3) <= p3    after g.delay;
 
        do(4) <= di(1) after g.delay;
 
        do(5) <= di(2) after g.delay;
 
        do(6) <= di(3) after g.delay;
 
        parity <= p1 xor p2 xor p3 xor di(0) xor di(1) xor di(2) xor di(3);
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity hamming_7_4_decoder is
 
        generic (g: common_generics; secdec: boolean := true);
 
        port (
 
                di:      in std_ulogic_vector(6 downto 0);
 
                parity:  in std_ulogic;
 
                do:     out std_ulogic_vector(3 downto 0);
 
                single, double: out std_ulogic);
 
end entity;
 
 
 
architecture behavior of hamming_7_4_decoder is
 
        signal s:  std_ulogic_vector(2 downto 0) := (others => '0');
 
        signal co, ct, dip: std_ulogic_vector(di'high + 1 downto 0)   := (others => '0');
 
        signal cp: std_ulogic := '0';
 
        signal unequal: std_ulogic := '0';
 
begin
 
        s(2) <= di(3) xor di(4) xor di(5) xor di(6) after g.delay;
 
        s(1) <= di(1) xor di(2) xor di(5) xor di(6) after g.delay;
 
        s(0) <= di(0) xor di(2) xor di(4) xor di(6) after g.delay;
 
 
 
        do(0) <= co(2) after g.delay;
 
        do(1) <= co(4) after g.delay;
 
        do(2) <= co(5) after g.delay;
 
        do(3) <= co(6) after g.delay;
 
 
 
        cp <= '0' when not secdec else di(0) xor di(1) xor di(2) xor di(3) xor di(4) xor di(5) xor di(6) after g.delay;
 
 
 
        dip(dip'high) <= parity when secdec else '0' after g.delay;
 
        dip(di'range) <= di after g.delay;
 
 
 
        unequal <= '1' when ct(di'range) /= dip(di'range) else '0' after g.delay;
 
 
 
        process (dip, s)
 
        begin
 
                ct <= dip after g.delay;
 
                ct(to_integer(unsigned(s) - 1)) <= not dip(to_integer(unsigned(s) - 1)) after g.delay;
 
        end process;
 
 
 
        process (s, dip, parity, ct, cp, unequal)
 
        begin
 
                co <= dip;
 
                single <= '0';
 
                double <= '0';
 
 
 
                if secdec and parity /= cp then
 
                        if unequal = '1' then
 
                                single <= '1';
 
                                co <= ct;
 
                        end if;
 
                else
 
                        if unequal = '1' then
 
                                if secdec then
 
                                        double <= '1';
 
                                else
 
                                        single <= '1';
 
                                        co <= ct;
 
                                end if;
 
                        end if;
 
                end if;
 
        end process;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
use ieee.numeric_std.all;
 
use ieee.math_real.all;
 
 
 
entity hamming_7_4_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of hamming_7_4_tb is
 
        constant clock_period:  time     := 1000 ms / g.clock_frequency;
 
        constant n:           positive   := 3;
 
        signal clk, rst:      std_ulogic := '0';
 
        signal stop:          std_ulogic := '0';
 
        signal di, do, do_s: std_ulogic_vector(3 downto 0) := (others => '0');
 
        signal encoded_tx, encoded_rx, ebit: std_ulogic_vector(6 downto 0) := (others => '0');
 
        signal parity, single, double: std_ulogic := '0';
 
        signal parity_s, single_s, double_s: std_ulogic := '0';
 
begin
 
        cs: entity work.clock_source_tb
 
                generic map (g => g, hold_rst => 2)
 
                port map (stop => stop, clk => clk, rst => rst);
 
 
 
        uut_encode: entity work.hamming_7_4_encoder
 
        generic map (g => g) port map (di => di, do => encoded_tx, parity => parity);
 
 
 
        lossy_channel: process(encoded_tx)
 
                variable seed1, seed2: positive;
 
                variable r: real;
 
                variable i: integer range 0 to 7;
 
        begin
 
                encoded_rx    <= encoded_tx;
 
                uniform(seed1, seed2, r);
 
                if r > 0.5 then
 
                        uniform(seed1, seed2, r);
 
                        i := integer(floor(r * 6.99));
 
                        encoded_rx(i) <= not encoded_tx(i);
 
                        uniform(seed1, seed2, r);
 
                end if;
 
                if r > 0.5 then
 
                        uniform(seed1, seed2, r);
 
                        i := integer(floor(r * 6.99));
 
                        encoded_rx(i) <= not encoded_tx(i);
 
                end if;
 
        end process;
 
 
 
        ebit <= encoded_tx xor encoded_rx;
 
 
 
        uut_decode_secdec: entity work.hamming_7_4_decoder
 
        generic map (g => g) port map (di => encoded_rx, do => do, parity => parity, single => single, double => double);
 
 
 
        uut_decode_single: entity work.hamming_7_4_decoder
 
        generic map (g => g, secdec => false) port map (di => encoded_rx, do => do_s, parity => parity_s, single => single_s, double => double_s);
 
 
 
        stimulus_process: process
 
                procedure test(slv: std_ulogic_vector) is
 
                begin
 
                        di <= slv;
 
                        wait for clock_period * 2;
 
                        if bit_count_f(ebit) = 2 then
 
                                assert double = '1' severity failure;
 
                                assert single = '0' severity failure;
 
                        elsif bit_count_f(ebit) = 1 then
 
                                assert di = do severity failure;
 
                                assert single = '1' severity failure;
 
                                assert double = '0' severity failure;
 
 
 
                                assert di = do_s severity failure;
 
                                assert single_s = '1' severity failure;
 
                        else
 
                                assert di = do severity failure;
 
                                assert double = '0' severity failure;
 
                                assert single = '0' severity failure;
 
 
 
                                assert di = do_s severity failure;
 
                                assert single_s = '0' severity failure;
 
                        end if;
 
                        wait for clock_period * 2;
 
                end procedure;
 
                variable ii: unsigned(7 downto 0) := (others => '1');
 
        begin
 
                di <= (others => '0');
 
                wait until rst = '0';
 
 
 
                while ii /= x"00" loop
 
                        ii := ii - 1;
 
                        test(std_ulogic_vector(ii(3 downto 0)));
 
                end loop;
 
                stop <= '1';
 
                wait;
 
        end process;
 
 
 
end architecture;
 
 
 
------------------------- Hamming CODEC  ------------------------------------------------------
 
 
 
------------------------- VGA Controller ------------------------------------------------------
 
-- VGA Controller
 
--
 
-- See:
 
--  * <https://en.wikipedia.org/wiki/Video_Graphics_Array>
 
--  * <http://www.ece.ualberta.ca/~elliott/ee552/studentAppNotes/1998_w/Altera_UP1_Board_Map/vga.html>
 
--  * <https://www.digikey.com/eewiki/pages/viewpage.action?pageId=15925278>
 
--
 
-- This purpose of this VGA controller is to provide the necessary VGA
 
-- timings for a given resolution (which has to be determined at instantiation
 
-- time and cannot be configured on the fly). The VGA controller will generate
 
-- the correct HSYNC and VSYNCH signals needed, as well as the current row and
 
-- column that is currently being drawn. This can be used to generate an image.
 
--
 
-- Example timing for 640 x 480:
 
--
 
--  |-----800 pixels / 31.778 us---------|
 
--  |-----640 Pixels--------|-160 Pixels-|
 
--  |-----25.422 us---------|--5.75 us---|
 
--  
 
--  +-----------------------+------------+   VSYNC
 
--  |                       |         ^  |     |
 
--  |                       |         |  |     |
 
--  |                       |         |  |     |
 
--  |    Display Period     |   480 Rows |     |
 
--  |                       |         |  |     |
 
--  |                       |         |  |     |
 
--  |                       |         |  |     |
 
--  |                       |         v  |     |
 
--  +-----------------------+        --- |     |
 
--  |                                 ^  |    _| <- Front porch 0.318 ms (10 rows)
 
--  |                                 |  |   |
 
--  |      Blanking Period       45 Rows |   | <--- VSYNC pulse 0.064 ms (2 rows)
 
--  |                                 |  |   |_
 
--  |                                 v  |     | <- Back porch 1.048 ms (33 rows)
 
--  +------------------------------------+     |
 
--                                 
 
--                              ___
 
--  ___________________________|   |_____ HSYNC
 
--                            ^  ^  ^
 
--  0.636 us   Front Porch __/  /  / <-(16 pixels)
 
--  3.813 us   HSYNC Pulse ____/  /  <-(96 pixels)
 
--  1.907 us   Back Porch _______/   <-(48 pixels)
 
--
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use work.util.all;
 
 
 
entity vga_controller is
 
        generic (
 
                g: common_generics;
 
                pixel_clock_frequency:  positive := 25_000_000;
 
                constant cfg: vga_configuration  := vga_640x480);
 
        port (
 
                clk, rst:          in std_ulogic;
 
                h_sync, v_sync:   out std_ulogic;
 
                h_blank, v_blank: out std_ulogic;
 
                column, row:      out integer);
 
end entity;
 
 
 
architecture behavior of vga_controller is
 
        constant h_period: integer := cfg.h_pulse + cfg.h_back_porch + cfg.h_pixels + cfg.h_front_porch; -- number of pixel clocks in a row
 
        constant v_period: integer := cfg.v_pulse + cfg.v_back_porch + cfg.v_pixels + cfg.v_front_porch; -- number of rows in column
 
        signal h_sync_internal, v_sync_internal: std_ulogic := '0';
 
begin
 
        -- The clock does not need to be exactly the correct value
 
        assert pixel_clock_frequency <= (cfg.clock_frequency + 250_000)
 
                and pixel_clock_frequency >= (cfg.clock_frequency - 250_000) severity warning;
 
 
 
        h_sync <= h_sync_internal xor cfg.h_polarity;
 
        v_sync <= v_sync_internal xor cfg.v_polarity;
 
 
 
        process (clk, rst)
 
                constant h_start: integer := cfg.h_pixels + cfg.h_front_porch;
 
                constant h_end:   integer := cfg.h_pixels + cfg.h_front_porch + cfg.h_pulse;
 
                constant v_start: integer := cfg.v_pixels + cfg.v_front_porch;
 
                constant v_end:   integer := cfg.v_pixels + cfg.v_front_porch + cfg.v_pulse;
 
                variable h_count: integer range 0 to h_period - 1 := 0;  -- horizontal counter (counts the columns)
 
                variable v_count: integer range 0 to v_period - 1 := 0;  -- vertical counter (counts the rows)
 
                procedure reset is
 
                begin
 
                        h_count         := 0;
 
                        v_count         := 0;
 
                        h_blank         <= '0' after g.delay;
 
                        v_blank         <= '0' after g.delay;
 
                        column          <= 0 after g.delay;
 
                        row             <= 0 after g.delay;
 
                end procedure;
 
        begin
 
                if rst = '1' and g.asynchronous_reset then
 
                        reset;
 
                elsif rising_edge(clk) then
 
                        if rst = '1' and not g.asynchronous_reset then
 
                                reset;
 
                        else
 
                                if h_count < (h_period - 1) then -- pixel count
 
                                        h_count := h_count + 1;
 
                                else
 
                                        if v_count < (v_period - 1) then -- row count
 
                                                v_count := v_count + 1;
 
                                        else
 
                                                v_count := 0;
 
                                        end if;
 
                                        h_count := 0;
 
                                end if;
 
 
 
                                h_sync_internal <= not logical((h_count < h_start) or (h_count >= h_end)) after g.delay;
 
                                v_sync_internal <= not logical((v_count < v_start) or (v_count >= v_end)) after g.delay;
 
 
 
                                column <= cfg.h_pixels - 1;
 
                                row    <= cfg.v_pixels - 1;
 
 
 
                                if h_count < cfg.h_pixels then h_blank <= '0'; column <= h_count; else h_blank <= '1'; end if;
 
                                if v_count < cfg.v_pixels then v_blank <= '0'; row    <= v_count; else v_blank <= '1'; end if;
 
                        end if;
 
                end if;
 
        end process;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity vga_tb is
 
        generic (g: common_generics; pixel_clock_frequency: positive := 25_000_000; simulation_us: time := 20000 us);
 
end entity;
 
 
 
architecture testing of vga_tb is
 
        constant pixel_clock_period: time   := 1000 ms / pixel_clock_frequency;
 
        signal rst, clk:        std_ulogic  := '1';
 
        signal stop:            boolean     := false;
 
        signal h_sync, v_sync:  std_ulogic  := 'X';
 
        signal h_blank, v_blank: std_ulogic := 'X';
 
        signal column, row:     integer     := 0;
 
begin
 
        duration: process begin wait for simulation_us; stop <= true; wait; end process;
 
        clk_process: process
 
        begin
 
                rst <= '1';
 
                wait for pixel_clock_period * 5;
 
                rst <= '0';
 
                while not stop loop
 
                        clk <= '1';
 
                        wait for pixel_clock_period / 2;
 
                        clk <= '0';
 
                        wait for pixel_clock_period / 2;
 
                end loop;
 
                wait;
 
        end process;
 
 
 
        uut: work.util.vga_controller
 
                generic map (g => g, pixel_clock_frequency => pixel_clock_frequency)
 
                port map (
 
                        rst     => rst,
 
                        clk     => clk,
 
                        h_sync  => h_sync,
 
                        v_sync  => v_sync,
 
                        h_blank => h_blank,
 
                        v_blank => v_blank,
 
                        column  => column,
 
                        row     => row);
 
end architecture;
 
 
 
------------------------- VGA Controller ------------------------------------------------------
 
 
 
------------------------- LED Controller ------------------------------------------------------
 
--| This module implements a 7 segment display (plus decimal point) driver,
 
--|  with 4 displays in total:
 
--|
 
--|    _____________________ an (selects segment)
 
--|    |     |     |     |
 
--|   __    __    __    __
 
--|  |  |  |  |  |  |  |  |
 
--|  |__|  |__|  |__|  |__|
 
--|  |  |  |  |  |  |  |  |
 
--|  |__|. |__|. |__|. |__|.
 
--|   |____|_____|_____|____ ka (value to display on segment)
 
--|
 
--| Each of the display shares a common anode for all of its LEDs, this can be
 
--| used to select an individual display
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity led_7_segment_display is
 
        generic (
 
                g:                      common_generics;
 
                use_bcd_not_hex:        boolean  := true;
 
                refresh_rate_us:        natural  := 1500;
 
                number_of_led_displays: positive := 4);
 
        port (
 
                clk:      in   std_ulogic;
 
                rst:      in   std_ulogic;
 
 
 
                leds_we:  in   std_ulogic;
 
                leds:     in   std_ulogic_vector((number_of_led_displays * led_7_segment_character_length) - 1 downto 0);
 
 
 
                -- Physical outputs
 
                an:       out  std_ulogic_vector(number_of_led_displays - 1 downto 0);  -- anodes, controls on/off
 
                ka:       out  std_ulogic_vector(7 downto 0)); -- cathodes, data on display
 
end;
 
 
 
architecture rtl of led_7_segment_display is
 
 
 
        -- This lookup table converts a BCD character into a value
 
        -- that can be displayed on an 7 segment display. The layout of which
 
        -- is as follows:
 
        --
 
        --       A
 
        --      ---
 
        --   F |   | B
 
        --     |___|
 
        --   E | G | C
 
        --     |___| . DP
 
        --       D
 
        --
 
        -- The following encoding is used to convert the input BCD character
 
        -- into a value that can be put onto the display.
 
        --
 
        --  -----------------------------------------
 
        -- |   | DP| G | F | E | D | C | B | A | Hex |
 
        -- |BCD| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |Hi Lo|
 
        --  -----------------------------------------
 
        -- | 0 |   |   | 1 | 1 | 1 | 1 | 1 | 1 | 3 F |
 
        -- | 1 |   |   |   |   |   | 1 | 1 |   | 0 6 |
 
        -- | 2 |   | 1 |   | 1 | 1 |   | 1 | 1 | 5 B |
 
        -- | 3 |   | 1 |   |   | 1 | 1 | 1 | 1 | 4 F |
 
        -- | 4 |   | 1 | 1 |   |   | 1 | 1 |   | 6 6 |
 
        -- | 5 |   | 1 | 1 |   | 1 | 1 |   | 1 | 6 D |
 
        -- | 6 |   | 1 | 1 | 1 | 1 | 1 |   | 1 | 7 D |
 
        -- | 7 |   |   |   |   |   | 1 | 1 | 1 | 0 7 |
 
        -- | 8 |   | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 7 F |
 
        -- | 9 |   | 1 | 1 |   | 1 | 1 | 1 | 1 | 6 F |
 
        -- |   |   |   |   |   |   |   |   |   | 0 0 |
 
        -- | . | 1 |   |   |   |   |   |   |   | 8 0 |
 
        -- | - |   | 1 |   |   |   |   |   |   | 4 0 |
 
        --  -----------------------------------------
 
        -- | A |   | 1 | 1 | 1 |   | 1 | 1 | 1 | 7 7 |
 
        -- | b |   | 1 | 1 | 1 | 1 | 1 |   |   | 7 C |
 
        -- | C |   |   | 1 | 1 | 1 |   |   | 1 | 3 9 |
 
        -- | d |   | 1 |   | 1 | 1 | 1 | 1 |   | 5 E |
 
        -- | E |   | 1 | 1 | 1 | 1 |   |   | 1 | 7 9 |
 
        -- | F |   | 1 | 1 | 1 |   |   |   | 1 | 7 1 |
 
        --  -----------------------------------------
 
        --
 
        -- The table is then inverted before it goes to the output.
 
        --
 
 
 
        function hex_to_7_segment(a: led_7_segment_character) return led_7_segment is
 
                variable r: std_ulogic_vector(7 downto 0) := x"00";
 
        begin
 
                -- NB. You may have thought a case statement would be the best
 
                -- way of doing this, and you would be right. However, Xilinx ISE
 
                -- issues annoying 'INFO' statements when you do - thanks Xilinx!
 
                -- The generated hardware is the same however.
 
                   if a = "0000" then r := x"3F"; -- 0
 
                elsif a = "0001" then r := x"06"; -- 1
 
                elsif a = "0010" then r := x"5B"; -- 2
 
                elsif a = "0011" then r := x"4F"; -- 3
 
                elsif a = "0100" then r := x"66"; -- 4
 
                elsif a = "0101" then r := x"6D"; -- 5
 
                elsif a = "0110" then r := x"7D"; -- 6
 
                elsif a = "0111" then r := x"07"; -- 7
 
                elsif a = "1000" then r := x"7F"; -- 8
 
                elsif a = "1001" then r := x"6F"; -- 9
 
                elsif a = "1010" then r := x"77"; -- A
 
                elsif a = "1011" then r := x"7C"; -- b
 
                elsif a = "1100" then r := x"39"; -- C
 
                elsif a = "1101" then r := x"5E"; -- d
 
                elsif a = "1110" then r := x"79"; -- E
 
                elsif a = "1111" then r := x"71"; -- F
 
                end if;
 
                return r;
 
        end function;
 
 
 
        function bcd_to_7_segment(a: led_7_segment_character) return led_7_segment is
 
                variable r: std_ulogic_vector(7 downto 0) := x"00";
 
        begin
 
                case a is
 
                        when "0000" => r := x"3F"; -- 0
 
                        when "0001" => r := x"06"; -- 1
 
                        when "0010" => r := x"5B"; -- 2
 
                        when "0011" => r := x"4F"; -- 3
 
                        when "0100" => r := x"66"; -- 4
 
                        when "0101" => r := x"6D"; -- 5
 
                        when "0110" => r := x"7D"; -- 6
 
                        when "0111" => r := x"07"; -- 7
 
                        when "1000" => r := x"7F"; -- 8
 
                        when "1001" => r := x"6F"; -- 9
 
                        when "1010" => r := x"00"; -- Blank
 
                        when "1011" => r := x"80"; -- .
 
                        when "1100" => r := x"40"; -- -
 
                        when "1101" => r := x"00"; -- Unused
 
                        when "1110" => r := x"00"; -- Unused
 
                        when "1111" => r := x"00"; -- Unused
 
                        when others => r := x"00"; -- Unused
 
                end case;
 
                return r;
 
        end function;
 
 
 
        function char_to_7_segment(a: led_7_segment_character) return led_7_segment is
 
        begin
 
                if use_bcd_not_hex then
 
                        return invert(bcd_to_7_segment(a));
 
                else
 
                        return invert(hex_to_7_segment(a));
 
                end if;
 
        end function;
 
 
 
        signal leds_o: std_ulogic_vector(leds'range) := (others => '0');
 
 
 
        signal do_shift:  std_ulogic := '0';
 
        signal shift_reg: std_ulogic_vector(number_of_led_displays - 1 downto 0);
 
 
 
        signal leds_reg_o: std_ulogic_vector(leds'range) := (others => '0');
 
        signal leds_reg_we_o: std_ulogic := '0';
 
begin
 
        an <= invert(shift_reg) after g.delay;
 
 
 
        segment_reg: entity work.reg
 
                generic map (g => g, N => number_of_led_displays * led_7_segment_character_length)
 
                port map (
 
                        clk => clk,
 
                        rst => rst,
 
                        we  => leds_we,
 
                        di  => leds,
 
                        do  => leds_reg_o);
 
 
 
        segment_reg_re: entity work.reg
 
                generic map (g => g, N => 1)
 
                port map (
 
                        clk   => clk,
 
                        rst   => rst,
 
                        we    => '1',
 
                        di(0) => leds_we,
 
                        do(0) => leds_reg_we_o);
 
 
 
        led_gen: for i in number_of_led_displays - 1 downto 0 generate
 
                led_i: entity work.reg
 
                        generic map (g => g, N => led_7_segment_character_length)
 
                        port map (
 
                                clk => clk,
 
                                rst => rst,
 
                                we  => leds_reg_we_o,
 
                                di  => leds_reg_o((i*led_7_segment_character_length) + led_7_segment_character_length - 1 downto (i*led_7_segment_character_length)),
 
                                do  => leds_o((i*led_7_segment_character_length) + led_7_segment_character_length - 1 downto (i*led_7_segment_character_length)));
 
        end generate;
 
 
 
        timer: entity work.timer_us
 
                generic map (g => g, timer_period_us => refresh_rate_us)
 
                port map (
 
                        clk             => clk,
 
                        rst             => rst,
 
                        co              => do_shift);
 
 
 
        process(rst, clk, do_shift, shift_reg)
 
        begin
 
                if rst = '1' and g.asynchronous_reset then
 
                        shift_reg    <= (others => '0') after g.delay;
 
                        shift_reg(0) <= '1' after g.delay;
 
                elsif rising_edge(clk) then
 
                        if rst = '1' and not g.asynchronous_reset then
 
                                shift_reg    <= (others => '0') after g.delay;
 
                                shift_reg(0) <= '1' after g.delay;
 
                        else
 
                                if do_shift = '1' then
 
                                        shift_reg <= shift_reg(number_of_led_displays - 2 downto 0) & shift_reg(number_of_led_displays - 1) after g.delay;
 
                                else
 
                                        shift_reg <= shift_reg after g.delay;
 
                                end if;
 
                        end if;
 
                end if;
 
        end process;
 
 
 
        process(leds_o, shift_reg)
 
        begin
 
                ka <= (others => '0');
 
                for i in  number_of_led_displays - 1 downto 0 loop
 
                        if '1' = shift_reg(number_of_led_displays - i - 1) then
 
                                ka <= char_to_7_segment(leds_o(i*led_7_segment_character_length + led_7_segment_character_length - 1 downto (i*led_7_segment_character_length))) after g.delay;
 
                        end if;
 
                end loop;
 
        end process;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity led_7_segment_display_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of led_7_segment_display_tb is
 
        constant clock_period:  time     := 1000 ms / g.clock_frequency;
 
        signal clk, rst:      std_ulogic := '0';
 
        signal stop:          std_ulogic := '0';
 
 
 
        constant number_of_led_displays: positive := 4;
 
        signal an: std_ulogic_vector(number_of_led_displays - 1 downto 0);
 
        signal ka: std_ulogic_vector(7 downto 0);
 
        signal leds_we: std_ulogic;
 
        signal leds:    std_ulogic_vector((number_of_led_displays * led_7_segment_character_length) - 1 downto 0);
 
begin
 
        cs: entity work.clock_source_tb
 
                generic map (g => g, hold_rst => 2)
 
                port map (stop => stop, clk => clk, rst => rst);
 
 
 
        -- We have a very fast refresh rate here, just for testing purposes.
 
        uut: entity work.led_7_segment_display
 
                generic map (g => g, refresh_rate_us => 1)
 
                port map (clk => clk, rst => rst, leds_we => leds_we, leds => leds, an => an, ka => ka);
 
 
 
        stimulus_process: process
 
        begin
 
                wait for clock_period * 2;
 
                leds_we <= '1';
 
                leds <= x"1234";
 
                wait for clock_period * 1;
 
                leds_we <= '0';
 
                wait for clock_period * 1000;
 
                stop <= '1';
 
                wait;
 
        end process;
 
 
 
end architecture;
 
 
 
------------------------- LED Controller ------------------------------------------------------
 
 
 
------------------------- Sine / Cosine  ------------------------------------------------------
 
-- Sine / Cosine calculation using multiplication
 
-- Half-inched from <https://github.com/jamesbowman/sincos>
 
-- Angles are input as signed Furmans (1 Furman = (1/pow(2, 16) of a circle))
 
-- 1 Degree is ~182 Furmans. 1 rad is ~10430 Furmans.
 
-- Result is signed scaled 16-bit integer; -1 = -32767, +1 = 32767
 
--
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity sine is
 
        generic (g: common_generics; pipeline: boolean := true);
 
        port (
 
                clk, rst, xwe: in std_ulogic;
 
                x:  in  std_ulogic_vector(15 downto 0);
 
                s:  out std_ulogic_vector(15 downto 0));
 
end entity;
 
 
 
architecture behavior of sine is
 
        subtype val is signed(x'range);
 
        subtype mul is signed((val'high * 2) + 1 downto 0);
 
        function half_multiply_add(a, b, c: val) return val is
 
                variable t: mul;
 
                variable r: val;
 
        begin
 
                t := a * b;
 
                r := t(t'high downto r'high + 1) + c;
 
                return r;
 
        end function;
 
        signal n: signed(2 downto 0);
 
        signal xn, z, y, sums, sumc, sum1, cc,  t0, t1, t0n, t1n, sa, so: val;
 
        signal cc32: mul;
 
        signal xnslv, t0nslv, t1nslv: std_ulogic_vector(x'range);
 
begin
 
        pipe_0: if pipeline generate
 
                reg_in: work.util.reg
 
                        generic map (g => g, N => x'length)
 
                        port map (clk => clk, rst => rst, we => xwe, di => x, do => xnslv);
 
                reg_out: work.util.reg
 
                        generic map (g => g, N => x'length)
 
                        port map (clk => clk, rst => rst, we => '1', di => std_ulogic_vector(so), do => s);
 
                xn  <= signed(xnslv);
 
                t0n <= signed(t0); -- also need to delay n
 
                t1n <= signed(t1); -- also need to delay n
 
        end generate;
 
        no_pipe_0: if not pipeline generate
 
                xn <= signed(x);
 
                s  <= std_ulogic_vector(so) after g.delay;
 
                t0n <= t0;
 
                t1n <= t1;
 
        end generate;
 
 
 
        y(1 downto 0)  <= (others => '0') after g.delay;
 
        y(15 downto 2) <= signed(xn(13 downto 0)) after g.delay;
 
        n    <= signed(xn(15 downto 13)) + "01" after g.delay;
 
        z    <= half_multiply_add(y, y,        x"0000") after g.delay;
 
        sumc <= half_multiply_add(z, x"0FBD", -x"4EE9") after g.delay;
 
        sums <= half_multiply_add(z, x"04F8", -x"2953") after g.delay;
 
        sum1 <= half_multiply_add(z, sums,     x"6487") after g.delay;
 
        t0   <= z    when n(1) = '1' else y after g.delay;
 
        t1   <= sumc when n(1) = '1' else sum1 after g.delay;
 
        cc32 <= t0n * t1n after g.delay;
 
        cc   <= cc32(cc32'high - 1 downto cc'high) after g.delay;
 
        sa   <= cc + x"7FFF" when n(1) = '1' else cc after g.delay;
 
        so   <= -sa when n(2) = '1' else sa after g.delay;
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity cosine is
 
        generic (g: common_generics; pipeline: boolean := true);
 
        port (
 
                clk, rst, xwe: in std_ulogic;
 
                x:  in  std_ulogic_vector(15 downto 0);
 
                c:  out std_ulogic_vector(15 downto 0));
 
end entity;
 
 
 
architecture behavior of cosine is
 
        signal xn: std_ulogic_vector(c'range);
 
begin
 
        xn <= std_ulogic_vector(signed(x) + x"4000");
 
        calc: entity work.sine
 
                generic map(g => g, pipeline => pipeline) port map(clk => clk, rst => rst, xwe => xwe, x => xn, s => c);
 
end architecture;
 
 
 
library ieee, work;
 
use ieee.std_logic_1164.all;
 
use ieee.numeric_std.all;
 
use work.util.all;
 
 
 
entity sine_tb is
 
        generic (g: common_generics);
 
end entity;
 
 
 
architecture testing of sine_tb is
 
        constant clock_period:  time     := 1000 ms / g.clock_frequency;
 
        signal clk, rst:      std_ulogic := '0';
 
        signal stop:          std_ulogic := '0';
 
 
 
        constant number_of_led_displays: positive := 4;
 
        signal x: std_ulogic_vector(15 downto 0);
 
        signal s, c: std_ulogic_vector(x'range);
 
begin
 
        cs: entity work.clock_source_tb
 
                generic map (g => g, hold_rst => 2)
 
                port map (stop => stop, clk => clk, rst => rst);
 
 
 
        uut_c: entity work.sine   generic map (g => g) port map (clk => clk, rst => rst, xwe => '1', x => x, s => s);
 
        uut_s: entity work.cosine generic map (g => g) port map (clk => clk, rst => rst, xwe => '1', x => x, c => c);
 
 
 
        stimulus_process: process
 
                variable cnt: integer := -32768;
 
        begin
 
                x <= std_ulogic_vector(to_signed(cnt, x'length));
 
                wait for clock_period * 2;
 
                while cnt < 32768 loop
 
                        x <= std_ulogic_vector(to_signed(cnt, x'length));
 
                        wait for clock_period * 10;
 
                        cnt := cnt + 182;
 
                end loop;
 
                stop <= '1';
 
                wait;
 
        end process;
 
end architecture;
 
------------------------- Sine / Cosine  ------------------------------------------------------
 
 
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.