wiki:UnconventionalHDLProgramming

Version 4 (modified by nakasato, 14 years ago) (diff)

--

eRubyによVHDLメタプログラミングの実例

説明

まとめ:行数の比較

行数 コメント
class定義 32行  
erbソース 181行
VHDL 337行

FP加算器のclass定義

class FPadd < FPop
  def initialize(nf = 32, nm = 23)
    super(nf, nm, 4)
    @narg = 3
    @name = gen_name(:add)

    @nadder = nm + 1 + 3 + 1
    @swap   = addcomponent Swap.new(nf)
    @rshift = addcomponent Rshift.new(nm+1,@nexp+1)
    @sbit   = addcomponent Extractsbit.new(nm+1, @nexp+1)

    @sadd   = addcomponent INTsadder.new(@nadder+1) ## 2
    @test   = addcomponent FPaddtest.new(nf, nm, @nadder) ## 1
    @uflow  = addcomponent Underflow.new(@nman+1,@nexp)

    @delay1 = addcomponent(Delay.new(1,2))
    @delay2 = addcomponent(Delay.new(@nexp,2))

    @delay3 = addcomponent(Delay.new(1,3))
    @delay4 = addcomponent(Delay.new(@nexp,3))
    @delay5 = addcomponent(Delay.new(@nexp+1,3))
    if @nexp == @nman then
      @delay6 = @delay5
    else
      @delay6 = addcomponent(Delay.new(@nman+1,3))
    end
  end

  def run
    super('float_add.vhd.erb')
  end
end

FP加算器のソース

-------------------------------------------------------------------------------
% defineIO :in,  :x,   @nfloat
% defineIO :in,  :y,   @nfloat
% defineIO :out, :z,   @nfloat
% defineIO :in,  :clk, 1
-------------------------------------------------------------------------------
% nfloat = @nfloat
% nman = @nman
% nexp = @nexp
%
% width_nf = "#{nfloat-1} downto 0"
% width_nm = "#{nman-1} downto 0"
% width_ne = "#{nexp-1} downto 0"
-------------------------------------------------------------------------------
<%= generate_header %>

<%= generate_entity %>

architecture source of <%= @name %> is

<%= generate_components %>

signal signz,sz : std_logic;
signal manz,mz : std_logic_vector(<%= nman %> downto 0);
signal expz,ez : std_logic_vector(<%= width_ne %>);
signal ex0, ey0            : std_logic_vector(<%= nexp %> downto 0);

signal xx, yy : std_logic_vector(<%= width_nf %>);
signal sx, sy : std_logic;
signal mx, my : std_logic_vector(<%= nman %> downto 0);
signal ex, ey : std_logic_vector(<%= width_ne %>);

signal dx   : std_logic_vector(<%= nexp %> downto 0);
signal dy   : std_logic_vector(<%= nexp %> downto 0);
signal diff : std_logic_vector(<%= nexp %> downto 0);

--
signal res0   : std_logic_vector(<%= nman %> downto 0);
signal expz0  : std_logic_vector(<%= width_ne %>);
signal signz0 : std_logic;
signal ulp0, rbit0, sbit0 : std_logic;

signal res1   : std_logic_vector(<%= nman %> downto 0);
signal expz1  : std_logic_vector(<%= width_ne %>);
signal signz1 : std_logic;
signal ulp1, rbit1, sbit1 : std_logic;

--
signal o1 : std_logic_vector(<%= @nadder - 1 %> downto 0);
signal o2 : std_logic_vector(<%= @nadder - 1 %> downto 0);
signal r1, r2, r3 : std_logic;

signal a0, a1 : std_logic_vector(<%= @nadder %> downto 0);
signal b0, b1 : std_logic_vector(<%= @nadder %> downto 0);
signal res : std_logic_vector(<%= @nadder %> downto 0);
signal resn : std_logic_vector(<%= @nadder %> downto 0);

signal zf   : std_logic;

--
signal dd : std_logic_vector(<%= nexp + 1 %> downto 0);
signal d0 : std_logic_vector(<%= nexp + 1 %> downto 0);
signal manzz : std_logic_vector(<%= nman %> downto 0);
signal expzz : std_logic_vector(<%= width_ne %>);
signal ulp, rbit, sbit : std_logic;

