Znow troche za szybko

Jun 25, 2005 13 Replies

Witam,



właśnie skończyłem pisać w VHDL generator zawartości Sboxów do algorytmu kryptograficznego AES. Jest on złożony z 9-stopniowego potoku i zajmuje 160 LE. Wszystkie działania teoretycznie są wykonywane w ciele Galois GF(2^8), a tak naprawdę w izomorficznym z nim ciele złożonym GF(2^4)^2, co dzięki paru sztuczkom algebraicznym pozwoliło 4-krotnie zmniejszyć układ. Dodawanie to xor, więc spodziewałem się że układ będzie dość szybki, ale przy docelowym układzie Cyclone



1C3-6 Timing Analyzer Quartusa 5.0 zwraca mi szokującą informację, że:

"Info: Clock "clk" has Internal fmax of 398.09 MHz between source register "SBOX_Generator:inst|d_latch:X11|r[2]" and destination register "SBOX_Generator:inst|gf24_multiply:X21|a2[0]" (period= 2.512 ns) Info: + Longest register to register delay is 2.310 ns"



Przecież to fizycznie niemożliwe. :-) BTW, w symulatorze wszystko działa wprost modelowo, więc na pewno nie zapomniałem podłączyć zegara do układu.



Pozdrawiam Piotr Wyderski


Trochę poprawiłem wskazaną ścieżkę krytyczną i dostałem:

"Info: Clock "clk" Internal fmax is restricted to 405.19 MHz between source register "SBOX_Generator:inst|d_latch:X11|r[1]" and destination register "SBOX_Generator:inst|gf24_multiply:X21|a2[1]" Info: fmax restricted to Clock High delay (1.234 ns) plus Clock Low delay (1.234 ns) : restricted to 2.468 ns. Expand message to see actual delay path. Info: + Longest register to register delay is 2.052 ns"

Hmm, przecież to o 2,2MHz szybciej, niż tak kość ma fmax w datasheecie... :-/ Ale działa... Co tu jest grane? :-)

(...)

ciach

Z kiciorem, grypserze...! ;)))

Kristo

no nie, troche ci ten wynik za duzy wyszedl.. no ale w 1C6-8 wychodzily mi po 5..7ns dla dosyc glebokich ukladow kombinacyjnych.. wiec skoro masz wersje -6 to bedzie troche wiecej.. a czy ustawiles wobec czego ma analyser liczyc ten czas? posprawdzaj czasy dla wszystkich kombinacji wejsc/wyjsc..gdzies powinna byc taka opcja.. wtedy juz nei jest tak rozowo:)

Greg wrote:

"Trochê"... :-> To ju¿ drugi raz. Wówczas (256MHz) pyta³em o to samo i kazali¶cie mi wierzyæ Quartusowi. To teraz sami mu wierzcie. :->

Jak to wzglêdem czego?

Ten uk³ad praktycznie nie ma wej¶æ (tj. ma reset i taktowanie), sam sobie generuje wektory "wej¶ciowe" i je nastêpnie transformuje. Poni¿ej za³±czam kod w wersji mocno beta -- na symulatorze dzia³a doskonale, wiêc chyba niczego nie zapomnia³em pod³±czyæ. Poniewa¿ VHDL w sumie siê dopiero uczê, proszê wskazaæ, co zrobi³em ¼le (oprócz zapisu tego uk³adu licz±cego odwrotno¶æ multiplikatywn± w GF(2^8)-- to w ogóle da siê czytelnie zapisaæ?).

Pozdrawiam Piotr Wyderski

---------------8<----------------------

-- WARNING: Do NOT edit the input and output ports in this file in a text

-- editor if you plan to continue editing the block that represents it in

-- the Block Editor! File corruption is VERY likely to occur.

-- Copyright (C) 1991-2005 Altera Corporation

-- Your use of Altera Corporation's design tools, logic functions

-- and other software and tools, and its AMPP partner logic

