Primerjava jezikov Verilog in VHDL

Verilog je veliko bolj kompakten jezik za opis digitalnih vezij kot je VHDL. Primerjavo opisa vezja v obeh jezikih bomo naredili na dveh primerih: modelu obnašanja (angl. behavioral description) 8-bitnega seštevalnika z izhodnim registrom in strukturnem modelu 4-bitnega seštevalnika.

Model obnašanja vezja

Verilog

module adder
( 
  input [7:0] a,
  input [7:0] b,
  input clk,
  output reg [7:0] sum,
  output reg carry 
);

always @(posedge clk)
  {carry, sum} <= a + b;
  
endmodule

Osnovna enota jezika Verilog je modul. Ime vezja je zapisano za rezervirano besedo module v oklepaju so deklaracije vhodnih in izhodnih signalov, nato pa stavki z opisom zgradbe ali delovanja vezja in na koncu endmodule.

Izhodni register z vsoto opišemo s stavkom: always, kjer definiramo fronto ure ob kateri se izvede prireditev. Jezik Verilog predpostavlja, da je vsota 8-bitnih signalov 9-biten vektor, ki ga v eni sami vrstici priredimo 8-bitni izhodni vsoti s prenosom (carry).

VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity adder is
    Port ( a, b : in std_logic_vector (7 downto 0);
           clk : in std_logic;
           sum : out std_logic_vector (7 downto 0);
           carry : out std_logic);
end adder;

architecture Behavioral of adder is
 signal s: unsigned(8 downto 0);
begin
 p: process(clk)
 begin
 if rising_edge(clk) then
   s <= resize(unsigned(a), 9) + resize(unsigned(b), 9);
 end if;
 end process;
 
 sum <= std_logic_vector(s(7 downto 0));
 carry <= s(8);
end Behavioral;

Opis seštevalnika je v jeziku VHDL precej daljši. V opis so vključene knjižnice, sestavljen je iz opisa vmesnika entity in arhitekture, kar omogoča izdelavo različnih arhitektur za enako vezje.

Za izračuin vsote s prenosom potrebujemo podatkovni tip unsigned in deklaracijo 9-bitnega notranjega signala. Izhodni register dobimo tako, da vsoto priredimo v procesu ob naraščajoči fronti ure rising_edge(clk). V prireditvenem stavku za izračun vsote explicitno pretvorimo vhoda v unsigned in ju razširimo na 9 bitov. Na koncu določimo kateri biti so povezani z vektorjem izhodne vsote in kateri s prenosom ter naredimo pretvorbo nazaj v std_logic_vector.

Strukturni opis 4-bitnega seštevalnika

Verilog

Strukturni opis je podoben sestavljanju sheme, kjer iz gradnikov (komponent, modulov) sestavljamo večje vezje. Naš gradnik bo polni seštevalnik, ki ga v jeziku Verilog opišemo z dvema stavkoma assign in logičnimi operatorji:

module full_adder(
    input a,
    input b,
    input cin,
    output s,
    output cout
    );

   assign s    = a ^ b ^ cin;
   assign cout = (a & b) | (cin & (a ^ b));
endmodule

Štiribitni seštevalnik sestavimo s povezavo štirih gradnikov full_adder. V opisu 4-bitnega seštevalnika adder imamo deklarirane 4-bitne vektorske vrednosti [3:0], kjer v oglatem oklepaju zapišemo območje indeksov. Deklarirali smo tudi povezovalne signale c za povezavo prenosov med polnimi seštevalniki. Polni seštevalnik vključimo v strukturni opis vezja tako, da navedemo ime modula full_adder, enolično oznako, npr. u1 in povezave signalov v oklepaju.

module adder(
   input [3:0] a,
   input [3:0] b,
   output [3:0] sum,
   output carry
   );

   wire [4:0] c;
   assign c[0] = 1'b0;

   full_adder u0 (a[0], b[0], c[0], sum[0], c[1] ); 
   full_adder u1 (a[1], b[1], c[1], sum[1], c[2] );
   full_adder u2 (a[2], b[2], c[2], sum[2], c[3] );
   full_adder u3 (a[3], b[3], c[3], sum[3], c[4] );

   assign carry = c[4];
endmodule

Opis povezav gradnikov je pri večbitnem seštevalniku zelo regularen, zato lahko zapišemo zanko namesto štirih stavkov, ki vključujejo in povezujejo gradnike. Uporabili bomo stavek generate in zanko for.

 genvar i;
 generate 
   for(i=0; i<3; i=i+1)
     begin : gen_adders
       full_adder u(a[i], b[i], c[i], sum[i], c[i+1]);
     end
 endgenerate

VHDL

VHDL opis polnega seštevalnika ne bomo posebej predstavljali, ampak gremo kar na opis 4-bitnega seštevalnika z vključenimi in povezanimi komponentami.

library ieee;
use ieee.std_logic_1164.all;
use work.all;

entity adder is
  port (a,b: in std_logic_vector(3 downto 0);
        sum: out std_logic_vector(3 downto 0)
        carry: out std_logic
        );
end adder;

architecture struct of adder is
  signal c: std_logic_vector(3 downto 0);
begin
  c(0) <= '0';

  u0: entity work.full_adder port map(a(0), b(0), c(0), s(0), c(1) );
  u1: entity work.full_adder port map(a(1), b(1), c(1), s(1), c(2) );
  u2: entity work.full_adder port map(a(2), b(2), c(2), s(2), c(3) );
  u3: entity work.full_adder port map(a(3), b(3), c(3), s(3), carry);
end struct;

Tudi v jeziku VHDL lahko s stavkom generate opišemo regularno strukturo 4-bitnega seštevalnika:


 gen_adders: for i in 0 to 3 generate
 begin
   u: entity work.full_adder port map(a(i), b(i), c(i), s(i), c(i+1));
 end generate;

Zaključek

Strojno-opisni jezik VHDL je veliko bolj deskriptiven, razvijalec mora natančno določiti pretvarjanje podatkov in delovanje operacij, kar ima za posledico daljšo kodo, predvsem za enostavne operacije. Koda jezika Verilog je krajša, ker predpostavlja zelo dobro razumevanje delovanja prevajalnikov in imlicitnih pretvorb podatkov. Vsak pristop ima svoje prednosti, tako da sta na področju razvoja digitalnih vezij danes zastopana oba jezika.