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


von Rene (Gast)


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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_ARITH.ALL;
4
use IEEE.STD_LOGIC_UNSIGNED.ALL;
5
6
---- Uncomment the following library declaration if instantiating
7
---- any Xilinx primitives in this code.
8
--library UNISIM;
9
--use UNISIM.VComponents.all;
10
11
entity Task2 is
12
Port   (   clka: in STD_LOGIC;
13
      procouta: out STD_LOGIC_VECTOR(7 downto 0);
14
      reset: in STD_LOGIC
15
    );
16
end Task2;
17
18
architecture Behavioral of Task2 is
19
component extROM
20
  Port(
21
    clkrom : in  STD_LOGIC;
22
    reset: in STD_LOGIC;
23
      addrinrom : in  STD_LOGIC_VECTOR(11 downto 0);
24
      instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0)
25
  );
26
end component;
27
28
type OP_type is (
29
  OP_OR,
30
  OP_UNKNOWN
31
);
32
33
type state_type is (
34
  init,
35
  execute,
36
  write_back,
37
  advance_PC,
38
  halt
39
);
40
41
signal instruction: STD_LOGIC_VECTOR(11 downto 0);
42
signal accu: STD_LOGIC_VECTOR(7 downto 0);
43
signal pc: integer;
44
signal my_state: state_type;
45
--Funktionen
46
47
-- Hole den Opcode
48
impure function decodeOp
49
( currOP : std_logic_vector (3 downto 0) )
50
return OP_type is
51
  variable result: OP_type;
52
begin
53
  case currOp is
54
    when "0000" =>
55
      result := OP_OR;
56
    when others =>
57
      result := OP_UNKNOWN;
58
  end case;
59
  return result;
60
end function decodeOp;
61
62
-- Hole den Wert der Instruktion
63
impure function getValue
64
( currIn : std_logic_vector (11 downto 0))
65
return STD_LOGIC_VECTOR  is
66
  variable result: STD_LOGIC_VECTOR (7 downto 0);
67
begin
68
  result := (currIn(7)&currIn(6)&currIn(5)&currIn(4)&currIn(3)&currIn(2)&currIn(1)&currIn(0));
69
  return result;
70
end function getValue;
71
72
begin
73
ROM1: extROM port map (
74
  clkrom => clka,
75
  reset => reset,
76
  addrinrom => conv_std_logic_vector(pc, 12),
77
  instructionoutrom => instruction
78
  );
79
80
81
my_proc: process
82
begin
83
84
wait until clka'event and clka='1';
85
if reset = '1' then
86
  my_state <= init;
87
else 
88
  case my_state is
89
    when init =>
90
      -- Initialisierung machen
91
      accu <= "00000000";
92
      procouta <= "00000000";
93
      instruction <= "000000000000";
94
      pc <= 0;
95
      my_state <= execute;
96
      -- Ein paar Takte warten
97
      for i in 1 to 4 loop
98
        wait until clka'event and clka='1';
99
      end loop;
100
    when execute =>
101
      --Bestimem Op-Code
102
      case decodeOp(instruction(11)&instruction(10)&instruction(9)&instruction(8)) is
103
        when OP_OR =>
104
          accu <= accu or getValue(instruction);
105
          my_state <= write_back;
106
        when others =>
107
          my_state <= halt;
108
      end case;
109
    when write_back =>
110
      procouta <= accu;
111
      my_State <= advance_PC;
112
    when advance_PC =>
113
      pc <= pc + 1;
114
      my_state <= execute;
115
    when halt =>
116
      wait until reset'event and reset = '1';
117
      my_state <= init;
118
  end case;
119
end if;
120
end process my_proc;
121
end Behavioral;

extROM.vhd
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_ARITH.ALL;
4
use IEEE.STD_LOGIC_UNSIGNED.ALL;
5
6
---- Uncomment the following library declaration if instantiating
7
---- any Xilinx primitives in this code.
8
--library UNISIM;
9
--use UNISIM.VComponents.all;
10
11
entity extROM is
12
    Port ( clkrom : in  STD_LOGIC;
13
        reset: in STD_LOGIC;
14
           addrinrom : in  STD_LOGIC_VECTOR(11 downto 0);
15
           instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0));
16
end extROM;
17
18
architecture Behavioral of extROM is
19
type ROM_type is array(0 to 8) of STD_LOGIC_VECTOR (11 downto 0);
20
constant prog_ROM : rom_type:=(
21
  "000000000001",
22
  "000000000010",
23
  "000000000100",
24
  "000000001000",
25
  "000000010000",
26
  "000000100000",
27
  "000001000000",
28
  "000010000000",  
29
  "100000000000"
30
);
31
begin
32
my_proc: process
33
begin
34
35
wait until clkrom'event and clkrom='1';
36
  if reset = '1' then
