Pytanie do wywiadu VHDL powinno spowodować powstanie kodu VHDL.
Miałem okazję znaleźć błąd zaplecza ghdl llvm z implementacją tabeli przejścia stanu Dave'a Tweeda, w której autor ghdl destylował implementację w funkcji do 17 wierszy:
type remains is (r0, r1, r2, r3, r4); -- remainder values
function mod5 (dividend: bit_vector) return boolean is
type remain_array is array (NBITS downto 0) of remains;
type branch is array (remains, bit) of remains;
constant br_table: branch := ( r0 => ('0' => r0, '1' => r1),
r1 => ('0' => r2, '1' => r3),
r2 => ('0' => r4, '1' => r0),
r3 => ('0' => r1, '1' => r2),
r4 => ('0' => r3, '1' => r4)
);
variable remaind: remains := r0;
variable tbit: bit_vector (NBITS - 1 downto 0) := dividend;
begin
for i in dividend'length - 1 downto 0 loop
remaind := br_table(remaind,tbit(i));
end loop;
return remaind = r0;
end function;
Powiązany przypadek testowy jest dość mały, co pozwala na łatwiejsze debugowanie i używa nazw stanów zgodnych z VHDL w wyliczonym typie pozostaje:
(stworzony przy pomocy Dia)
Chodzi o to, że funkcja (lub nawet przykładowy program 27 linii VHDL) jest wystarczająco krótki, aby napisać odpowiedź VHDL podczas wywiadu. Nie musisz się martwić, że zepsujesz pytanie podczas rozmowy kwalifikacyjnej wymagające wykazania się zarówno wiedzą, jak i umiejętnościami, od osoby, z którą rozmawiamy, będzie się bronić implementacji, gdy zostanie zapytany.
(Błąd llvm został naprawiony dzisiaj w commit 1f5df6e ).
Jedną z ważniejszych rzeczy jest to, że tabela przejścia stanu mówi nam również, gdzie bit ilorazu byłby „1” pokazany przez przejście do stanu o niższej wartości resztkowej (lub obu przejść dla r4) przy odejmowaniu 5 od dywidendy. Można to zakodować w osobnej tabeli (lub tabeli typu rekordu, która wydaje się niewygodna). Robimy to historycznie w sprzęcie graficznym obsługującym poziome rozdzielczości ekranu wielokrotności 5 pikseli.
W ten sposób otrzymujemy div / mod5, który tworzy iloraz, a resztę:
library ieee;
use ieee.std_logic_1164.all;
entity divmod5 is
generic (
NBITS: natural := 13
);
port (
clk: in std_logic;
dividend: in std_logic_vector (NBITS - 1 downto 0);
load: in std_logic;
quotient: out std_logic_vector (NBITS - 3 downto 0);
remainder: out std_logic_vector (2 downto 0);
remzero: out std_logic
);
end entity;
architecture foo of divmod5 is
type remains is (r0, r1, r2, r3, r4); -- remainder values
type remain_array is array (NBITS downto 0) of remains;
signal remaindr: remain_array := (others => r0);
signal dividendreg: std_logic_vector (NBITS - 1 downto 0);
signal quot: std_logic_vector (NBITS - 3 downto 0);
begin
parallel:
for i in NBITS - 1 downto 0 generate
type branch is array (remains, bit) of remains;
-- Dave Tweeds state transition table:
constant br_table: branch := ( r0 => ('0' => r0, '1' => r1),
r1 => ('0' => r2, '1' => r3),
r2 => ('0' => r4, '1' => r0),
r3 => ('0' => r1, '1' => r2),
r4 => ('0' => r3, '1' => r4)
);
type qt is array (remains, bit) of std_ulogic;
-- Generate quotient bits from Dave Tweeds state machine using q_table.
-- A '1' when a remainder goes to a lower remainder or for both branches
-- of r4. A '0' for all other branches.
constant q_table: qt := ( r0 => (others => '0'),
r1 => (others => '0'),
r2 => ('0' => '0', '1' => '1'),
r3 => (others => '1'),
r4 => (others => '1')
);
signal tbit: bit;
begin
tbit <= to_bit(dividendreg(i));
remaindr(i) <= br_table(remaindr(i + 1),tbit);
do_quotient:
if i < quot'length generate
quot(i) <= q_table(remaindr(i + 1),tbit);
end generate;
end generate;
dividend_reg:
process (clk)
begin
if rising_edge(clk) then
if load = '1' then
dividendreg <= dividend;
end if;
end if;
end process;
quotient_reg:
process (clk)
begin
if rising_edge (clk) then
quotient <= quot;
end if;
end process;
remainders:
process (clk)
begin
if rising_edge(clk) then
remzero <= '0';
case remaindr(0) is
when r0 =>
remainder <= "000";
remzero <= '1';
when r1 =>
remainder <= "001";
when r2 =>
remainder <= "010";
when r3 =>
remainder <= "011";
when r4 =>
remainder <= "100";
end case;
end if;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity divmod5_tb is
end entity;
architecture foo of divmod5_tb is
constant NBITS: integer range 0 to 13 := 8;
signal clk: std_logic := '0';
signal dividend: std_logic_vector (NBITS - 1 downto 0);
signal load: std_logic := '0';
signal quotient: std_logic_vector (NBITS - 3 downto 0);
signal remainder: std_logic_vector (2 downto 0);
signal remzero: std_logic;
signal psample: std_ulogic;
signal sample: std_ulogic;
signal done: boolean;
begin
DUT:
entity work.divmod5
generic map (NBITS)
port map (
clk => clk,
dividend => dividend,
load => load,
quotient => quotient,
remainder => remainder,
remzero => remzero
);
CLOCK:
process
begin
wait for 5 ns;
clk <= not clk;
if done'delayed(30 ns) then
wait;
end if;
end process;
STIMULI:
process
begin
for i in 0 to 2 ** NBITS - 1 loop
wait for 10 ns;
dividend <= std_logic_vector(to_unsigned(i,NBITS));
wait for 10 ns;
load <= '1';
wait for 10 ns;
load <= '0';
end loop;
wait for 15 ns;
done <= true;
wait;
end process;
SAMPLER:
process (clk)
begin
if rising_edge(clk) then
psample <= load;
sample <= psample after 4 ns;
end if;
end process;
MONITOR:
process (sample)
variable i: integer;
variable div5: integer;
variable rem5: integer;
begin
if rising_edge (sample) then
i := to_integer(unsigned(dividend));
div5 := i / 5;
assert div5 = unsigned(quotient)
report LF & HT &
"i = " & integer'image(i) &
" div 5 expected " & integer'image(div5) &
" got " & integer'image(to_integer(unsigned(quotient)))
SEVERITY ERROR;
rem5 := i mod 5;
assert rem5 = unsigned(remainder)
report LF & HT &
"i = " & integer'image(i) &
" rem 5 expected " & integer'image(rem5) &
" got " & integer'image(to_integer(unsigned(remainder)))
SEVERITY ERROR;
end if;
end process;
end architecture;
Zaimplementowane tutaj z instrukcją generowania, wewnętrzną instrukcją generowania produkującą bity ilorazowe. Pozostała tablica zapewnia śledzenie przejścia stanu:
Wszystko bez operacji arytmetycznej.
Możliwe jest również wdrożenie w procedurze bez wykorzystywania przez wszystkie rejestry parametrów bez trybu. To zbliży się do minimalnej liczby linii na rozmowę kwalifikacyjną.
Taktowana sekwencyjna implementacja wymagałaby nieco licznika i kontroli przepływu (przerzutnik JK i kilka bramek).
Kompromis czas / złożoność zależy od wielkości dywidendy, której prawdopodobnie będziesz musiał bronić podczas wywiadu.