Forum: FPGA, VHDL & Co. VHDL - Kombinatorische Logik und Signal aus dem Prozess aktuallisieren


von Artata (Gast)


Lesenswert?

Ich stehe gerade auf dem Schlauch. Und zwar habe ich hier eine 
vereinfachte Version eines Adressendecoder der mit bei Schreibzugriffen 
die Adresse und den Datensatz in zwei Temp-Registern ablegen soll:
AD_TEMP_ADDR_OUT
AD_TEMP_DATA_OUT

Werden Daten über die Serielle Schnittstelle empfangen, werden diese an 
den Adressendecoder weiter geleitet. Ähnlich wie bei SPI kommt erst die 
Adresse, die dann als paralleles Signal an den Adressendecoder 
ausgegeben wird und dann die Daten. Der Adressendecoder soll diese, bei 
Schreibzugriffen, in Temp-Registern zwischen lagern und einen Interrupt 
generieren. Die Sache ist, so wie es jetzt ist, werden die Interrupts 
bereits bei Änderung der Adresse generiert. Somit erhalte ich beim 
Auslesen der Temp Register einen Datensatz bestehend aus der richtigen 
Adresse aber einem vorher geschriebenen Wert. Da ich zum Umrechnen der 
Adresse auf die Änderung dieser reagieren muss, fällt mir gerade nichts 
ein, wie ich Interrupt generieren soll, erst wenn die Daten ebenfalls 
geschrieben wurden. Mir fällt da so eine Art onChange Funktion :)
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_UNSIGNED.ALL;
4
use IEEE.numeric_std.all;
5
6
entity address_decoder is
7
port (
8
  -- RAM CLOCK
9
  AD_CLK_SERIALBUS_IN          : in  STD_LOGIC;  -- clock from SERIALBUS
10
11
  -- Address from SERIALBUS/uC to RAm
12
  AD_REGADDR_SERIALBUS_IN        : in  STD_LOGIC_VECTOR(15 downto 0);  -- reg address from SERIALBUS Interface
13
  AD_REGADDR_RAM8_OUT        : out  STD_LOGIC_VECTOR(15 downto 0);   -- reg address to RAM8
14
15
  
16
  -- Data from SERIALBUS/uC to RAM
17
  AD_REGDATA_SERIALBUS_IN        : in    STD_LOGIC_VECTOR(15 downto 0);  -- data from SERIALBUS
18
  AD_REGDATA_RAM8_OUT        : out  STD_LOGIC_VECTOR(7 downto 0);  -- data to ram8
19
20
  -- Data from RAM to SERIALBUS/uC
21
  AD_REGDATA_SERIALBUS_OUT        : out  STD_LOGIC_VECTOR(15 downto 0);  -- data to SERIALBUS   
22
  AD_REGDATA_RAM8_IN        : in   STD_LOGIC_VECTOR(7 downto 0);  -- data from ram8 
23
24
  -- Read/Write
25
  AD_RW_SERIALBUS_IN          : in  STD_LOGIC;  -- read/write Signal from SERIALBUS
26
  AD_RW_RAM8_OUT          : out  STD_LOGIC;  -- read/write to RAM8
27
  
28
  -- RAM CLK
29
  AD_CLK_RAM8_OUT          : out   STD_LOGIC;  -- clock to 8Bit  RAM
30
  AD_CLK_RAM16_OUT        : out  STD_LOGIC;  -- clock to 16Bit RAM
31
32
  -- RAM ENABLE
33
  AD_ENABLE_RAM8          : out  STD_LOGIC;  -- anable signal (HIGH: enabled)
34
  AD_ENABLE_RAM16          : out  STD_LOGIC;
35
36
  -- internal connections to uC interface to signalize SERIALBUS writes from host
37
  AD_TEMP_INTERRUPT_OUT      : out  STD_LOGIC;            -- will be set if new data is available
38
  AD_TEMP_ADDR_OUT        : out  STD_LOGIC_VECTOR(15 downto 0);  -- stores the register address
39
  AD_TEMP_DATA_OUT        : out  STD_LOGIC_VECTOR(15 downto 0);  -- stores the data 
40
  AD_TEMP_CLEAR_IN        : in  STD_LOGIC;            -- signal to clear Tempdata
41
42
  -- Asynchronous reset input
43
  RESET              : in  STD_LOGIC
44
);
45
end address_decoder;
46
47
architecture address_decoder_arch of address_decoder is
48
begin
49
50
process (RESET, AD_REGADDR_SERIALBUS_IN, AD_REGDATA_SERIALBUS_IN, AD_RW_SERIALBUS_IN, AD_REGDATA_RAM8_IN, AD_TEMP_CLEAR_IN)
51
52
constant READ_ONLY    : STD_LOGIC := '1';
53
constant WRITE       : STD_LOGIC := '0';
54
constant ENABLED    : STD_LOGIC := '1';
55
constant DISABLED     : STD_LOGIC := '0';
56
57
BEGIN
58
  if rising_edge(RESET) then