-- functions, and any output files any of the foregoing

-- (including device programming or simulation files), and any

-- associated documentation or information are expressly subject

-- to the terms and conditions of the Altera Program License

-- Subscription Agreement, Altera MegaCore Function License

-- Agreement, or other applicable license agreement, including,

-- without limitation, that your use is for the sole purpose of

-- programming logic devices manufactured by Altera and sold by

-- Altera or its authorized distributors. Please refer to the

-- applicable agreement for further details.

-- Generated by Quartus II Version 5.0 (Build Build 148 04/26/2005)

-- Created on Sat Jun 25 16:28:37 2005

library ieee; use ieee.std_logic_1164.all;

entity d_latch is

generic (

N : positive );

port (

clk : in std_logic; v : in std_logic_vector(N-1 downto 0); r : out std_logic_vector(N-1 downto 0) );

end d_latch;

-- -------------------

architecture implementation of d_latch is

-- This block latches N bits of information

begin

process(clk, v) is begin

if rising_edge(clk) then r <= v; end if; end process; end implementation;

-- -------------------

library ieee; use ieee.std_logic_1164.all;

entity gf24_square is

port (

v : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0) );

end gf24_square;

-- -------------------

architecture implementation of gf24_square is

-- This block computes the value of v^2 in GF(2^4)

begin

process(v) is begin

case v is

when "0000" => r <= "0000"; when "0001" => r <= "0001"; when "0010" => r <= "0100"; when "0011" => r <= "0101"; when "0100" => r <= "0011"; when "0101" => r <= "0010"; when "0110" => r <= "0111"; when "0111" => r <= "0110"; when "1000" => r <= "1100"; when "1001" => r <= "1101"; when "1010" => r <= "1000"; when "1011" => r <= "1001"; when "1100" => r <= "1111"; when "1101" => r <= "1110"; when "1110" => r <= "1011"; when "1111" => r <= "1010";

end case; end process; end implementation;

-- -------------------

library ieee; use ieee.std_logic_1164.all;

entity gf24_inverse is

port (

v : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0) );

end gf24_inverse;

-- -------------------

architecture implementation of gf24_inverse is

-- This block computes the value of v^(-1) in GF(2^4)

begin

process(v) is begin

case v is

when "0000" => r <= "0000"; when "0001" => r <= "0001"; when "0010" => r <= "1001"; when "0011" => r <= "1110"; when "0100" => r <= "1101"; when "0101" => r <= "1011"; when "0110" => r <= "0111"; when "0111" => r <= "0110"; when "1000" => r <= "1111"; when "1001" => r <= "0010"; when "1010" => r <= "1100"; when "1011" => r <= "0101"; when "1100" => r <= "1010"; when "1101" => r <= "0100"; when "1110" => r <= "0011"; when "1111" => r <= "1000";

end case; end process; end implementation;

-- -------------------

library ieee; use ieee.std_logic_1164.all;

entity gf28_to_gf24 is

port (

v : in std_logic_vector(7 downto 0); r : out std_logic_vector(7 downto 0) );

end gf28_to_gf24;

-- -------------------

architecture implementation of gf28_to_gf24 is

-- This block transforms a given v from GF(2^8) into GF(2^4)^2

begin

-- Map an element from GF(2^8) into GF(2^4)^2

-- using the following transformation matrix

--

-- | 1 0 1 0 0 0 0 0 |

-- | 1 0 1 0 1 1 0 0 |

-- | 1 1 0 1 0 0 1 0 |

-- r = | 0 1 1 1 0 0 0 0 | * v

-- | 0 0 0 1 1 0 0 0 |

-- | 1 1 1 1 1 1 0 0 |

-- | 0 0 0 0 0 1 0 0 |

-- | 1 0 1 0 0 0 0 1 |

