Details

Voordat je (ongetwijfeld met vol enthousiasme) een Vivado project maakt en code begint te schijven, blijft het belangrijk om eerst een design te maken!!

Hiernaast wordt de volledige set van instructie voor de RISC-V weergeven. Om precies te zijn, dit is de volledige set van instructie voor de basis RISC-V 32i (RV32i) instructies.

In deze lijst zijn er 8 instructies die een effect hebben op de program counter. De eerste 6 gemarkeerde instructies zijn de conditional branch instructies: beq, bne, blt, bge, bltu en bgeu. Bij deze instructies zal er (indien aan de vooropgestelde voorwaarde voldaan is) een relatieve jump gebeuren. Het adres waarnaar er gesprongen wordt is een offset ten opzichte van de huidige waarde van de program counter. Bij de laatste gemarkeerde instructies kan een relatieve jump en een absolute jump gedaan worden.

Er kan dus geconcludeerd worden dat, bij een jump, de waarde van de program counter altijd het resultaat is van een som:

  • van de PC zelf en een offset
  • van een register en een offset

Indien er geen jump is, is de waarde van de program counter de som:

  • van de PC zelf en de constante 0x4

Met dit inzicht, een blaadje papier met een potlood (en een gom), enkele tassen koffie of thee (of water), kan een design gemaakt worden. Bijvoorbeeld:

Ongeacht de keuze van het design, ziet de entity voor de program counter er (quasi) hetzelfde uit.

  • clock en synchrone, actief hoge reset
  • twee 32-bit data ingangen
  • één 32-bit data uitgang
  • 2 controle signalen:
    • abs_rel_b is ‘1’ bij een absolute sprong en ‘0’ bij een relatieve
    • immediate_four_b is ‘1’ voor een relatieve sprong met offset en ‘0’ bij een (standaard) sprong met 4
entity program_counter is
    port(
        clock : in STD_LOGIC;
        reset : in STD_LOGIC;
        abs_rel_b: in std_logic;
        immediate_four_b: in std_logic;
        rs1 : in std_logic_vector(31 downto 0);
        immediate : in std_logic_vector(31 downto 0);
        data_out : out std_logic_vector(31 downto 0)
    );
end entity program_counter;

Merk ook op dat de immediate ingang geen rol speel bij een absolute jump

Een testbench voor de program counter kan je hieronder vinden of hier downloaden. Op het einde van de simulatie wordt er een resultaat afgedrukt, zoals in het voorbeeld hieronder.

--------------------------------------------------------------------------------
-- KU Leuven - ESAT/COSIC - Emerging technologies, Systems & Security
--------------------------------------------------------------------------------
-- Module Name:     program_counter_tb - Behavioural
-- Project Name:    Testbench for program_counter
-- Description:     
--
-- Revision     Date       Author     Comments
-- v0.1         20250826   VlJo       Initial version
--
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- use IEEE.NUMERIC_STD.ALL;

entity program_counter_tb is
end entity program_counter_tb;

architecture Behavioural of program_counter_tb is

    component program_counter is
        port (
            clock : in STD_LOGIC;
            reset : in STD_LOGIC;
            abs_rel_b: in std_logic;
            immediate_four_b: in std_logic;
            rs1 : in std_logic_vector(31 downto 0);
            immediate : in std_logic_vector(31 downto 0);
            data_out : out std_logic_vector(31 downto 0)
        );
    end component program_counter;

    signal clock_i : STD_LOGIC;
    signal reset_i : STD_LOGIC;
    signal abs_rel_b_i : STD_LOGIC;
    signal immediate_four_b_i : STD_LOGIC;
    signal rs1_i : STD_LOGIC_VECTOR(31 downto 0);
    signal immediate_i : STD_LOGIC_VECTOR(31 downto 0);
    signal data_out_o : STD_LOGIC_VECTOR(31 downto 0);

    constant clock_period : time := 10 ns;