59
60
    AD_REGADDR_RAM8_OUT   <= (others => '1');
61
    AD_REGDATA_RAM8_OUT   <= (others => '0');
62
63
    AD_REGDATA_SERIALBUS_OUT    <= (others => '0');
64
65
    -- clear temporary signals on reset
66
    AD_TEMP_ADDR_OUT     <= (others => '0');
67
    AD_TEMP_DATA_OUT     <= (others => '0');
68
    AD_TEMP_INTERRUPT_OUT  <= DISABLED;
69
70
    --// For Loop To Initialize all Registers to 0 on power on
71
  end if;
72
73
  if AD_TEMP_CLEAR_IN = ENABLED then
74
    AD_TEMP_INTERRUPT_OUT <= DISABLED; -- reset interrupt out signal
75
  end if;
76
  
77
78
  -- Decode Address comming from SERIALBUS Interface to RAM
79
  ----------------------------------------------------------------------------
80
  -- 8BIT RAM
81
  -- Used 682 Bytes within 2 Block RAMs: 342 Bytes are left
82
  ----------------------------------------------------------------------------
83
  if (AD_REGADDR_SERIALBUS_IN >= x"1000" and AD_REGADDR_SERIALBUS_IN <= x"1FFF") then
84
      
85
      AD_ENABLE_RAM8   <= ENABLED;
86
      AD_ENABLE_RAM16 <= DISABLED;
87
88
      --sig_flag_ram16 <= '0';
89
      if 
90
      -- ##### CFP NVR 
91
      (AD_REGADDR_SERIALBUS_IN >= x"1000" and AD_REGADDR_SERIALBUS_IN <= x"1198") then
92
        AD_REGADDR_RAM8_OUT <= (AD_REGADDR_SERIALBUS_IN - x"1000");
93
      -- disable writing to this address space (Read: HIGH; Write: LOW). Signal shall stay HIGH!
94
        AD_RW_RAM8_OUT      <= READ_ONLY;       -- Writes by SERIALBUS are restricted
95
      -- forward data from SERIALBUS to ram 
96
        AD_REGDATA_RAM8_OUT <= AD_REGDATA_SERIALBUS_IN(7 downto 0);
97
      -- forward data from ram to SERIALBUS
98
        AD_REGDATA_SERIALBUS_OUT <= (x"00" & AD_REGDATA_RAM8_IN);
99
      elsif
100
      -- ##### Vendor NVR 1 
101
      (AD_REGADDR_SERIALBUS_IN >= x"1420" and AD_REGADDR_SERIALBUS_IN <= x"1430") then
102
        AD_REGADDR_RAM8_OUT <= (AD_REGADDR_SERIALBUS_IN - x"1420" + x"199"); -- +"Offset
103
        AD_RW_RAM8_OUT     <= READ_ONLY;        -- Writes by SERIALBUS are restricted
104
        AD_REGDATA_RAM8_OUT <= AD_REGDATA_SERIALBUS_IN(7 downto 0); 
105
        AD_REGDATA_SERIALBUS_OUT <= (x"00" & AD_REGDATA_RAM8_IN); 
106
      elsif
107
      -- ##### User NVR 1 and User NVR 2 
108
      (AD_REGADDR_SERIALBUS_IN >= x"1800" and AD_REGADDR_SERIALBUS_IN <= x"18FF") then
109
        AD_REGADDR_RAM8_OUT <= (AD_REGADDR_SERIALBUS_IN - x"1800" +  x"1AA"); -- +Offset: 
110
        AD_RW_RAM8_OUT     <= AD_RW_SERIALBUS_IN;  -- read/wire is controlled by 
