VHDL 인터뷰 질문으로 인해 VHDL 코드가 생성됩니다.
나는 ghdl의 저자가 17 줄의 함수로 구현을 증류시킨 Dave Tweed의 상태 전이 테이블의 구현 으로 ghdl llvm 백엔드 버그를 찾을 수있었습니다 .
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;
관련된 테스트 사례는 매우 작아 디버깅이 쉬우 며 열거 유형의 VHDL과 호환되는 상태 이름을 사용합니다.
(디아와 함께 만든)
여기서 아이디어는 함수 (또는 27 줄의 예제 VHDL 프로그램)가 인터뷰 중에 VHDL 답변을 작성하기에 충분히 짧다는 것입니다. 지식과 기술을 모두 요구하는 인터뷰 질문을 망칠 염려가 없어도, 인터뷰 대상자는 질문이있을 때 구현을 방어해야합니다.
(llvm 백엔드 버그는 오늘 일찍 커밋 1f5df6e 에서 수정되었습니다 .)
주의해야 할 사항 중 하나는 상태 전이 테이블에서 몫 비트가 피제수에서 5를 뺄 때 나머지 값이 더 낮은 상태 (또는 r4에 대한 두 전이) 로의 전환으로 표시되는 몫 비트가 '1'인 위치를 알려줍니다. 별도의 테이블 (또는 번거로운 레코드 유형의 테이블)로 인코딩 할 수 있습니다. 우리는 역사적으로 5 픽셀의 배수 인 수평 화면 해상도를 다루는 그래픽 하드웨어에서이 작업을 수행합니다.
그렇게하면 몫과 나머지를 생성하는 div / mod5가 제공됩니다.
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;
몫 비트를 생성하는 내부 생성 문인 generate 문으로 구현되었습니다. 나머지 배열은 상태 전이 추적을 제공합니다.
모든 산술 연산이 없습니다.
모든 레지스터가 모드가없는 상태에서 매개 변수를 사용하지 않고 절차에서 구현할 수도 있습니다. 그것은 인터뷰를 위해 최소한의 줄에 접근합니다.
클럭 순차 구현에는 비트 카운터 및 흐름 제어 (JK 플립 플롭 및 몇 개의 게이트)가 필요합니다.
인터뷰에서 방어해야 할 배당 규모에 따라 시간 / 복잡성 트레이드 오프가 발생합니다.