r(7) <= v(7) xor v(5); r(6) <= v(7) xor v(5) xor v(3) xor v(2); r(5) <= v(7) xor v(6) xor v(4) xor v(1); r(4) <= v(6) xor v(5) xor v(4); r(3) <= v(4) xor v(3); r(2) <= v(7) xor v(6) xor v(5) xor v(4) xor v(3) xor v(2); r(1) <= v(2); r(0) <= v(7) xor v(5) xor v(0);

end implementation;

-- -------------------

library ieee; use ieee.std_logic_1164.all;

entity gf24_to_gf28 is

port (

v : in std_logic_vector(7 downto 0); r : out std_logic_vector(7 downto 0) );

end gf24_to_gf28;

-- -------------------

architecture implementation of gf24_to_gf28 is

-- This block transforms a given v from GF(2^4)^2 into GF(2^8)

begin

-- Map an element from GF(2^4)^2 into GF(2^8)

-- using the following transformation matrix

--

-- | 1 1 0 1 0 1 0 0 |

-- | 1 0 0 0 1 1 1 0 |

-- | 0 1 0 1 0 1 0 0 |

-- r = | 1 1 0 0 1 0 1 0 | * v

-- | 1 1 0 0 0 0 1 0 |

-- | 0 0 0 0 0 0 1 0 |

-- | 1 0 1 1 0 0 0 0 |

-- | 1 0 0 0 0 0 0 1 |

r(7) <= v(7) xor v(6) xor v(4) xor v(2); r(6) <= v(7) xor v(3) xor v(2) xor v(1); r(5) <= v(6) xor v(4) xor v(2); r(4) <= v(7) xor v(6) xor v(3) xor v(1); r(3) <= v(7) xor v(6) xor v(1); r(2) <= v(1); r(1) <= v(7) xor v(5) xor v(4); r(0) <= v(7) xor v(0);

end implementation;

-- -------------------

library ieee; use ieee.std_logic_1164.all;

entity gf24_multiply is

port (

clk : in std_logic; x, y : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0) );

end gf24_multiply;

-- -------------------

architecture implementation of gf24_multiply is

-- This block multiplies a and b in GF(2^4)

begin

process(clk, x, y) is

variable a1, b1, c1 : std_logic_vector(3 downto 0); variable a2, b2, c2 : std_logic_vector(3 downto 0); variable a3, b3, c3 : std_logic_vector(3 downto 0);

begin

if rising_edge(clk) then

r <= a3 xor (b3 and (b3'range => c3(0)));

a3 := a2 xor (b2 and (c2'range => c2(0))); b3 := (b2(2 downto 0) & "0") xor ("0011" and (b2'range => b2(3))); c3 := "0" & c2(3 downto 1);

a1 := y and (x'range => x(0)); b1 := (y(2 downto 0) & "0") xor ("0011" and (y'range => y(3))); c1 := "0" & x(3 downto 1);

a2 := a1 xor (b1 and (c1'range => c1(0))); b2 := (b1(2 downto 0) & "0") xor ("0011" and (b1'range => b1(3))); c2 := "0" & c1(3 downto 1);

end if; end process; end implementation;

-- -------------------

library ieee; use ieee.std_logic_1164.all;

entity gf24_multiply_by_8 is

port (

v : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0) );

end gf24_multiply_by_8;

-- -------------------

architecture implementation of gf24_multiply_by_8 is

-- This block computes the value of v*8 in GF(2^4)

begin

process(v) is begin

case v is

when "0000" => r <= "0000"; when "0001" => r <= "1000"; when "0010" => r <= "0011"; when "0011" => r <= "1011"; when "0100" => r <= "0110"; when "0101" => r <= "1110"; when "0110" => r <= "0101"; when "0111" => r <= "1101"; when "1000" => r <= "1100"; when "1001" => r <= "0100"; when "1010" => r <= "1111"; when "1011" => r <= "0111"; when "1100" => r <= "1010"; when "1101" => r <= "0010"; when "1110" => r <= "1001"; when "1111" => r <= "0001";

end case; end process; end implementation;

-- -------------------

