Forum: FPGA, VHDL & Co. NIOS II mit eigenem Bauteil verbinden


von Peer R. (moepser)


Lesenswert?

Hallo,

ich bin neu im Forum, natürlich habe ich die Suchfunktion bedient, aber 
keine passende Hilfe bekommen. Sollte ich einen passenden Beitrag 
übersehen oder nicht gefunden haben, bitte ich das zu entschuldigen.
Zu meinem Problem:
Ich möchte einen bestehenden NIOS2 Prozessor um eine eigene Komponente 
erweitern. Bei der Komponente soll es sich um einen simplen Counter mit 
preload handeln. Sprich, es soll einen 8 Bit breiten eingang geben, dem 
ein Wert übergeben werden kann, von dem aus dann der Zähler bis 255 
hochzählt. Für den Fall das nichts übergeben wird, soll einfach bei 0 
angefangen werden. Weiter soll der Zähler erst anfangen zu zählen, wenn 
er ein Start-Bit gesetzt wird. Natürlich soll es auch einen Reset und 
CLK Eingang geben.

Ich habe ein Bauteil erstellt:
1
library IEEE;
2
use ieee.std_logic_1164.all;
3
use ieee.std_logic_unsigned.all;
4
5
entity CounterWPreload is
6
  port (
7
      -- <interface type>_<interface name>_<signal type>
8
      avs_avalonslave_writedata:  IN std_logic_vector (7 downto 0);
9
      avs_avalonslave2_writedata: IN std_logic;
10
      avs_avalonslave_write:    IN std_logic;
11
      csi_clockreset_clk:      IN std_logic;
12
      csi_clockreset_reset:    IN std_logic;
13
      coe_counterOutput_export:  OUT std_logic_vector (7 downto 0)
14
      );
15
end CounterWPreload;
16
17
architecture CounterWPreload_arch of CounterWPreload is
18
signal counter:   std_logic_vector (7 downto 0); -- enthaellt zaehlerstand
19
signal stop:    std_logic := '0';  -- signalisiert, dass der zahler voll ist
20
21
begin
22
standart: process (csi_clockreset_clk, csi_clockreset_reset)
23
begin
24
  if (csi_clockreset_reset = '1') then        --wurde der Reset gesetzt
25
    counter <= avs_avalonslave_writedata;    --setze den counter zurueck auf den Wert des Preload
26
    stop <= '0';            --setze das Stopbit auf 0
