Hallo,
ich möchte ein NCO basteln dabei liegen die daten im externen Ram.
Dabei soll eine externere CPU die Daten in das Ram speichern mit Hilfe
eines 8 Bit Datenbus (Adr_Buf , Dat_Buf , IO_Data).
Die Idee dabei erst Adresse setzen z.b 0x0000 dann die Daten durch den
FPGA in das Ram.
Mein Problem ist das die FSM nicht aufgerufen wird bzw das signal ctr
nicht auf "000" setzbar ist.
Hier mein Code:
entity ramversuch2122009 is
GENERIC (ADDRESS_WIDTH : integer := 8;
DATA_WIDTH : integer := 8
);
Port ( SRam_D : inout STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
SRam_A : inout STD_LOGIC_VECTOR (ADDRESS_WIDTH - 1 downto
0);
SRam_WE : out STD_LOGIC;
SRam_OE : out STD_LOGIC;
clock : in STD_LOGIC;
IO_Data : in STD_LOGIC_VECTOR (7 downto 0);
IO_Sel : in STD_LOGIC_VECTOR (2 downto 0);
IO_WE : in STD_LOGIC;
IO_CE : in STD_LOGIC
);
end ramversuch2122009;
architecture Behavioral of ramversuch2122009 is
signal count: std_logic_vector (28 downto 0) :=
"00000000000000000000000000000";
signal Dat_Buf : STD_LOGIC_VECTOR (7 downto 0);
signal Adr_Buf : STD_LOGIC_VECTOR (7 downto 0);
signal Frq_Buf : STD_LOGIC_VECTOR (7 downto 0);
signal Pha_Buf : STD_LOGIC_VECTOR (7 downto 0);
signal ctr : STD_LOGIC_VECTOR (2 downto 0) := "000";
TYPE fsm_type IS ( fsm_increment_address , fsm_load_address ,
fsm_stop
);
SIGNAL fsm : fsm_type;
begin
process (IO_WE)
begin
if IO_CE='0' then
if IO_WE='0' and IO_WE'event then
if IO_Sel="000" then
fsm <= fsm_stop;
Dat_Buf <= IO_Data;
fsm <= fsm_increment_address;
end if;
if IO_Sel="001" then
Adr_Buf <= IO_Data;
fsm <= fsm_load_address ;
end if;
if IO_Sel="010" then
Frq_Buf <= IO_Data;
end if;
if IO_Sel="011" then
Pha_Buf <= IO_Data;
end if;
end if;
end if;
end process;
process (clock , fsm )
begin
if clock='1' and clock'event then
case fsm is
when fsm_stop =>
ctr <= "000";
when fsm_load_address =>
SRam_A <= Adr_Buf; --Load Low Byte
--SRam_A ..downto.. <= Adr_Buf ; --Load High Byte
when fsm_increment_address =>
if ctr = "000" then
SRam_WE <= '1' ;
SRam_OE <= '1' ;
SRam_A <= SRam_A;
SRam_D <= Dat_Buf;
ctr <= "001";
elsif ctr = "001" then
SRam_WE <= '0' ;
SRam_OE <= '1' ;
ctr <= "010";
elsif ctr = "010" then
SRam_WE <= '1' ;
SRam_OE <= '1' ;
ctr <= "011";
elsif ctr = "011" then
SRam_A <= SRam_A + 1 ;
ctr <= "111";
end if;
end case;
end if;
end process;
end Behavioral;
Gibt es ne bessere möglichkeit als dieser Code?
Mfg
Commtel
Was heißt denn "FSM nicht aufgerufen wird" und "nicht auf 000 setzbar
ist"?
Wo geht was nicht? In Hardware? In der Simulation?
Auf den ersten Blick: Deine sensitivity lists stimmen nicht.
> process (IO_WE)
Hier fehlen alle anderen Signale die in dem Prozess gelesen werden:
IO_CE, IO_Data...
> process (clock , fsm )
Hier muss fsm nicht mit rein
Btw: Eine einheitliche Einrückung erleichtert das Lesen ungemein.
Hallo Jan M. ,
ja das sollte ich tun.
In der Simulation.
Muß ich auch externe eingänge in die sensitivity list aufnehmen?
Ich dachte nur interne signale.
Nochmals zur funktion der schaltung(software)
step 1
die externe cpu sendet die adresse auf dem 8 bit externen 8 bit bus.
IO_Sel = 01 und positive flanke von io_we = adresse gültig
step 2
IO_Sel = 00 und positive flanke von io_we = adresse , externe daten und
lösen dabei ein schreibzyklus für das externe ram aus das am fpga
angeschlossen ist.Anschliessend sollte die adresse +1 erhöht werden.
Dieser vorgang ist in der FSM beschrieben und sollte bei der nächsten
positiven flanke von io_we wiederholt werden.
Leider wird in der simulation nur die adresse ausgegeben.
mfg
> Muß ich auch externe eingänge in die sensitivity list aufnehmen?> Ich dachte nur interne signale.
Du mußt alles in diese Liste (die nur für die Simulation da ist)
aufnehmen, was eine Neuberechnung des Prozesses nötig macht. Also jedes
Signal, dessen Änderung einen der Ausgabewerte des Prozesses ändern
könnte, muß in die Liste.
> SRam_A : inout STD_LOGIC_VECTOR ...> SRam_A : inout STD_LOGIC_VECTOR ...
Warum hier ein inout?
Nur, dass du lokale Signale vermeiden kannst?
> SRam_A <= SRam_A + 1 ;
Vergiss die alten Synopsis-Libs. Mit Vektoren wird nicht gerechnet.
Nimm die numeric_std, in der gibt es passende Datentypen und
Casts+Konvertierungen:
http://www.lothar-miller.de/s9y/archives/14-Numeric_Std.html
> kannste mir das genauer erklären?
Sicher. Was denn?
>>> In der Simulation.
Nehmen wir mal das hier:
1
process(IO_WE)
2
begin
3
ifIO_CE='0'then
4
ifIO_WE='0'andIO_WE'eventthen
5
ifIO_Sel="000"then
6
fsm<=fsm_stop;
7
Dat_Buf<=IO_Data;
8
fsm<=fsm_increment_address;
9
endif;
10
ifIO_Sel="001"then
11
Adr_Buf<=IO_Data;
12
fsm<=fsm_load_address;
13
endif;
14
ifIO_Sel="010"then
15
Frq_Buf<=IO_Data;
16
endif;
17
ifIO_Sel="011"then
18
Pha_Buf<=IO_Data;
19
endif;
20
endif;
21
endif;
22
endprocess;
Was meinst du, was dieser Prozess in der Simulation macht, wenn sich
IO_CE ändert?
Gar nichts. Denn dieses Signal fehlt in der Sensitivliste. Und deshalb
wird das Signal fsm niemals auf fsm_stop gesetzt werden. Solche Fehler
findet man übrigens am einfachsten in der Simulation. Wenn du den nicht
findest, dann mußt du noch ein wenig üben ;-)
BTW:
1)
Einen Initialwert kannst du auch vergeben
SIGNAL fsm : fsm_type := fsm_stop;
2)
1
process(IO_WE)
2
begin
3
ifIO_CE='0'then
4
ifIO_WE='0'andIO_WE'eventthen
Sieh dir mal an, wie ein getakteter Prozess "üblicherweise" beschrieben
wird. Allein das Tauschen von 2 Zeilen wird hier einiges bringen:
1
process(IO_WE)
2
begin
3
ifIO_WE='0'andIO_WE'eventthen
4
ifIO_CE='0'then
3)
Du hast 2 Taktdomänen (alles, was mit 'event beschrieben wird):
1
ifIO_WE='0'andIO_WE'eventthen
2
:
3
:
4
ifclock='1'andclock'eventthen
Die werden dich auf der Hardware garantiert ins Schleudern bringen.
Stichworte dazu sind Einsynchronisieren und Taktdomänenübergang.
Hallo Lothar
erst mal vielen dank für den tip
1)
Einen Initialwert kannst du auch vergeben
SIGNAL fsm : fsm_type := fsm_stop;
werd ich mir gut merken
falls du nochmal zeit hast kannst du mir das mit den
numeric_std, Casts , Konvertierungen
da hab ich nix verstanden
übrigends klasse homepage die du da hast :-)
so ich hab wieder gebastelt
TYPE fsm_type IS ( fsm_start_wr_ram , fsm_load_address , fsm_IO_data ,
fsm_start_wr_ram_state1 , fsm_start_wr_ram_state2 ,
fsm_start_wr_ram_state3 , fsm_start_wr_ram_stop
);
SIGNAL fsm : fsm_type; --SIGNAL fsm : fsm_type := fsm_stop;
begin
process (IO_CE , IO_WE , IO_Sel , clock)
begin
if clock='1' and clock'event then
case fsm is
when fsm_IO_data =>
if IO_CE='0' then
if IO_WE='0' then
if IO_Sel="000" then
Dat_Buf <= IO_Data;
fsm <= fsm_start_wr_ram;
end if;
if IO_Sel="001" then
Adr_Buf <= IO_Data;
fsm <= fsm_load_address;
end if;
if IO_Sel="010" then
Frq_Buf <= IO_Data;
end if;
if IO_Sel="011" then
Pha_Buf <= IO_Data;
end if;
end if;
end if;
when fsm_start_wr_ram_stop =>
if IO_CE='0' and IO_WE='1' then
fsm <= fsm_IO_data;
end if;
when fsm_load_address =>
SRam_A <= Adr_Buf; --Load Low Byte
--SRam_A ..downto.. <= Adr_Buf ; --Load High Byte
fsm <= fsm_start_wr_ram_stop;
when fsm_start_wr_ram =>
SRam_WE <= '1' ;
SRam_OE <= '1' ;
SRam_A <= SRam_A;
SRam_D <= Dat_Buf;
fsm <= fsm_start_wr_ram_state1;
when fsm_start_wr_ram_state1 =>
SRam_WE <= '0' ;
SRam_OE <= '1' ;
SRam_A <= SRam_A;
SRam_D <= Dat_Buf;
fsm <= fsm_start_wr_ram_state2;
when fsm_start_wr_ram_state2 =>
SRam_WE <= '1' ;
SRam_OE <= '1' ;
SRam_A <= SRam_A;
SRam_D <= Dat_Buf;
fsm <= fsm_start_wr_ram_state3;
when fsm_start_wr_ram_state3 =>
SRam_WE <= '1' ;
SRam_OE <= '1' ;
SRam_A <= SRam_A + 1 ;
SRam_D <= Dat_Buf;
fsm <= fsm_start_wr_ram_stop;
END CASE;
end if;
end process;
end Behavioral;
und die simulation funzt so ich mir ie sache soweit vorstelle.
> process (IO_CE , IO_WE , IO_Sel , clock)
Hier würde clock ausreichen.
Denn der Prozess wird nur aktualisiert, wenn sich der Takt ändert.
> falls du nochmal zeit hast kannst du mir das mit den> numeric_std, Casts , Konvertierungen> da hab ich nix verstanden
Mehr dazu später... ;-)
ein kleines update
------------------------------------------------------------------------
----------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
entity ramversuch2122009 is
GENERIC (Address_width : integer := 7;
Data_width : integer := 7;
IO_Data_width : integer := 7
);
Port ( SRam_D : inout STD_LOGIC_VECTOR (DATA_WIDTH downto 0);
SRam_A : out STD_LOGIC_VECTOR (ADDRESS_WIDTH downto 0);
SRam_WE : out STD_LOGIC;
SRam_OE : out STD_LOGIC;
clock : in STD_LOGIC;
IO_Data : in STD_LOGIC_VECTOR (IO_Data_width downto 0);
IO_Sel : in STD_LOGIC_VECTOR (2 downto 0);
IO_WE : in STD_LOGIC;
IO_CE : in STD_LOGIC
);
end ramversuch2122009;
architecture Behavioral of ramversuch2122009 is
signal Dat_Buf : STD_LOGIC_VECTOR (7 downto 0);
signal Adr_Buf : STD_LOGIC_VECTOR (7 downto 0);
signal Adr_Buf_temp : STD_LOGIC_VECTOR (7 downto 0);
signal Frq0_reg : STD_LOGIC_VECTOR (7 downto 0):="00000000";
signal Pha0_reg : STD_LOGIC_VECTOR (7 downto 0):="00000000";
signal Pha_Akku : STD_LOGIC_VECTOR (7 downto 0):="00000000";
signal Con_reg : STD_LOGIC_VECTOR (7 downto 0);
signal wr_busy : STD_LOGIC;
TYPE fsm_type IS ( fsm_start_wr_ram , fsm_load_address , fsm_IO_data
,
fsm_start_wr_ram_state1 , fsm_start_wr_ram_state2 ,
fsm_start_wr_ram_stop
);
SIGNAL fsm : fsm_type; --SIGNAL fsm : fsm_type := fsm_stop;
begin
process (clock)
begin
if clock='1' and clock'event then
case fsm is
when fsm_IO_data =>
if IO_CE='0' then
if IO_WE='0' then
if IO_Sel="000" then
wr_busy <= '1';
Dat_Buf <= IO_Data;
fsm <= fsm_start_wr_ram;
end if;
if IO_Sel="001" then
Adr_Buf <= IO_Data;
fsm <= fsm_load_address;
end if;
if IO_Sel="010" then
Frq0_reg <= IO_Data;
end if;
if IO_Sel="011" then
Pha0_reg <= IO_Data;
end if;
if IO_Sel="111" then
Con_reg <= IO_Data;
end if;
end if;
end if;
when fsm_start_wr_ram_stop =>
wr_busy <= '0';
if IO_CE='0' and IO_WE='1' then
fsm <= fsm_IO_data;
end if;
when fsm_load_address =>
Adr_Buf_temp <= Adr_Buf; --Load Low Byte
--SRam_A ..downto.. <= Adr_Buf ; --Load High Byte
fsm <= fsm_start_wr_ram_stop;
when fsm_start_wr_ram =>
SRam_WE <= '1' ;
SRam_A <= Adr_Buf_temp;
SRam_D <= Dat_Buf;
fsm <= fsm_start_wr_ram_state1;
when fsm_start_wr_ram_state1 =>
SRam_WE <= '0' ;
fsm <= fsm_start_wr_ram_state2;
when fsm_start_wr_ram_state2 =>
SRam_WE <= '1' ;
Adr_Buf_temp <= Adr_Buf_temp + 1;
fsm <= fsm_start_wr_ram_stop;
end case;
if wr_busy = '1' then
SRam_OE <= '1' ;
else
SRam_OE <= '0' ;
Pha_Akku <= Pha_Akku + Frq0_reg;
SRam_A <= Pha0_reg + Pha_Akku;
end if;
end if;
end process;
end Behavioral;
Frohes Fest
Entweder:
> use IEEE.std_logic_arith.all;> use IEEE.std_logic_unsigned.all;
Oder:
> use IEEE.numeric_std.all;
Aber nicht: Viel hilft viel...
Du willst die numeric_std benutzen, bekommst jetzt aber dei Vektoren
nicht mehr addiert? Und deshalb lässt du die std_logic_arith drin?
Dann nimm die numeric_std und mach überall dort wo sowas steht:
> signal Dat_Buf : STD_LOGIC_VECTOR (7 downto 0);> signal Adr_Buf : STD_LOGIC_VECTOR (7 downto 0);
das daraus:
> signal Dat_Buf : UNSIGNED (7 downto 0);> signal Adr_Buf : UNSIGNED (7 downto 0);
Die Ports der Entity lässt du aber std_logic_vector.
Und für diese Zuweisungen:
SRam_A <= Pha0_reg + Pha_Akku;
gibts dann
SRam_A <= std_logic_vector(Pha0_reg + Pha_Akku);
Hier wird ein unsigned und ein unsigend addiert und das Ergebnis zur
Ausgabe in einen Vektor umgecastet.
Insgesamt gefällt mir jetzt gut, dass die FSM synchron ist. Ich erwarte
allerdings noch Probleme beim Taktdomänenübergang von der externen CPU
in deine FSM:
if IO_WE='0' then
Das ist asynchron. Und nirgends ist ein Mechanismus zum
Einsynchronisieren zu des IO_WE erkennen. Insbesondere innnerhalb einer
FSM wird sowas mit eigenartigem Verhalten quittiert:
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html
Hallo Lothar,
ich hab das jetzt gemacht
library IEEE;
use IEEE.std_logic_1164.all;
--use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
architecture Behavioral of ramversuch2122009 is
signal Dat_Buf : unsigned (7 downto 0);
signal Adr_Buf : unsigned (7 downto 0);
und bekomm das als fehler
Type of Dat_Buf is incompatible with type of IO_Data.
ich such nun seit 2 stunden nach ner lösung.
Komm echt nicht weiter :-(
Hoffe ich hab nichts übersehen...
konkret : unsigned und std_logic_vector kannst du ineinander "umwandeln"
indem du den einen Typ in Klammern setzt und den neuen Typ davor
schreibst.
> unsigned und std_logic_vector kannst du ineinander "umwandeln"
Das war das, was ich dort mit "Casts" meinte:
Beitrag "Re: Problem mit FSM"
Konvertierungen nach und von integer haben ein to_ vorangestellt.
1
useIEEE.NUMERIC_STD.ALL;
2
:
3
Port(din:inSTD_LOGIC_VECTOR(7downto0);
4
dout:ouSTD_LOGIC_VECTOR(7downto0);
5
:
6
:
7
signaldatain:unsigned(7downto0);
8
signaldinteger:integerrange0to255;
9
signaldataout:unsigned(7downto0);
10
:
11
datain<=unsigned(din);-- von slv (std_logic_vector) nach unsigend
12
dinteger<=to_integer(datain);-- von unsigned nach integer
13
dataout<=to_unsigned(datainteger,8);-- von integer nach unsigned
14
dout<=std_logic_vector(dataout);-- von unsigned nach slv
vielen dank Iulius aber es kommen immer noch fehler
+ can not have such operands in this context
hallo Lothar
was hat das ganze den für vorteile wenn ich das in unsigned umsetze?
einfacher? Find ich jetzt nicht gerade
Bin wohl heut morgen doch noch etwas verpennt
> einfacher? Find ich jetzt nicht gerade
Nein, in sich schlüssiger. Und exakt definiert.
Nehmen wir mal sowas:
1
signala:STD_LOGIC_VECTOR(7downto0):="00000001";
2
signalb:STD_LOGIC_VECTOR(7downto0):="11111111";
3
signalc:STD_LOGIC_VECTOR(15downto0);
4
5
c<=a*b;
was kommt da jetzt raus?
Wenn du use IEEE.std_logic_unsigned.all;
verwendest, ist das Ergebnis c = 0000000011111111;
Wenn du use IEEE.std_logic_signed.all;
verwendest, ist das Ergebnis c = 1111111111111111;
Du siehst also niemals nur an der Rechenoperation, was eigentlich
berechnet wird.
Wenn du
1
signala:UNSIGNED(7downto0):="00000001";
2
signalb:UNSIGNED(7downto0):="11111111";
3
signalc:UNSIGNED(15downto0);
4
5
c<=a*b;
verwendest, ist alles wohldefiniert und klar.
EDIT:
Mit den Tags [/vhdl] und [vhdl] kannst du deinen VHDL-Text schön
formatieren lassen.
>>> + can not have such operands in this context
Poste mal die Zeile und die Definitionen der beteiligten Signale. Und
dazu die verwendeten Libs.
Das sind ja böse fallen.
Woher hast du all diese information?
Auf deiner homepage find ich jetzt nichts.
Ok ich hab jetzt alles umgeschrieben bis auf die IO_WE geschichte und
das
Con_reg signal.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity ramversuch2122009 is
GENERIC (Address_width : integer := 7;
Data_width : integer := 7;
IO_Data_width : integer := 7
);
Port ( SRam_D : inout STD_LOGIC_VECTOR (Data_width downto 0);
SRam_A : out STD_LOGIC_VECTOR (Address_width downto 0);
SRam_WE : out STD_LOGIC;
SRam_OE : out STD_LOGIC;
clock : in STD_LOGIC;
IO_Data : in STD_LOGIC_VECTOR (IO_Data_width downto 0);
IO_Sel : in STD_LOGIC_VECTOR (2 downto 0);
IO_WE : in STD_LOGIC;
IO_CE : in STD_LOGIC
);
end ramversuch2122009;
architecture Behavioral of ramversuch2122009 is
signal Dat_Buf : unsigned (IO_Data_width downto 0);
signal Adr_Buf : unsigned (Address_width downto 0);
signal Adr_Buf_temp : unsigned (7 downto 0);
signal Frq0_reg : unsigned(7 downto 0):="00000000";
signal Pha0_reg : unsigned (7 downto 0):="00000000";
signal Pha_Akku : unsigned (7 downto 0):="00000000";
signal Con_reg : STD_LOGIC_VECTOR (7 downto 0);
signal wr_busy : STD_LOGIC;
TYPE fsm_type IS ( fsm_start_wr_ram , fsm_load_address , fsm_IO_data
,
fsm_start_wr_ram_state1 , fsm_start_wr_ram_state2 ,
fsm_start_wr_ram_stop
);
SIGNAL fsm : fsm_type;
begin
process (clock)
begin
if clock='1' and clock'event then
case fsm is
when fsm_IO_data =>
if IO_CE='0' then
if IO_WE='0' then
if IO_Sel="000" then
wr_busy <= '1';
Dat_Buf <= unsigned(IO_Data);
fsm <= fsm_start_wr_ram;
end if;
if IO_Sel="001" then
Adr_Buf <= unsigned(IO_Data);
fsm <= fsm_load_address;
end if;
if IO_Sel="010" then
Frq0_reg <= unsigned(IO_Data);
end if;
if IO_Sel="011" then
Pha0_reg <= unsigned(IO_Data);
end if;
if IO_Sel="111" then
Con_reg <= IO_Data;
end if;
end if;
end if;
when fsm_start_wr_ram_stop =>
wr_busy <= '0';
if IO_CE='0' and IO_WE='1' then
fsm <= fsm_IO_data;
end if;
when fsm_load_address =>
Adr_Buf_temp <= Adr_Buf; --Load Low Byte
--SRam_A ..downto.. <= Adr_Buf ; --Load High Byte
fsm <= fsm_start_wr_ram_stop;
when fsm_start_wr_ram =>
SRam_WE <= '1' ;
SRam_A <= std_logic_vector(Adr_Buf_temp);
SRam_D <= std_logic_vector(Dat_Buf);
fsm <= fsm_start_wr_ram_state1;
when fsm_start_wr_ram_state1 =>
SRam_WE <= '0' ;
fsm <= fsm_start_wr_ram_state2;
when fsm_start_wr_ram_state2 =>
SRam_WE <= '1' ;
Adr_Buf_temp <= Adr_Buf_temp+1;
fsm <= fsm_start_wr_ram_stop;
end case;
if wr_busy = '1' then
SRam_OE <= '1' ;
else
SRam_OE <= '0' ;
Pha_Akku <= Pha_Akku + Frq0_reg;
SRam_A <= std_logic_vector(Pha0_reg + Pha_Akku);
end if;
end if;
end process;
end Behavioral;