begin

    -------------------------------------------------------------------------------
    -- STIMULI
    -------------------------------------------------------------------------------
    PSTIM: process
        variable good_checks : natural;
        variable bad_checks : natural;
    begin
        abs_rel_b_i <= '0';
        immediate_four_b_i <= '0';
        rs1_i <= (others => '0');
        immediate_i <= (others => '0');
        wait until clock_i = '1';
        wait until clock_i = '0';
        wait until reset_i = '0';
        if data_out_o /= x"00000000" then
            bad_checks := bad_checks + 1;
        else
            good_checks := good_checks + 1;
        end if;

        wait for clock_period;
        if data_out_o /= x"00000004" then
            bad_checks := bad_checks + 1;
        else
            good_checks := good_checks + 1;
        end if;
    
        wait for clock_period;
        if data_out_o /= x"00000008" then
            bad_checks := bad_checks + 1;
        else
            good_checks := good_checks + 1;
        end if;

        wait for clock_period*5;
        if data_out_o /= x"0000001C" then
            bad_checks := bad_checks + 1;
        else
            good_checks := good_checks + 1;
        end if;

        immediate_four_b_i <= '1';
        immediate_i <= (4 => '1', others => '0');
        wait for clock_period;
        if data_out_o /= x"0000002C" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        immediate_four_b_i <= '0';
        wait for clock_period;
        if data_out_o /= x"00000030" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        wait for clock_period;
        if data_out_o /= x"00000034" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        immediate_four_b_i <= '1';
        immediate_i <= x"80000000";
        wait for clock_period;
        if data_out_o /= x"80000034" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        immediate_four_b_i <= '0';
        wait for clock_period;
        if data_out_o /= x"80000038" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        wait for clock_period;
        if data_out_o /= x"8000003C" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        abs_rel_b_i <= '1';
        immediate_i <= x"00000004";
        wait for clock_period;
        if data_out_o /= x"00000004" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;


        immediate_four_b_i <= '1';
        immediate_i <= x"80000000";
        wait for clock_period;
        if data_out_o /= x"80000000" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        immediate_four_b_i <= '0';
        wait for clock_period;
        if data_out_o /= x"80000000" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        wait for clock_period;
        if data_out_o /= x"80000000" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        rs1_i <= x"80000000";
        wait for clock_period;
        if data_out_o /= x"00000000" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;
        
        
        rs1_i <= x"5EADBEEF";
        wait for clock_period;
        if data_out_o /= x"DEADBEEF" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        rs1_i <= x"00000002";
        immediate_i <= x"00000002";
        wait for clock_period;
        if data_out_o /= x"00000004" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        wait until reset_i = '1';

        if data_out_o /= x"00000004" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        wait until clock_i = '1';
        if data_out_o /= x"00000004" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;
        
        wait for 1 ns;
        if data_out_o /= x"00000000" then
            bad_checks := bad_checks + 1;
            report("DISCH_GRADING - Abnormal behavior detected");
        else
            good_checks := good_checks + 1;
        end if;

        report "DISCH_GRADING (good, bad, total): " & integer'image(good_checks) & " " & integer'image(bad_checks) & " " & integer'image(good_checks + bad_checks) & "" severity note;
        
        wait;
    end process;


    -------------------------------------------------------------------------------
    -- DUT
    -------------------------------------------------------------------------------
    DUT: component program_counter port map(
        clock => clock_i,
        reset => reset_i,
        abs_rel_b => abs_rel_b_i,
        immediate_four_b => immediate_four_b_i,
        rs1 => rs1_i,
        immediate => immediate_i,
        data_out => data_out_o
    );


    -------------------------------------------------------------------------------
    -- CLOCK
    -------------------------------------------------------------------------------
    PCLK: process
    begin
        clock_i <= '1';
        wait for clock_period/2;
        clock_i <= '0';
        wait for clock_period/2;
    end process PCLK;


    -------------------------------------------------------------------------------
    -- RESET
    -------------------------------------------------------------------------------
    PRST: process
    begin
        reset_i <= '1';
        wait for clock_period*9;
        wait for clock_period/2;
        reset_i <= '0';
        wait for clock_period*25;
        reset_i <= '1';
        wait;
    end process PRST;

end Behavioural;