www.mikrocontroller.net

Forum: FPGA, VHDL & Co. VHDL ROM Component: Sollte 1 geben, gibt aber X


Autor: Rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich bin relativ neu bei VHDL und bastle gerade an nem kleinen Prozessor. 
Der kann im Moment nur logisch ODER und hat nur ein Register bzw. nen 
Akku. Nun habe ich eine ROM-Komponente erstellt, in der ein kleines 
Programm steht, bei dem er den kku vom LSB hin zum MSB mit 1 verodern 
soll.
Das Problem: Bei der "Veroderung" werden im Akku nicht Einsen sondern 
jeweils ein X gespeichert.
Als das ROM noch im Prozessor deklariert wurde ging es noch...
Ich habe leider keine Ahnung was ich da faalsch mache.
Hier mal der Code:

Task2.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Task2 is
Port   (   clka: in STD_LOGIC;
      procouta: out STD_LOGIC_VECTOR(7 downto 0);
      reset: in STD_LOGIC
    );
end Task2;

architecture Behavioral of Task2 is
component extROM
  Port(
    clkrom : in  STD_LOGIC;
    reset: in STD_LOGIC;
      addrinrom : in  STD_LOGIC_VECTOR(11 downto 0);
      instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0)
  );
end component;

type OP_type is (
  OP_OR,
  OP_UNKNOWN
);

type state_type is (
  init,
  execute,
  write_back,
  advance_PC,
  halt
);

signal instruction: STD_LOGIC_VECTOR(11 downto 0);
signal accu: STD_LOGIC_VECTOR(7 downto 0);
signal pc: integer;
signal my_state: state_type;
--Funktionen

-- Hole den Opcode
impure function decodeOp
( currOP : std_logic_vector (3 downto 0) )
return OP_type is
  variable result: OP_type;
begin
  case currOp is
    when "0000" =>
      result := OP_OR;
    when others =>
      result := OP_UNKNOWN;
  end case;
  return result;
end function decodeOp;

-- Hole den Wert der Instruktion
impure function getValue
( currIn : std_logic_vector (11 downto 0))
return STD_LOGIC_VECTOR  is
  variable result: STD_LOGIC_VECTOR (7 downto 0);
begin
  result := (currIn(7)&currIn(6)&currIn(5)&currIn(4)&currIn(3)&currIn(2)&currIn(1)&currIn(0));
  return result;
end function getValue;

begin
ROM1: extROM port map (
  clkrom => clka,
  reset => reset,
  addrinrom => conv_std_logic_vector(pc, 12),
  instructionoutrom => instruction
  );


my_proc: process
begin

wait until clka'event and clka='1';
if reset = '1' then
  my_state <= init;
else 
  case my_state is
    when init =>
      -- Initialisierung machen
      accu <= "00000000";
      procouta <= "00000000";
      instruction <= "000000000000";
      pc <= 0;
      my_state <= execute;
      -- Ein paar Takte warten
      for i in 1 to 4 loop
        wait until clka'event and clka='1';
      end loop;
    when execute =>
      --Bestimem Op-Code
      case decodeOp(instruction(11)&instruction(10)&instruction(9)&instruction(8)) is
        when OP_OR =>
          accu <= accu or getValue(instruction);
          my_state <= write_back;
        when others =>
          my_state <= halt;
      end case;
    when write_back =>
      procouta <= accu;
      my_State <= advance_PC;
    when advance_PC =>
      pc <= pc + 1;
      my_state <= execute;
    when halt =>
      wait until reset'event and reset = '1';
      my_state <= init;
  end case;
end if;
end process my_proc;
end Behavioral;

extROM.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity extROM is
    Port ( clkrom : in  STD_LOGIC;
        reset: in STD_LOGIC;
           addrinrom : in  STD_LOGIC_VECTOR(11 downto 0);
           instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0));
end extROM;

architecture Behavioral of extROM is
type ROM_type is array(0 to 8) of STD_LOGIC_VECTOR (11 downto 0);
constant prog_ROM : rom_type:=(
  "000000000001",
  "000000000010",
  "000000000100",
  "000000001000",
  "000000010000",
  "000000100000",
  "000001000000",
  "000010000000",  
  "100000000000"
);
begin
my_proc: process
begin