37
    instructionoutrom <= prog_ROM(0);
38
  else
39
    if conv_integer(addrinrom) < 8 then
40
      instructionoutrom <= prog_ROM(conv_integer(addrinrom));
41
    else
42
      instructionoutrom <= "111111111111";
43
    end if;
44
  end if;
45
end process my_proc;
46
47
end Behavioral;

Und die entsprechende Testbench:
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 TextBencTask2 IS
7
END TextBencTask2;
8
 
9
ARCHITECTURE behavior OF TextBencTask2 IS 
10
 
11
    -- Component Declaration for the Unit Under Test (UUT)
12
 
13
    COMPONENT Task2
14
    PORT(
15
         clka : IN  std_logic;
16
         procouta : OUT  std_logic_vector(7 downto 0);
17
         reset : IN  std_logic
18
        );
19
    END COMPONENT;
20
    
21
22
   --Inputs
23
   signal clka : std_logic := '0';
24
   signal reset : std_logic := '0';
25
26
   --Outputs
27
   signal procouta : std_logic_vector(7 downto 0);
28
29
   -- Clock period definitions
30
   constant clka_period : time := 100ns;
31
 
32
BEGIN
33
 
34
  -- Instantiate the Unit Under Test (UUT)
35
   uut: Task2 PORT MAP (
36
          clka => clka,
37
          procouta => procouta,
38
          reset => reset
39
        );
40
41
   -- Clock process definitions
42
   clka_process :process
43
   begin
44
    clka <= '0';
45
    wait for clka_period/2;
46
    clka <= '1';
47
    wait for clka_period/2;
48
   end process;
49
  
50
      reset <= '0',
51
      '1' after 1*clka_period,
52
      '0' after 5*clka_period,
53
      '1' after 30*clka_period,
54
      '0' after 50*clka_period;
55
56
END;

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

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


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)
1
wait until clka'event and clka='1';            -- der Takt
2
if reset = '1' then
3
    :
4
else 
5
    :
6
      for i in 1 to 4 loop
7
        wait until clka'event and clka='1';    -- Aua, ein paar Takte im Takt   :-/
8
      end loop;
9
    :
10
    when halt =>
11
       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)
1
USE ieee.std_logic_unsigned.all;
2
USE ieee.numeric_std.ALL;
Entweder - Oder. Aber niemals zusammen.
Du solltest heutzutage für die Synthese auch eher die numeric_std 
nehmen.


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

von Rene (Gast)


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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_ARITH.ALL;
4
use IEEE.STD_LOGIC_UNSIGNED.ALL;
5
6
---- Uncomment the following library declaration if instantiating
7
---- any Xilinx primitives in this code.
8
--library UNISIM;
9
--use UNISIM.VComponents.all;
10
11
entity Task2 is
12
Port   (   clka: in STD_LOGIC;
13
      procouta: out STD_LOGIC_VECTOR(7 downto 0);
14
      reset: in STD_LOGIC
15
    );
16
end Task2;
17
18
architecture Behavioral of Task2 is
19
-- Breite des Adressbusses des ROMs (Index des MSB)
20
constant maxPC : integer := 3;
21
component extROM
22
  generic (Adr_max : integer := maxPC);
23
  Port(
24
    clkrom : in  STD_LOGIC;
25
      addrinrom : in  STD_LOGIC_VECTOR(Adr_max downto 0);
26
      instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0)
27
  );
28
end component;
29
30
type OP_type is (
31
  OP_OR,
32
  OP_UNKNOWN
33
);
34
35
type state_type is (
36
  init,
37
  execute,
38
  write_back,
39
  advance_PC,
40
  halt
41
);
42
43
signal instruction: STD_LOGIC_VECTOR(11 downto 0);
44
signal accu: STD_LOGIC_VECTOR(7 downto 0);
45
signal pc: integer;
46
signal my_state: state_type := init;
47
--Funktionen
48
49
-- Hole den Opcode
50
impure function decodeOp
51
( currOP : std_logic_vector (3 downto 0) )
52
return OP_type is
53
  variable result: OP_type;
54
begin
55
  case currOp is
56
    when "0000" =>
57
      result := OP_OR;
58
    when others =>
59
      result := OP_UNKNOWN;
60
  end case;
61
  return result;
62
end function decodeOp;
63
64
-- Hole den Wert der Instruktion
65
impure function getValue
66
( currIn : std_logic_vector (11 downto 0))
67
return STD_LOGIC_VECTOR  is
68
  variable result: STD_LOGIC_VECTOR (7 downto 0);
69
begin
70
  result := currIn(7 downto 0);
71
  return result;