27
  elsif(csi_clockreset_clk'event and csi_clockreset_clk = '1' and stop = '0' and avs_avalonslave2_writedata = '1') then -- wenn der Takt eintrifft und der Baustein aktiv ist und der Zaehler nicht durchgelaufen ist
28
    if(avs_avalonslave_write = '1') then
29
      counter <= avs_avalonslave_writedata;
30
    elsif (avs_avalonslave_write = '0') then
31
      coe_counterOutput_export <= counter;    -- dann gebe den momentanen counterstand aus
32
      counter <= counter + 1;      -- und erhoehe den counterstand
33
      if(counter = "11111111") then -- ist der zaehler vollgelaufen
34
        stop <= '1';          -- dann aktiviere das stopbit
35
      end if;
36
    end if;
37
  end if;
38
end process;
39
40
end CounterWPreload_arch;

Mein Problem ist nun, wenn ich das Bauteil über den SoPC Builder in den 
NIOS2 einbinde, dann weiß ich nicht wie es an den Avalon Master 
angebunden wird, sprich: Wie schaffe ich es, dass ein Bit verwendet 
werden kann um den Zähler loslaufen zu lassen? Und wie kann ich in C 
dann dieses Bit setzen und Daten an den Zähler schicken um ihn zu laden? 
Ich habe diese Funktion in Forenbeiträgen gefunden: 
IOWR_8DIRECT(COUNTER_W_PRELOAD_8BIT_0_BASE, 0, 0xAA);
aber die führt bei mir nur zu Fehlern.

Kann mir jemand helfen? Vielen Dank!

von Kest (Gast)


Lesenswert?

Lies mal die Doku zum AVALON-Interface -- das was Du gemacht hast ist 
falsch.
1. clk'event und clk='1' ist nur für getaktete Prozesse gedacht, also da 
sollten keine weitere "and stop = '0' and avs_avalonslave2_writedata = 
'1'" auftauchen
2. ein AVALON Interface besteht aus writedata, write, adress (vielleicht 
noch chip_select und wait_request)
D.h. in Deiner Komponente müsstest Du ein Register-Set aufbauen, etwa 
so:

if avalon_write = '1' then
  if avalon_adress = x"00" then
     internal_counter <= write_data
  end if;
end if;

Das ist nur pseudocode. Such' mal hier im Forum danach, das habe ich 
schon ein Paar mal beschreiben.

Am besten Du liest die Doku, damit Du es auch verstehst, was Du machst. 
Viel Erfolg,

Kest

von Peer R. (moepser)


Lesenswert?

Hi, danke für die schnelle Antwort!

Ich gebe zu ich bin weder mit VHDL noch mit dem NIOS oder Quartus sehr 
vertraut. Ich habe mir die Avalon Spezifikation (teilweise) 
durchgelesen.

Habe ich das richtig verstanden, würde man eine Variable namens:
1
avs_avalonslave_address: IN std_logic
 erstellen, kann man über diese die Datenbytes der Komponente auswählen? 
Also würde ich in meinen Fall (siehe oben) mit avs_avalonslave_address = 
'0' die ersten 8 Bit meiner Komponente zum beschreiben auswählen? Aber 
wenn das so ist, woher weiß ich, welche die ersten 8 Bits sind? Bzw. 
wenn ich davon ausgehe, dass über writedata die beschreibaren Bits 
ausgewählt werden, wie kann ich dann noch register hinzufügen, die 
unabhängig von den writedata beschrieben werden? Oder muss ich die größe 
des writedata verändern und dann über avs_avalonslave_address = '1' die 
nächsten 8 Bis auswählen?

Bitte habt Gedult mit einem Neuling, lasst mich nicht dumm sterben! ;)

Vielen Dank!

von Kest (Gast)


Lesenswert?

Hallo,
Ein Avalon-Slave sieht in etwa so aus:

entity digital_io is

  port (
    -- Avalon Clock
    clk_m : in std_logic;

    -- AVALON Slave Interface
    as_address       : in  std_logic_vector(7 downto 0);
    as_chipselect    : in  std_logic;
    as_read          : in  std_logic;
    as_write         : in  std_logic;
    as_writedata     : in  std_logic_vector(31 downto 0);
    as_readdata      : out std_logic_vector(31 downto 0);
    as_readdatavalid : out std_logic;
    as_waitrequest   : out std_logic;

    -- externe Pins
    ....

    );

end digital_io;


und später irgendwo:

  ------------------------------------------------------------------------ 
-----
  -- AVALON Slave Interface / Registerset
  ------------------------------------------------------------------------ 
-----
  as_readdata    <= reg_readdata;
  as_waitrequest <= not (as_write or as_read);

  process(clk_m)
  begin
    if rising_edge(clk_m) then

      ------------------------------------------------------------------------ 
-
      -- SCHREIBEN
      ------------------------------------------------------------------------ 
-
      if as_chipselect = '1' and as_write = '1' then
        case as_address is
          when x"00" => cpld_spi_clock_div <= unsigned(as_writedata(7 
downto 0));
          when x"01" => max_cpld_cnt <= 
unsigned(as_writedata(max_cpld_cnt'range));
          when x"02" => Output_Register <= as_writedata;
          when x"03" => digital_o_reg   <= as_writedata;

          when others => null;
        end case;
      end if;
      ------------------------------------------------------------------------ 
-
      -- LESEN
      ------------------------------------------------------------------------ 
-
      as_readdatavalid <= as_chipselect and as_read;

      if as_chipselect = '1' and as_read = '1' then
        case as_address is
          when x"00"  => reg_readdata <= Input_register(31 downto 0);
          when x"01"  => reg_readdata  <= digital_i_reg;
          when x"02"  => reg_readdata(15 downto 0) <= cBOARD_REVISION;
          when others => null;
        end case;
      end if;

    end if;
  end process;

das Ganze ist eher exemplarisch und nicht vollständig. Aber es sollte 
klar sein, wie es funktioniert.

Grüße,
Kest

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.