Hallo Richard,
habe mir den Code mal angeschaut, den Fehler aber ohne mir das Design
mal zu skizzieren nicht auf gefunden, was daran liegt das der Code -
sorry - nicht sehr hardwarenah geschrieben ist. Hier meine 2 Cent.
- Datenpfade & Controlpfade strikt getrennt halten!
Eine Zuweisung wie "DataRAM_o <= DataSPI_i" hat in einer FSM nichts zu
suchen. Wenn man Datenpfade schalten will (multiplexen), dann einen
Multiplexer verwenden und das Kontrolsignal von der FSM generieren
lassen. Soweit ich das in deinem Code sehe wird DataRam_o immer von
DataSPI_i getrieben, also raus damit aus der FSM. Inbesondere nicht in
einer If-Else Anweisung innerhalb eines geclockten Prozesses, das kann
dir "versteckte" Register generieren.
- Gleiches gilt fur AddressRam_o. Soweit ich das sehe wird der Adressbus
nur von einem Counter getrieben. Also:
prcoess(clk)
begin
if rising_edge(clk) then
if Counter_Reset = '1' then
Counter <= (others=>'0');
elsif Counter_Increment = 1' then
Counter <= Counter + '1';
end if;
end process;
AddressRam_o <= Counter;
Die Signale Counter_Reset und Counter_Increment werden über die
Kontroll-FSM gesteuert.
- Vorsicht mit 1-Process FSMs. Die kann man zwar verwenden, sollte sich
aber bewusst sein, dass die generierten Kontrolsignale einen Takt nach
dem State erst gültig sind. Ist nicht falsch, aber macht es
komplizierter das Verhalten im Kopf nachzuvollziehen. Sauberer - und
meiner Erfahrung nach - einfacher zu lesen sind 2-Prozess FSMs. Ein
synchroner Prozess für die State-Register, in denen der aktuelle State
gespeichert wird. Und ein asynchroner der den nächsten State berechnet
und die Outputs entsprechend treibt.
FSM-States : process(clk)
begin
if rising_edge(clk) then
if Reset = '1' then
State <= Initial_State;
else
State <= Next_State;
end if;
end process;
FSM-Logic : process(State, Start_FSM, Input_A, Input_B)
begin
-- default assignments --
Next-State <= State;
Output_A <= '0';
Output_B <= '0';
-- state transitions --
case State is
when S_IDLE =>
if Start_FSM = '1' then
Next_State <= S_Drive_A;
end if;
when S_Drive_A =>
Next_State <= S_Drive_B;
Output_A <= '1';
when S_Drive_B =>
Next_State <= S_IDLE;
Output_B <= '1';
when others =>
null;
end case;
end process;
Diese Schreibweise hat mehrere Vorteile:
1) Der Output entspricht immer genau dem State in dem man gerade ist und
kommt genau in diesem Taktzyklus. Bei einer 1-Prozess FSM muss das nicht
der Fall sein (wie in deinem, in dem sich die Signalzuweisung innerhalb
des If rising_edge(clk) Statements befindet).
2) Durch die Default Assignments sind alle Signale zu jedem Zeitpunkt
sauber definiert und es entsehen keine "versteckten" Register.
Abschließend noch 3 Anmerkungen:
- Vergiss asynchrone Reset, die hat man Anfang 2000 bei FPGAs beerdigt.
Mit steigender Logikdichte und Geschwindigkeit machen die mehr Probleme
als dass sie Nutzen bringen. Detailiert kann man das im Xilinx
WhitePaper WP272 nachlesen.
- Dein Code zur Synthese des RAM ist korrekt, jeder Syntheizer sollte
das erkennen, manche könnten sich aber an dem Reset verschlucken. Reset
an einem RAM existiert so auch nicht, im schlimsten Fall, wie schon
andere zuvor angemerkt haben, wird das RAM in FFs implementiert. Reset
an einem RAM braucht man aber auch nicht, es ist völlig egal was da drin
steht, da man in ein RAM überlicherweise erstmal reinschreibt, bevor man
rausliest. Falls man vorinitialisierte RAMS braucht, dann macht man das
über spezielle Init Direktiven.
- Digital Design ist kein Software Design. VHDL und Verilog sind
Beschreibungssprachen, die beschreiben Systeme, die im Falle von FPGAs
aus bestimmten diskreten Elementen bestehen (LUTs, FF, RAMs, Hardcores,
DSPs). Und Synthesizer sind dumm! Alles was die versuchen ist zu
erkennen, wie man die Beschreibung auf diese diskreten Elemente abbilden
kann. Je klarer man seinen Code schreibt (und sich an gewisse Regeln
hält) desto eher tut der Synthesizer das was er tun soll. Am besten geht
das mit einem Blatt Papier und einem Stift. Man skizziert erstmal das
Design oder einen Teil davon, hält Daten- und Kontrolpfade strikt
getrennt und schreibt es dann genau so in VHDL/Verilog runter.
Viel Erfolg,
JD