library ieee; use ieee.std_logic_1164.all;

entity sbox_affine_transform is

port (

v : in std_logic_vector(7 downto 0); r : out std_logic_vector(7 downto 0) );

end sbox_affine_transform;

-- -------------------

architecture implementation of sbox_affine_transform is

-- This block transforms a given multiplicative

-- inverse element v from GF(2^8) into a valid

-- AES sbox output

begin

-- Transform a given inverse element using the following affine mapping

--

-- | 1 1 1 1 1 0 0 0 | | 0 |

-- | 0 1 1 1 1 1 0 0 | | 1 |

-- | 0 0 1 1 1 1 1 0 | | 1 |

-- r = | 0 0 0 1 1 1 1 1 | * v + | 0 |

-- | 1 0 0 0 1 1 1 1 | | 0 |

-- | 1 1 0 0 0 1 1 1 | | 0 |

-- | 1 1 1 0 0 0 1 1 | | 1 |

-- | 1 1 1 1 0 0 0 1 | | 1 |

r(7) <= v(7) xor v(6) xor v(5) xor v(4) xor v(3); r(6) <= v(6) xor v(5) xor v(4) xor v(3) xor v(2) xor '1'; r(5) <= v(5) xor v(4) xor v(3) xor v(2) xor v(1) xor '1'; r(4) <= v(4) xor v(3) xor v(2) xor v(1) xor v(0); r(3) <= v(7) xor v(3) xor v(2) xor v(1) xor v(0); r(2) <= v(7) xor v(6) xor v(2) xor v(1) xor v(0); r(1) <= v(7) xor v(6) xor v(5) xor v(1) xor v(0) xor '1'; r(0) <= v(7) xor v(6) xor v(5) xor v(4) xor v(0) xor '1';

end implementation;

-- -------------------

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

-- Entity Declaration

entity SBOX_Generator is

-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!

port (

clk : in std_logic; mode_select : in std_logic; reset : in std_logic; sbox_index : out std_logic_vector(7 downto 0); sbox_value : out std_logic_vector(7 downto 0); stall : out std_logic );

-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!

end SBOX_Generator;

-- Architecture Body

architecture SBOX_Generator_architecture of SBOX_Generator is

component d_latch is

generic (

N : positive );

port (

clk : in std_logic; v : in std_logic_vector(N-1 downto 0); r : out std_logic_vector(N-1 downto 0) );

end component;

component gf24_square is port (

v : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0)

); end component;

component gf24_inverse is port (

v : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0)

); end component;

component gf24_multiply is port (

clk : in std_logic; x, y : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0)

); end component;

component gf24_multiply_by_8 is port (

v : in std_logic_vector(3 downto 0); r : out std_logic_vector(3 downto 0)

); end component;

component gf28_to_gf24 is port (

v : in std_logic_vector(7 downto 0); r : out std_logic_vector(7 downto 0)

); end component;

component gf24_to_gf28 is port (

v : in std_logic_vector(7 downto 0); r : out std_logic_vector(7 downto 0)

); end component;

component sbox_affine_transform is port (

v : in std_logic_vector(7 downto 0); r : out std_logic_vector(7 downto 0)

); end component;

signal index_generator : std_logic_vector(7 downto 0);

signal s01, s02 : std_logic_vector(7 downto 0); signal b01, c01 : std_logic_vector(3 downto 0); signal b02, c02, d02 : std_logic_vector(3 downto 0); signal b03, c03, d03 : std_logic_vector(3 downto 0); signal b04, c04, d04 : std_logic_vector(3 downto 0); signal b05, c05, d05 : std_logic_vector(3 downto 0); signal b06, c06, d06 : std_logic_vector(3 downto 0); signal b07, c07, d07 : std_logic_vector(3 downto 0); signal b08, c08 : std_logic_vector(3 downto 0); signal b09, c09 : std_logic_vector(3 downto 0); signal b10, c10 : std_logic_vector(3 downto 0); signal b11, c11 : std_logic_vector(3 downto 0); signal b12, c12 : std_logic_vector(3 downto 0); signal v0, v1, v2 : std_logic_vector(7 downto 0);

