Forum: FPGA, VHDL & Co. Erster ernster Versuch- kann mal jemand drüberschauen?


von Heiko L. (der_caveman)


Lesenswert?

Hallo!
Das ist mein erster, ernster Versuch mit VHDL ;)

Ich habe versucht den TWI- Prescaler der Mega AVRs (48/88/168- bestimmt 
auch viele andere) nachzubauen.

Ich finde, dass das schon mal ganz toll aussieht, aber ist es das auch?
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity i2c_ce_gen is
6
    Port ( CLK_I : in  STD_LOGIC;
7
           RST_I : in STD_LOGIC;
8
           CE_I : in  STD_LOGIC;
9
           TWPS_I : in  STD_LOGIC_VECTOR (1 downto 0);
10
           TWBR_I : in  STD_LOGIC_VECTOR (7 downto 0);
11
           CE_O : out  STD_LOGIC);
12
end i2c_ce_gen;
13
14
architecture Behavioral of i2c_ce_gen is
15
16
signal prescale : integer range 0 to 32767;
17
signal prescale_cmp : integer range 0 to 32767;
18
signal sub_prescale : integer range 1 to 64;
19
signal twbr_temp : integer range 0 to 255;
20
21
begin
22
23
process (CLK_I)
24
begin
25
  --[CLKSYNC] sync process
26
  if rising_edge(CLK_I) then
27
    --[RESET]sync reset
28
    if RST_I = '1' then
29
      CE_O <= '0';
30
      prescale <= 0;
31
      prescale_cmp <= 0;
32
      sub_prescale <= 1;
33
    else
34
      --avr style prescaler selection
35
      case TWPS_I is
36
        when "00" => sub_prescale <= 1;
37
        when "01" => sub_prescale <= 4;
38
        when "10" => sub_prescale <= 16;
39
        when "11" => sub_prescale <= 64;
40
        when others => null;
41
      end case;
42
      --avr style prescale count register
43
      twbr_temp <= to_integer( unsigned(TWBR_I));
44
      --calculation of compare value (avr style)
45
      prescale_cmp <= 15 + 2 * twbr_temp * sub_prescale;
46
      
47
      --[CE] to cascade prescalers
48
      if CE_I = '1' then
49
        prescale <= prescale + 1;
50
        --[COMP] comparator
51
        if prescale = prescale_cmp then
52
          CE_O <= '1';
53
          prescale <= 0;
54
        else
55
          CE_O <= '0';
56
        end if; --/[COMP]
57
      end if; --/[CE]
58
    end if; --/[RESET]
59
  end if; --/[CLKSYNC]
60
end process;
61
end Behavioral;

von Jan M. (mueschel)


Lesenswert?

Ich würde sagen, da gibts erstmal nichts zu meckern.
Du solltest aber bei der Synthese mal nachschauen, was hieraus gemacht 
wird:
> prescale_cmp <= 15 + 2  twbr_temp  sub_prescale;
Da sub_prescale ja nur Zweierpotenzen als Wert annehmen kann, braucht es 
hier ja keinen Multiplizierer - ich weiß nur nicht, ob das 
Synthese-Programm das auch erkennt. Falls nicht, kannst du den Code 
etwas umstellen um ihm auf die Sprünge zu helfen.

von Duke Scarring (Gast)


Lesenswert?

@Heiko Lechner:

Für den ersten Versuch sieht es echt gut aus. Hast Du auch eine 
Testbench dazu, um den Block funktional verifizieren zu können?

Duke

von Heiko L. (der_caveman)


Lesenswert?

Jan M. wrote:

>> prescale_cmp <= 15 + 2  twbr_temp  sub_prescale;
> Da sub_prescale ja nur Zweierpotenzen als Wert annehmen kann, braucht es
> hier ja keinen Multiplizierer - ich weiß nur nicht, ob das
> Synthese-Programm das auch erkennt. Falls nicht, kannst du den Code
> etwas umstellen um ihm auf die Sprünge zu helfen.

Ok, da habe ich noch nicht dran gedacht.
Wie wird denn ein "left shift" synthetisiert (Mux, Schieberegister oder 
ganz anders)?

> Für den ersten Versuch sieht es echt gut aus.

Erster ernster Versuch ;)
Davor gab es auch schon so manchen Müll :)

> Hast Du auch eine
> Testbench dazu, um den Block funktional verifizieren zu können?

Bin ich gerade dran, die ersten Versuche sehen schon brauchbar aus.

Danke,
Heiko.

von Jan M. (mueschel)


Lesenswert?