signal zz : std_logic_vector(<%= width_nf %>);

signal expz0_reg   : std_logic_vector(<%= width_ne %>);
signal expz0_regg  : std_logic_vector(<%= width_ne %>);
signal r1_reg, r2_reg, r3_reg : std_logic;
signal diff_reg : std_logic_vector(<%= nexp %> downto 0);
signal res0_reg   : std_logic_vector(<%= nman %> downto 0);
signal signz0_reg : std_logic;
signal signz1_reg : std_logic;
signal ulp0_reg, rbit0_reg, sbit0_reg : std_logic;
signal zf_reg : std_logic;

begin
  ex0 <= '0'&x(<%= nfloat - 2 %> downto <%= nman %>);
  ey0 <= '0'&y(<%= nfloat - 2 %> downto <%= nman %>);

  dx <= ex0 - ey0;
  dy <= ey0 - ex0;

-- swap
  s0 : <%= @swap %> port map ( f => dx(<%= nexp %>), x => x, y => y, xs => xx, ys => yy);

  with dx(<%= nexp %>) select
    diff <= dy when '1',
            dx when others;

  e0 : <%= @fextract %> port map ( x => xx, s => sx, m => mx, e => ex);
  e1 : <%= @fextract %> port map ( x => yy, s => sy, m => my, e => ey);

--------------------------------------------------------------------
-- if diff > <%= nman + 1 %>
  res0 <= mx;
  expz0  <= ex;
  signz0 <= sx;
  ulp0  <= res0(0);
  rbit0 <= '0';
  sbit0 <= '1';
-- else
-- o1
  o1 <= "00"&mx&"00";

-- o2
  shift0 : <%= @rshift %> port map (c => diff, i => my, o => o2);

  r1 <= o2(1);
  r2 <= o2(0);

-- r3
  sb0 : <%= @sbit %> port map (c => diff, i => my, s => r3);

----
  a0 <= o1(<%= @nadder - 1 %> downto 0)&'0';
  b0 <= o2(<%= @nadder - 1 %> downto 0)&r3;

--
  add: <%= @sadd %> port map (x => a0, sx => sx, y => b0, sy => sy,
                              z => resn, sz => signz1, clk => clk);

  d1 : <%= @delay1 %> port map (i => r1, o => r1_reg, clk => clk);
  d2 : <%= @delay1 %> port map (i => r2, o => r2_reg, clk => clk);
  d3 : <%= @delay1 %> port map (i => r3, o => r3_reg, clk => clk);
  d4 : <%= @delay2 %> port map (i => expz0, o => expz0_reg, clk => clk);

-- flag zf if res == 0
  with resn select
    zf <= '1' when "<%= 0.to_b(@nadder+1) %>",
          '0' when others;