72
end function getValue;
73
74
75
begin
76
ROM1: extROM port map (
77
  clkrom => clka,
78
  addrinrom => conv_std_logic_vector(pc, maxPC+1),
79
  instructionoutrom => instruction
80
  );
81
82
83
my_proc: process
84
begin
85
86
wait until clka'event and clka='1';
87
if reset = '1' then
88
  my_state <= execute;
89
  accu <= "00000000";
90
  procouta <= "00000000";
91
  instruction <= "000000000000";
92
  pc <= 0;
93
else
94
  case my_state is
95
    when init =>
96
      -- Initialisierung machen
97
      my_state <= execute;
98
      accu <= "00000000";
99
      procouta <= "00000000";
100
      instruction <= "000000000000";
101
  pc <= 0;
102
    when execute =>
103
      --Bestimem Op-Code
104
      case decodeOp(instruction(11 downto 8)) is
105
        when OP_OR =>
106
          accu <= accu or getValue(instruction);
107
          my_state <= write_back;
108
        when others =>
109
          my_state <= halt;
110
      end case;
111
    when write_back =>
112
      procouta <= accu;
113
      my_State <= advance_PC;
114
    when advance_PC =>
115
      pc <= pc + 1;
116
      my_state <= execute;
117
    when halt =>
118
  end case;
119
end if;
120
end process my_proc;
121
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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_ARITH.ALL;
4
use IEEE.STD_LOGIC_UNSIGNED.ALL;
5
6
---- Uncomment the following library declaration if instantiating
7
---- any Xilinx primitives in this code.
8
--library UNISIM;
9
--use UNISIM.VComponents.all;
10
11
entity extROM is
12
  generic (Adr_max : integer := 3);
13
    Port ( clkrom : in  STD_LOGIC;
14
           addrinrom : in  STD_LOGIC_VECTOR(Adr_max downto 0);
15
           instructionoutrom : out  STD_LOGIC_VECTOR(11 downto 0));
16
end extROM;
17
18
architecture Behavioral of extROM is
19
type ROM_type is array(0 to 8) of STD_LOGIC_VECTOR (11 downto 0);
20
constant prog_ROM : rom_type:=(
21
  "000000000001",
22
  "000000000010",
23
  "000000000100",
24
  "000000001000",
25
  "000000010000",
26
  "000000100000",
27
  "000001000000",
28
  "000010000000",  
29
  "100000000000"
30
);
31
begin
32
my_proc: process
33
begin
34
35
wait until clkrom'event and clkrom='1';
36
    if conv_integer(addrinrom) < 8 then
37
      instructionoutrom <= prog_ROM(conv_integer(addrinrom));
38
    else
39
      instructionoutrom <= "111111111111";
40
    end if;
41
end process my_proc;
42
43
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

von Rene (Gast)


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

von Rene (Gast)


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...
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_ARITH.ALL;
4
use IEEE.STD_LOGIC_UNSIGNED.ALL;
5
6
---- Uncomment the following library declaration if instantiating
7
---- any Xilinx primitives in this code.
8
--library UNISIM;
9
--use UNISIM.VComponents.all;
10
11
entity extROM is
12
  generic (Adr_max : integer := 3; InstructionLength : integer := 17);
13
    Port ( addrinrom : in  STD_LOGIC_VECTOR(Adr_max downto 0);
14
           instructionoutrom : out  STD_LOGIC_VECTOR(InstructionLength downto 0));
15
end extROM;
16
17
architecture Behavioral of extROM is
18
type ROM_type is array(0 to 4) of STD_LOGIC_VECTOR (InstructionLength downto 0);
19
constant prog_ROM : rom_type:=(
20
  "000000000000001111",
21
  "000000000110001110",
22
  "001111000100000000",
23
  "101100000100000011",
24
  "111111111111111111"
25
);
26
begin
27
my_proc: process(addrinrom)
28
begin
29
    if conv_integer(addrinrom) < 4 then
30
      instructionoutrom <= prog_ROM(conv_integer(addrinrom));
31
    else
32
      instructionoutrom <= "111111111111111111";
33
    end if;
34
end process my_proc;
35
36
end Behavioral;


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

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


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:
1
ROM1: extROM port map (
2
  clkrom => clka,
3
  addrinrom => conv_std_logic_vector(pc, maxPC+1),
4
  instructionoutrom => instruction   ---- !!!!!  1. Treiber
5
  );
6
7
8
  instruction <= "000000000000";     ---- !!!!!  2. Treiber:  die Nullen
Du darfst deine instruction nicht von 2 Seiten treiben    :-o

von Rene (Gast)


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!

von Rick Dangerus (Gast)


Lesenswert?

@Rene:
Tu Dir trotzdem noch den gefallen und schmeiss das raus:
1
use IEEE.STD_LOGIC_ARITH.ALL;
2
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Und nimm die
1
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

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.