Heiko Lechner wrote:
> Jan M. wrote:
>
>>> prescale_cmp <= 15 + 2  twbr_temp  sub_prescale;
>> Da sub_prescale ja nur Zweierpotenzen als Wert annehmen kann, braucht es
>> hier ja keinen Multiplizierer - ich weiß nur nicht, ob das
>> Synthese-Programm das auch erkennt. Falls nicht, kannst du den Code
>> etwas umstellen um ihm auf die Sprünge zu helfen.
>
> Ok, da habe ich noch nicht dran gedacht.
> Wie wird denn ein "left shift" synthetisiert (Mux, Schieberegister oder
> ganz anders)?

Es muss nichts wirklich geschoben werden, nur die richtigen Bits 
ausgewaehlt - es gibt also einen 4-zu-1-mux, der je nach Prescaler 
entweder Bit0, 2,4 oder 6 von twbr_temp auf Bit0 von prescale_cmp legt 
(zuzueglich Addition natuerlich).

von Heiko L. (der_caveman)


Lesenswert?

Jan M. wrote:

> Es muss nichts wirklich geschoben werden, nur die richtigen Bits
> ausgewaehlt - es gibt also einen 4-zu-1-mux, der je nach Prescaler
> entweder Bit0, 2,4 oder 6 von twbr_temp auf Bit0 von prescale_cmp legt
> (zuzueglich Addition natuerlich).

Es wird tatsächlich ein Multiplizierer generiert.

Ich habe es nun geändert zu:
1
--avr style prescaler selection
2
case TWPS_I is
3
  when "00" => sub_prescale <= 0; -- x<<0 == x*1
4
  when "01" => sub_prescale <= 2; -- x<<2 == x*4
5
  when "10" => sub_prescale <= 4; -- x<<4 == x*16
6
  when "11" => sub_prescale <= 6; -- x<<6 == x*64
7
  when others => null;
8
end case;  
9
--avr style prescale count register
10
twbr_temp <= to_integer( unsigned(TWBR_I));
11
--calculation of compare value (avr style)
12
prescale_cmp <= 15 + to_integer(to_unsigned(twbr_temp,8) sll (sub_prescale+1));

Allerdings ist die "Multiplizierer- Variante" bis auf den Multiplizierer 
ressourcensparender.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Das:
1
--avr style prescaler selection
2
case TWPS_I is
3
  when "00" => sub_prescale <= 0; -- x<<0 == x*1
4
  when "01" => sub_prescale <= 2; -- x<<2 == x*4
5
  when "10" => sub_prescale <= 4; -- x<<4 == x*16
6
  when "11" => sub_prescale <= 6; -- x<<6 == x*64
7
  when others => null;
8
end case;

ginge aber auch so:
1
  sub_prescale <=  to_integer(unsigned(TWPS_I & '0'));

von Heiko L. (der_caveman)


Lesenswert?

Lothar Miller wrote:

> ginge aber auch so:
1
sub_prescale <=  to_integer(unsigned(TWPS_I & '0'));

Fällt mir jetzt erst auf :)

Kann die case Anweisung denn zu weniger "optimierten" Synthetisierungen 
führen (etwas übersichtlicher finde ich es schon)?

von Duke Scarring (Gast)


Lesenswert?

@Heiko:
> Kann die case Anweisung denn zu weniger "optimierten" Synthetisierungen
> führen (etwas übersichtlicher finde ich es schon)?

Ja, kann. Die Wege der Synthesetools sind manchmal unergründlich :-(
Ich würde nur auf Platz optimieren, wenn es triftige Gründe gibt. Sicher 
muß man die Ressourcen nicht verschwenden, aber bei 
Entwicklungsprojekten, wo es nicht auf Masse oder Platz, sondern auf 
Zeit ankommt, hat man einfach keine Zeit ewig rumzuoptimieren.

Lieber lesebarer hinschreiben, da hat man später (manchmal) mehr davon.

Duke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> (etwas übersichtlicher finde ich es schon)?
Weil TWPS_I nur 4 Zustände hat und alle im case auscodiert wurden, 
solltest du aber das
1
when others => null;
 aus dem case herauslassen. Sonst könnte man ja meinen, da gäbe es noch 
andere (nicht abgedeckte) Zustände. Und das wäre dann doch etwas 
unübersichtlich ...  ;-)

von Duke Scarring (Gast)


Lesenswert?

@Lothar:
Die anderen Zustände gibt es doch, oder wolltest Du alles hinschreiben:
1
when "ZZ" => ...;
2
when "U1" => ...;
3
when "LH" => ...;
4
...

:-)

Duke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

>  when "ZZ" => ...;
>  when "U1" => ...;
>  when "XU" => ...;
>  when "LZ" => ...;
>  when "LH" => ...;
Auf die Signalzustände wollte ich schon immer mal abfragen  ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.