begin

X00 : gf28_to_gf24 port map (v => index_generator, r => s01); X01 : d_latch generic map (N => 8) port map (v => s01, r(7 downto 4) => b01, r(3 downto 0) => c01, clk => clk); X02 : gf24_square port map (v => b01, r => b02); X03 : gf24_square port map (v => c01, r => c02); X04 : gf24_multiply port map (x => b01, y => c01, r => d02, clk => clk); X05 : d_latch generic map (N => 4) port map (v => b02, r => b03, clk => clk); X06 : d_latch generic map (N => 4) port map (v => c02, r => c03, clk => clk); X07 : gf24_multiply_by_8 port map (v => b03, r => b04); X08 : d_latch generic map (N => 4) port map (v => b04, r => b05, clk => clk); X09 : d_latch generic map (N => 4) port map (v => c03, r => c04, clk => clk); c05 <= b05 xor c04; X10 : d_latch generic map (N => 4) port map (v => c05, r => c06, clk => clk); d03 <= d02 xor c06; X11 : d_latch generic map (N => 4) port map (v => d03, r => d04, clk => clk); X12 : gf24_inverse port map (v => d04, r => d05); c07 <= c01 xor b01; X13 : d_latch generic map (N => 4) port map (v => c07, r => c08, clk => clk); X14 : d_latch generic map (N => 4) port map (v => b01, r => b08, clk => clk); X15 : d_latch generic map (N => 4) port map (v => c08, r => c09, clk => clk); X16 : d_latch generic map (N => 4) port map (v => b08, r => b09, clk => clk); X17 : d_latch generic map (N => 4) port map (v => c09, r => c10, clk => clk); X18 : d_latch generic map (N => 4) port map (v => b09, r => b10, clk => clk); X19 : d_latch generic map (N => 4) port map (v => c10, r => c11, clk => clk); X20 : d_latch generic map (N => 4) port map (v => b10, r => b11, clk => clk); X21 : gf24_multiply port map (x => d05, y => b11, r => d06, clk => clk); X22 : gf24_multiply port map (x => d05, y => c11, r => d07, clk => clk); X23 : gf24_to_gf28 port map (v(7 downto 4) => d06, v(3 downto 0) => d07, r => v0); X24 : d_latch generic map (N => 8) port map (v => v0, r => v1, clk => clk); -- v1 = the multiplicative inverse X26 : sbox_affine_transform port map (v => v1, r => v2);

process(clk, reset, mode_select) is begin

if reset = '0' then

index_generator <= "00000000";

elsif rising_edge(clk) then

index_generator <= index_generator + 1;

end if; end process;

sbox_value <= v2; sbox_index <= index_generator + "11110111";

end SBOX_Generator_architecture;

Ustawi³em teraz w symulatorze okres zegara na 2,5ns i wyniki dalej s± poprawne, tylko wynik symulacji wygl±da do¶æ zabawnie przed ostatnim latchem -- przez prawie ca³y czas na wyj¶ciu panuje stan nieustalony, uk³ad nie mo¿e zdecydowaæ siê na podanie w³a¶ciwego wyniku. Jednak o w³os przed up³ywem timeoutu nagle wyskakuje jak zaj±c w³a¶ciwa odpowied¼. :-)

Po latchu wszystko jest oczywi¶cie bardzo ³adne. ;-)

Pozdrawiam Piotr Wyderski

Siê garowa³o na algebrze, to siê ma bajerê skrañcowan±. ;-)))

Pozdrawiam Piotr Wyderski

Temperature ustaw inna :-)

W zasadzie co sie dziwic ze proste operacje w pipeline daja taki szybki szyfrator ? I tak nie podasz danych wystarczajaco szybko :-)

J.