----
  f0 : <%= @test %> port map ( tmp => resn(<%= @nadder - 1 %> downto 0),
                               exp => expz0_reg, r1 => r1_reg, r2 => r2_reg, r3 => r3_reg,
                               res => res1, expz => expz1, ulp => ulp1, rbit => rbit1, sbit => sbit1, clk => clk);

  process(clk) begin
   if(clk'event and clk='1') then
     signz1_reg <= signz1;
     zf_reg <= zf;
   end if;
  end process;

--sadd 2   signz1, resn
--test 3   res1, expz1, ulp1, rbit1, sbit1

  d5  : <%= @delay3 %> port map (i => signz0, o => signz0_reg, clk => clk);
  d6  : <%= @delay3 %> port map (i => ulp0,  o => ulp0_reg, clk => clk);
  d7  : <%= @delay3 %> port map (i => rbit0, o => rbit0_reg, clk => clk);
  d8  : <%= @delay3 %> port map (i => sbit0, o => sbit0_reg, clk => clk);
  d9  : <%= @delay4 %> port map (i => expz0, o => expz0_regg, clk => clk);
  d10 : <%= @delay5 %> port map (i => diff, o => diff_reg, clk => clk);
  d11 : <%= @delay6 %> port map (i => res0, o => res0_reg, clk => clk);

--------------------------------------------------------------------
  d0 <= '0'&diff_reg;
  dd <= "<%= (nman + 1).to_b(nexp+1) %>" - d0;

  uf : <%= @uflow %> port map (f => dd(<%= nexp %>),
                               m1 => res0_reg, e1 => expz0_regg, u1 => ulp0_reg, r1 => rbit0_reg, s1 => sbit0_reg,
                               m2 => res1,     e2 => expz1,      u2 => ulp1,     r2 => rbit1,     s2 => sbit1,
                               m => manzz, e => expzz, u => ulp, r => rbit, s => sbit );

  with dd(<%= nexp %>) select
    signz <= signz0_reg when '1',
             signz1_reg when others;

  r0 : <%= @frounding %> port map ( m => manzz, e => expzz, u => ulp, r => rbit, s => sbit,
                                   mout => manz, eout=> expz);

  with zf_reg select
    sz <= signz when '0',
          '0' when others;

  with zf_reg select
    mz <= manz when '0',
          "<%= 0.to_b(@nman+1) %>" when others;

  with zf_reg select
    ez <= expz when '0',
          "<%= 0.to_b(@nexp) %>" when others;

  c0 : <%= @fcompose %> port map (s => sz, m => mz, e => ez, z => z, clk => clk);
end source;
-------------------------------------------------------------------------------
<%= generate_components_body %>
-------------------------------------------------------------------------------

生成結果(単精度相当)

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;


entity fp_add_32_23_8_4 is
  port (
    x : in std_logic_vector(31 downto 0);
    y : in std_logic_vector(31 downto 0);
    z : out std_logic_vector(31 downto 0);
    clk : in std_logic
  );
end fp_add_32_23_8_4;


architecture source of fp_add_32_23_8_4 is

component extract_32_23_8
  port (
    x : in std_logic_vector(31 downto 0);
    s : out std_logic;
    m : out std_logic_vector(23 downto 0);
    e : out std_logic_vector(7 downto 0)
  );
end component;

component rounding_32_23_8
  port (
    m : in std_logic_vector(23 downto 0);
    e : in std_logic_vector(7 downto 0);
    u : in std_logic;
    r : in std_logic;
    s : in std_logic;
    mout : out std_logic_vector(23 downto 0);
    eout : out std_logic_vector(7 downto 0)
  );
end component;

component compose_32_23_8
  port (
    s : in std_logic;
    m : in std_logic_vector(23 downto 0);
    e : in std_logic_vector(7 downto 0);
    z : out std_logic_vector(31 downto 0);
    clk : in std_logic
  );
end component;

component swap_32
  port (
    f : in std_logic;
    x : in std_logic_vector(31 downto 0);
    y : in std_logic_vector(31 downto 0);
    xs : out std_logic_vector(31 downto 0);
    ys : out std_logic_vector(31 downto 0)
  );
end component;

component int_rshift_24_9_0
  port (
    c : in std_logic_vector(8 downto 0);
    i : in std_logic_vector(23 downto 0);
    o : out std_logic_vector(27 downto 0)
  );
end component;

component int_extractsbit_24_9_0
  port (
    c : in std_logic_vector(8 downto 0);
    i : in std_logic_vector(23 downto 0);
    s : out std_logic
  );
end component;

component int_sadder_29_2
  port (
    x : in std_logic_vector(28 downto 0);
    sx : in std_logic;
    y : in std_logic_vector(28 downto 0);
    sy : in std_logic;
    z : out std_logic_vector(28 downto 0);
    sz : out std_logic;
    clk : in std_logic
  );
end component;

component fp_addtest_32_23_8_0
  port (
    tmp : in std_logic_vector(27 downto 0);
    exp : in std_logic_vector(7 downto 0);
    r1 : in std_logic;
    r2 : in std_logic;
    r3 : in std_logic;
    res : out std_logic_vector(23 downto 0);
    expz : out std_logic_vector(7 downto 0);
    ulp : out std_logic;
    rbit : out std_logic;
    sbit : out std_logic;
    clk : in std_logic
  );
end component;

component underflow_24_8
  port (
    f : in std_logic;
    m1 : in std_logic_vector(23 downto 0);
    e1 : in std_logic_vector(7 downto 0);
    u1 : in std_logic;
    r1 : in std_logic;
    s1 : in std_logic;
    m2 : in std_logic_vector(23 downto 0);
    e2 : in std_logic_vector(7 downto 0);
    u2 : in std_logic;
    r2 : in std_logic;
    s2 : in std_logic;
    m : out std_logic_vector(23 downto 0);
    e : out std_logic_vector(7 downto 0);
    u : out std_logic;
    r : out std_logic;
    s : out std_logic
  );
end component;

component delay_1_2
  port (
    i : in std_logic;
    o : out std_logic;
    clk : in std_logic
  );
end component;

component delay_8_2
  port (
    i : in std_logic_vector(7 downto 0);
    o : out std_logic_vector(7 downto 0);
    clk : in std_logic
  );
end component;

component delay_1_3
  port (
    i : in std_logic;
    o : out std_logic;
    clk : in std_logic
  );
end component;

component delay_8_3
  port (
    i : in std_logic_vector(7 downto 0);
    o : out std_logic_vector(7 downto 0);
    clk : in std_logic
  );
end component;

component delay_9_3
  port (
    i : in std_logic_vector(8 downto 0);
    o : out std_logic_vector(8 downto 0);
    clk : in std_logic
  );
end component;

component delay_24_3
  port (
    i : in std_logic_vector(23 downto 0);
    o : out std_logic_vector(23 downto 0);
    clk : in std_logic
  );
end component;



signal signz,sz : std_logic;
signal manz,mz : std_logic_vector(23 downto 0);
signal expz,ez : std_logic_vector(7 downto 0);
signal ex0, ey0            : std_logic_vector(8 downto 0);

signal xx, yy : std_logic_vector(31 downto 0);
signal sx, sy : std_logic;
signal mx, my : std_logic_vector(23 downto 0);
signal ex, ey : std_logic_vector(7 downto 0);

signal dx   : std_logic_vector(8 downto 0);
signal dy   : std_logic_vector(8 downto 0);
signal diff : std_logic_vector(8 downto 0);

--
signal res0   : std_logic_vector(23 downto 0);
signal expz0  : std_logic_vector(7 downto 0);
signal signz0 : std_logic;
signal ulp0, rbit0, sbit0 : std_logic;

signal res1   : std_logic_vector(23 downto 0);
signal expz1  : std_logic_vector(7 downto 0);
signal signz1 : std_logic;
signal ulp1, rbit1, sbit1 : std_logic;

--
signal o1 : std_logic_vector(27 downto 0);
signal o2 : std_logic_vector(27 downto 0);
signal r1, r2, r3 : std_logic;

signal a0, a1 : std_logic_vector(28 downto 0);
signal b0, b1 : std_logic_vector(28 downto 0);
signal res : std_logic_vector(28 downto 0);
signal resn : std_logic_vector(28 downto 0);

signal zf   : std_logic;

--
signal dd : std_logic_vector(9 downto 0);
signal d0 : std_logic_vector(9 downto 0);
signal manzz : std_logic_vector(23 downto 0);
signal expzz : std_logic_vector(7 downto 0);
signal ulp, rbit, sbit : std_logic;

signal zz : std_logic_vector(31 downto 0);

signal expz0_reg   : std_logic_vector(7 downto 0);
signal expz0_regg  : std_logic_vector(7 downto 0);
signal r1_reg, r2_reg, r3_reg : std_logic;
signal diff_reg : std_logic_vector(8 downto 0);
signal res0_reg   : std_logic_vector(23 downto 0);
signal signz0_reg : std_logic;
signal signz1_reg : std_logic;
signal ulp0_reg, rbit0_reg, sbit0_reg : std_logic;
signal zf_reg : std_logic;

begin
  ex0 <= '0'&x(30 downto 23);
  ey0 <= '0'&y(30 downto 23);

  dx <= ex0 - ey0;
  dy <= ey0 - ex0;

-- swap 
  s0 : swap_32 port map ( f => dx(8), x => x, y => y, xs => xx, ys => yy);

  with dx(8) select
    diff <= dy when '1', 
            dx when others;

  e0 : extract_32_23_8 port map ( x => xx, s => sx, m => mx, e => ex);
  e1 : extract_32_23_8 port map ( x => yy, s => sy, m => my, e => ey);

--------------------------------------------------------------------
-- if diff > 24
  res0 <= mx;
  expz0  <= ex;
  signz0 <= sx;
  ulp0  <= res0(0);
  rbit0 <= '0';
  sbit0 <= '1';
-- else
-- o1
  o1 <= "00"&mx&"00";

-- o2
  shift0 : int_rshift_24_9_0 port map (c => diff, i => my, o => o2);

  r1 <= o2(1);
  r2 <= o2(0);	

-- r3
  sb0 : int_extractsbit_24_9_0 port map (c => diff, i => my, s => r3);  

----
  a0 <= o1(27 downto 0)&'0';
  b0 <= o2(27 downto 0)&r3;

--
  add: int_sadder_29_2 port map (x => a0, sx => sx, y => b0, sy => sy, 
                              z => resn, sz => signz1, clk => clk);

  d1 : delay_1_2 port map (i => r1, o => r1_reg, clk => clk); 
  d2 : delay_1_2 port map (i => r2, o => r2_reg, clk => clk); 
  d3 : delay_1_2 port map (i => r3, o => r3_reg, clk => clk); 
  d4 : delay_8_2 port map (i => expz0, o => expz0_reg, clk => clk); 

-- flag zf if res == 0
  with resn select
    zf <= '1' when "00000000000000000000000000000", 
          '0' when others;
----
  f0 : fp_addtest_32_23_8_0 port map ( tmp => resn(27 downto 0),
                               exp => expz0_reg, r1 => r1_reg, r2 => r2_reg, r3 => r3_reg,
                               res => res1, expz => expz1, ulp => ulp1, rbit => rbit1, sbit => sbit1, clk => clk);

  process(clk) begin
   if(clk'event and clk='1') then
     signz1_reg <= signz1;
     zf_reg <= zf;
   end if;
  end process;

--sadd 2   signz1, resn
--test 3   res1, expz1, ulp1, rbit1, sbit1

  d5  : delay_1_3 port map (i => signz0, o => signz0_reg, clk => clk); 
  d6  : delay_1_3 port map (i => ulp0,  o => ulp0_reg, clk => clk); 
  d7  : delay_1_3 port map (i => rbit0, o => rbit0_reg, clk => clk); 
  d8  : delay_1_3 port map (i => sbit0, o => sbit0_reg, clk => clk); 
  d9  : delay_8_3 port map (i => expz0, o => expz0_regg, clk => clk); 
  d10 : delay_9_3 port map (i => diff, o => diff_reg, clk => clk); 
  d11 : delay_24_3 port map (i => res0, o => res0_reg, clk => clk); 

--------------------------------------------------------------------
  d0 <= '0'&diff_reg;
  dd <= "000011000" - d0;

  uf : underflow_24_8 port map (f => dd(8),
                               m1 => res0_reg, e1 => expz0_regg, u1 => ulp0_reg, r1 => rbit0_reg, s1 => sbit0_reg,
                               m2 => res1,     e2 => expz1,      u2 => ulp1,     r2 => rbit1,     s2 => sbit1,
                               m => manzz, e => expzz, u => ulp, r => rbit, s => sbit );

  with dd(8) select
    signz <= signz0_reg when '1', 
             signz1_reg when others;
  
  r0 : rounding_32_23_8 port map ( m => manzz, e => expzz, u => ulp, r => rbit, s => sbit,
               	                   mout => manz, eout=> expz);

  with zf_reg select
    sz <= signz when '0',
          '0' when others;

  with zf_reg select
    mz <= manz when '0',
          "000000000000000000000000" when others;

  with zf_reg select
    ez <= expz when '0',
          "00000000" when others;

  c0 : compose_32_23_8 port map (s => sz, m => mz, e => ez, z => z, clk => clk); 
end source;

エミュレーションコードの生成

そのうち載せる。