111
        AD_REGDATA_RAM8_OUT <= AD_REGDATA_SERIALBUS_IN(7 downto 0); 
112
        AD_REGDATA_SERIALBUS_OUT <= (x"00" & AD_REGDATA_RAM8_IN); --
113
114
        if AD_RW_SERIALBUS_IN = WRITE and AD_TEMP_CLEAR_IN = ENABLED then   -- save new data if uC cleared last request
115
          AD_TEMP_ADDR_OUT    <=   AD_REGADDR_SERIALBUS_IN;       -- contains current register address
116
          AD_TEMP_DATA_OUT    <=  AD_REGDATA_SERIALBUS_IN;      -- contains current register data
117
          AD_TEMP_INTERRUPT_OUT   <=  ENABLED;             -- signalize uC "NEW DATA ARRIVED"
118
        end if;
119
        
120
      else
121
        AD_REGADDR_RAM8_OUT  <= (others => '0');
122
        AD_RW_RAM8_OUT     <= READ_ONLY;
123
        AD_REGDATA_RAM8_OUT <= (others => '0');
124
        AD_REGDATA_SERIALBUS_OUT <= (others => '0'); -- send zeros instead to read from RAM, if an unspecefied address was selected
125
      end if;
126
  end if;  
127
end process;
128
129
-- Forward Clock Signal to both RAMs
130
AD_CLK_RAM8_OUT   <= AD_CLK_SERIALBUS_IN;  -- clock to RAM8
131
132
end address_decoder_arch;

Wie kann ich diesen Teil so umschreiben, dass Interrupt erst bei 
Änderung von Daten kommt, damit Adresse und Daten korrelieren?
1
if AD_RW_SERIALBUS_IN = WRITE and AD_TEMP_CLEAR_IN = ENABLED then   -- save new data if uC cleared last request
2
          AD_TEMP_ADDR_OUT    <=   AD_REGADDR_SERIALBUS_IN;       -- contains current register address
3
          AD_TEMP_DATA_OUT    <=  AD_REGDATA_SERIALBUS_IN;      -- contains current register data
4
          AD_TEMP_INTERRUPT_OUT   <=  ENABLED;             -- signalize uC "NEW DATA ARRIVED"
5
        end if;

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


Lesenswert?

Artata schrieb:
> if rising_edge(RESET) then
Hoppala. Das kann lustig werden. Ich glaube nicht, dass das wie 
gewünscht funktioniert. Und falls doch, dann glaube ich, dass ich den 
Trick dabei nicht verstanden habe...

1
  if rising_edge(RESET) then
2
    :
3
  end if;
4
5
  if AD_TEMP_CLEAR_IN = ENABLED then
6
    :
7
  end if;
8
9
  if (AD_REGADDR_SERIALBUS_IN >= x"1000" and AD_REGADDR_SERIALBUS_IN <= x"1FFF") then
10
    :
11
  end if;
In welchem Buch/welcher Vorlesung hast du sowas gelernt?

Artata schrieb:
> Wie kann ich diesen Teil so umschreiben, dass Interrupt erst bei
> Änderung von Daten kommt, damit Adresse und Daten korrelieren?
Um Änderungen erkennen zu können brauchst du ein "Vorher" und ein 
"Jetzt". Also irgendwas, das mit "Zeit" und "Merken" zu tun hat. 
Zeitliche Abläufe und speichernde Werte werden in VHDL über getaktete 
Register beschrieben.

von Artata (Gast)


Lesenswert?

>Ich glaube nicht, dass das wie gewünscht funktioniert.
Meinst du, weil ich mix Betrieb habe und rising_edge benutze?

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


Lesenswert?

Artata schrieb:
> Meinst du, weil ich mix Betrieb habe und rising_edge benutze?
Ja, auch.
Und im Besonderen, weil ein Reset normalerweise nicht an die 
Takteingänge von Flipflops gehört...

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Lothar Miller schrieb:
> Und im Besonderen, weil ein Reset normalerweise nicht an die
> Takteingänge von Flipflops gehört...
Niemals gehört ein Reset an den Tekteingang. Der Reset gehört bei einem 
modernden FPGA in die Kiste und Deckel zu. FPGAs brauchen nur in 
Ausnahmefällen einen Reset.

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.