Nie szyfrator, tylko jego fragment. A co do zdziwienia, to ja rozumiem 200 MHz, nad 300 MHz bym siê zastanawia³, czy to naprawdê dzia³a, a tu dosta³em 405 MHz. :-)

Ten uk³ad nie do tego s³u¿y.

Pozdrawiam Piotr Wyderski

"Piotr Wyderski":

[...]

timing analizer po prostu liczy opoznienia, czy tez propagacje sygnalu miedzy wyjsciem Q FF, a wejsciem D nastepnego FF i na podstawie maksymalnego czasu podaje maksymalna czestotliwosc zegara; to, ze fpga 'sama z siebie' ma inna max. zegara to zupelnie inna sprawa :) nadal uwazam, ze analizator czasowy quartusa jest godny zaufania, i jesli uklad dziala w symulatorze, to bedzie dzialal w rzeczywistosci, pod warunkiem nie przekroczenia maksymalnej czestotliwosci zegara dla danej rodziny fpga;

JA

I chyba masz rację: przeniosłem ten kod na ProASIC+ Actela i analizator z pakietu Libero daje mu 178MHz, rónież prawie na styk z teoretyczną wydajnością kości APA075. Widać rzeczywiście grunt to dobry algorytm, a ja chyba zaczynam być dobry w te klocki. ;->

Pozdrawiam Piotr Wyderski

"Piotr Wyderski":

[,,,]

nie watpie :) jedna z oznak 'bycia dobrym' jest zauwazenie, ze ' if else' jest bardzo niewydajne w hardware, a zagniezdzonie 'if - else if' to juz tragedia; 'case' sobie radzi znacznie lepiej w takich przypadkach;

JA

Wszystko prawda. Tylko ze Twoj uklad jest teraz bezuzyteczny... Dolozysz mu wejscia/wyjscia, cos tam jeszcze, w rezultacie do tego neta CLK od szyfratora podlaczysz 10x wieksze obciazenie i Fmax spadnie o polowe. Potem cos jeszcze dodasz, zacznie byc ciasno w kosci, brakowac interconnectow i nagle zacznie Fmax leciec na pysk (jak duzo zajetego miejsca w FPGA, tak >85% to zauwazylem ze Fmax zmienia sie szybko tylko w jedna strone... zabawa z kilkoma kompilacjami troszke to poprawia, ale naprawde tylko troszke).

Sprobuj tak z ciekawosci do tego dolozyc cos duzego (50% kosci) - nawet na innym zegarze. Pewnie bedzie wolniej.

To jest testbed, on z założenia jest bezużyteczny, choćby z tego powodu, że kostka nie jest zabezpieczona. :-) Napisałem to w Quartusie, bo po prostu już się go nauczyłem. ;-)

Ten moduł w docelowym układzie miałby osobnego neta, 4x szybszego niż reszta kostki, dzieliłby go tylko z FIFO.

Biorąc pod uwagę, że celem było osiągnięcie 132MHz (4x33), to i tak byłoby 70MHz zapasu. :-) Po prostu widząc nierealne w moim pojęciu wyniki analizatora timingów (jakieś 330MHz) postanowiłem się poznęcać nad układem i poprawić wskazane ścieżki, co w końcu doprowadziło mnie do tego 405,2MHz. :->>>

Ustaw maksymalny odpowiedni poziom optymalizacji. Co prawda układ (mieszacz kwadratuowy) kompiluje się wtedy 15 minut zamiast

3,5, ale fmax mu wzrosło z 218 na 256MHz (zaczął limitować dostęp do RAMu). Biorąc pod uwagę to, że i tak będzie chodził na 130MHz, to ta różnica nie ma technicznego znaczenia, ale za to można się bardziej chwalić -- IMVHO to całkiem niezły wynik jak na amatora. :-)

Trudno się z tym nie zgodzić -- szybciej niż 405MHz już raczej nie będzie. ;-)))

Pozdrawiam Piotr Wyderski

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required