wait until clkrom'event and clkrom='1';
  if reset = '1' then
    instructionoutrom <= prog_ROM(0);
  else
    if conv_integer(addrinrom) < 8 then
      instructionoutrom <= prog_ROM(conv_integer(addrinrom));
    else
      instructionoutrom <= "111111111111";
    end if;
  end if;
end process my_proc;

end Behavioral;

Und die entsprechende Testbench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
 
ENTITY TextBencTask2 IS
END TextBencTask2;
 
ARCHITECTURE behavior OF TextBencTask2 IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT Task2
    PORT(
         clka : IN  std_logic;
         procouta : OUT  std_logic_vector(7 downto 0);
         reset : IN  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal clka : std_logic := '0';
   signal reset : std_logic := '0';

   --Outputs
   signal procouta : std_logic_vector(7 downto 0);

   -- Clock period definitions
   constant clka_period : time := 100ns;
 
BEGIN
 
  -- Instantiate the Unit Under Test (UUT)
   uut: Task2 PORT MAP (
          clka => clka,
          procouta => procouta,
          reset => reset
        );

   -- Clock process definitions
   clka_process :process
   begin
    clka <= '0';
    wait for clka_period/2;
    clka <= '1';
    wait for clka_period/2;
   end process;
  
      reset <= '0',
      '1' after 1*clka_period,
      '0' after 5*clka_period,
      '1' after 30*clka_period,
      '0' after 50*clka_period;

END;

Es wäre super wenn mir jemaand helfen könnte.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Willst du das Ganze mal in ein FPGA reinstecken?
Falls ja:
Dieses X ist vorerst eines deiner kleinsten Probleme   :-o

Knackiger ist das hier:
1)
wait until clka'event and clka='1';            -- der Takt
if reset = '1' then
    :
else 
    :
      for i in 1 to 4 loop
        wait until clka'event and clka='1';    -- Aua, ein paar Takte im Takt   :-/
      end loop;
    :
    when halt =>
       wait until reset'event and reset = '1'; -- hoppla, ein anderer Takt im Takt  :-o
Sowas lässt sich garantiert nicht in Hardware abbilden.
Und: du solltest dir das Thema for-Schleifen in VHDL (und insbesondere 
deren Umsetzung in Hardware) mal genauer anschauen.


2)
wait until clka'event and clka='1';
wait until clkrom'event and clkrom='1';
wait until reset'event and reset = '1';
Du hast viel zu viele Takte. Dein Design wird in der Realität nicht 
zuverlässig laufen. Ein ideales FPGA-Design hat 1 Takt und 0 Resets. In 
der Praxis muß man etwas von dieser strengen Regel abweichen, aber du 
solltest dafür sehr gute Gründe angeben können.


3)
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
Entweder - Oder. Aber niemals zusammen.
Du solltest heutzutage für die Synthese auch eher die numeric_std 
nehmen.


BTW:
  result := (currIn(7)&currIn(6)&currIn(5)&currIn(4)&currIn(3)&currIn(2)&currIn(1)&currIn(0));
so geht das kürzer und leserlicher:
  result := currIn(7 downto 0);

Autor: Rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Lothar,
danke für deine Antwort!

Lothar Miller schrieb:
> 1)
> ...
> Sowas lässt sich garantiert nicht in Hardware abbilden.
> Und: du solltest dir das Thema for-Schleifen in VHDL (und insbesondere
> deren Umsetzung in Hardware) mal genauer anschauen.

Ok, ich habe das ganze schonmal angepasst, sieht noch nicht 100%ig gut 
aus (besonders die Codeduplizierung bei reset und init, werde das wohl 
noch in eine Funktion auslagern oder mir fällt nen schöneres Design ein 
(theoretisch kann ich mir das Init auch sparen denke ich...).

Hier der Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Task2 is
Port   (   clka: in STD_LOGIC;
      procouta: out STD_LOGIC_VECTOR(7 downto 0);
      reset: in STD_LOGIC
    );
end Task2;

architecture Behavioral of Task2 is
-- Breite des Adressbusses des ROMs (Index des MSB)
constant maxPC : integer := 3;
component extROM
  generic (Adr_max : integer := maxPC);
  Port(
    clkrom : in  STD_LOGIC;
      addrinrom : in  STD_LOGIC_VECTOR(Adr_max downto 0);
      instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0)
  );
end component;

type OP_type is (
  OP_OR,
  OP_UNKNOWN
);

type state_type is (
  init,
  execute,
  write_back,
  advance_PC,
  halt
);

signal instruction: STD_LOGIC_VECTOR(11 downto 0);
signal accu: STD_LOGIC_VECTOR(7 downto 0);
signal pc: integer;
signal my_state: state_type := init;
--Funktionen

-- Hole den Opcode
impure function decodeOp
( currOP : std_logic_vector (3 downto 0) )
return OP_type is
  variable result: OP_type;
begin
  case currOp is
    when "0000" =>
      result := OP_OR;
    when others =>
      result := OP_UNKNOWN;
  end case;
  return result;
end function decodeOp;

-- Hole den Wert der Instruktion
impure function getValue
( currIn : std_logic_vector (11 downto 0))
return STD_LOGIC_VECTOR  is
  variable result: STD_LOGIC_VECTOR (7 downto 0);
begin
  result := currIn(7 downto 0);
  return result;
end function getValue;


begin
ROM1: extROM port map (
  clkrom => clka,
  addrinrom => conv_std_logic_vector(pc, maxPC+1),
  instructionoutrom => instruction
  );


my_proc: process
begin

wait until clka'event and clka='1';
if reset = '1' then
  my_state <= execute;
  accu <= "00000000";
  procouta <= "00000000";
  instruction <= "000000000000";
  pc <= 0;
else
  case my_state is
    when init =>
      -- Initialisierung machen
      my_state <= execute;
      accu <= "00000000";
      procouta <= "00000000";
      instruction <= "000000000000";
  pc <= 0;
    when execute =>
      --Bestimem Op-Code
      case decodeOp(instruction(11 downto 8)) is
        when OP_OR =>
          accu <= accu or getValue(instruction);
          my_state <= write_back;
        when others =>
          my_state <= halt;
      end case;
    when write_back =>
      procouta <= accu;
      my_State <= advance_PC;
    when advance_PC =>
      pc <= pc + 1;
      my_state <= execute;
    when halt =>
  end case;
end if;
end process my_proc;
end Behavioral;


Hoffe so ist es besser (bis auf die Duplizierung).

Lothar Miller schrieb:
> 2)
> wait until clka'event and clka='1';
> wait until clkrom'event and clkrom='1';
> wait until reset'event and reset = '1';
> Du hast viel zu viele Takte. Dein Design wird in der Realität nicht
> zuverlässig laufen. Ein ideales FPGA-Design hat 1 Takt und 0 Resets. In
> der Praxis muß man etwas von dieser strengen Regel abweichen, aber du
> solltest dafür sehr gute Gründe angeben können.

Ok, das wait fürs reset ist schonmaal raus, aber das clkrom ist doch 
über die Portmap mit clka quasi fest verdrahtet oder? Ist das damit 
nicht das gleiche Signal? Oder bezieht sich das auf die beiden waits und 
welches Signbal das ist spielt keine Rolle? Wenn ja:
Wie kann man soetwas denn sonst lösen? Sorry, bin wirklich totler 
Neuling :-(
Das rom wurde auch angepasst:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity extROM is
  generic (Adr_max : integer := 3);
    Port ( clkrom : in  STD_LOGIC;
           addrinrom : in  STD_LOGIC_VECTOR(Adr_max downto 0);
           instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0));
end extROM;

architecture Behavioral of extROM is
type ROM_type is array(0 to 8) of STD_LOGIC_VECTOR (11 downto 0);
constant prog_ROM : rom_type:=(
  "000000000001",
  "000000000010",
  "000000000100",
  "000000001000",
  "000000010000",
  "000000100000",
  "000001000000",
  "000010000000",  
  "100000000000"
);
begin
my_proc: process
begin

wait until clkrom'event and clkrom='1';
    if conv_integer(addrinrom) < 8 then
      instructionoutrom <= prog_ROM(conv_integer(addrinrom));
    else
      instructionoutrom <= "111111111111";
    end if;
end process my_proc;

end Behavioral;

Wie gesagt, wie ich mir da das wait sparen kann weiß ich leider nicht...

Lothar Miller schrieb:
> 3)USE ieee.std_logic_unsigned.all;
> USE ieee.numeric_std.ALL;
> Entweder - Oder. Aber niemals zusammen.
> Du solltest heutzutage für die Synthese auch eher die numeric_std
> nehmen.

Ok, da habe ich nun nur doch die numeric_std drin. Danke für den 
Hinweis.

Lothar Miller schrieb:
> BTW:  result := 
(currIn(7)&currIn(6)&currIn(5)&currIn(4)&currIn(3)&currIn(2)&currIn(1)&c 
urrIn(0));
> so geht das kürzer und leserlicher:  result := currIn(7 downto 0);

Ahh habe ich mir schon gedacht das das auch komfortabler gehen muss :-) 
Danke nochmal!


MfG Rene

Autor: Rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
konnte das Problem immernoch nicht beseitigen...
Habe im Netz etwas über resolution functions gefunden, bin mir aber 
nicht sicher ob es genau das sit, was ich haben möchte?!

MfG Rene

Autor: Rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
tut mir leid, das ich schon wieder hier selbst antworte, habe aber aus 
dem ROM nun auch den Takt entfernt, damit es synthetisierbar wird:

Danke nochmal Lothar...
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity extROM is
  generic (Adr_max : integer := 3; InstructionLength : integer := 17);
    Port ( addrinrom : in  STD_LOGIC_VECTOR(Adr_max downto 0);
           instructionoutrom : out  STD_LOGIC_VECTOR(InstructionLength downto 0));
end extROM;

architecture Behavioral of extROM is
type ROM_type is array(0 to 4) of STD_LOGIC_VECTOR (InstructionLength downto 0);
constant prog_ROM : rom_type:=(
  "000000000000001111",
  "000000000110001110",
  "001111000100000000",
  "101100000100000011",
  "111111111111111111"
);
begin
my_proc: process(addrinrom)
begin
    if conv_integer(addrinrom) < 4 then
      instructionoutrom <= prog_ROM(conv_integer(addrinrom));
    else
      instructionoutrom <= "111111111111111111";
    end if;
end process my_proc;

end Behavioral;


Leider werden immernoch nur X in mein instructionoutrom geschrieben und 
keine 1...
0 geht immer wunderbar.
Ich verzweifel langsam :-(

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Habe im Netz etwas über resolution functions gefunden, bin mir aber
> nicht sicher ob es genau das sit, was ich haben möchte?!
Nein, die Auflösungsfunktion macht genau das X aus den Eingangswerten. 
Wenn bei der 9-wertigen std_logic zwei gleich starke Pegel 
aufeinandertreffen (z.B. 0 und 1 oder  H und L), ist das Ergebnis X...

> Leider werden immernoch nur X in mein instructionoutrom geschrieben und
> keine 1...
> 0 geht immer wunderbar.
Das heißt, irgendwoher wird per default das ROM mit Nullen vorbelegt, 
und dann ist das Ergebnis klar:
0 und 0 gibt 0
0 und 1 gibt X

Ein kurze Suche ergibt:
ROM1: extROM port map (
  clkrom => clka,
  addrinrom => conv_std_logic_vector(pc, maxPC+1),
  instructionoutrom => instruction   ---- !!!!!  1. Treiber
  );


  instruction <= "000000000000";     ---- !!!!!  2. Treiber:  die Nullen
Du darfst deine instruction nicht von 2 Seiten treiben    :-o

Autor: Rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
danke vielmals!! Jetzt gehts und der Proz rechnet auch schon nen bissl 
was (hat nun auch Register etc).

Das Problem wurde gelöst, Thread kann geschlossen werden.


Danke nochmals!

Autor: Rick Dangerus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rene:
Tu Dir trotzdem noch den gefallen und schmeiss das raus:
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Und nimm die
use ieee.numeric_std.all; 
mit ihren Konvertierungsfunktionen stattdessen. Auch wenn es in 80% der 
Code-Beispielen, die im Netz zu finden sind, verwendet wird.

Rick

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.