Hi,
vorgestern habe ich mit VHDL angefangen. Erstes Projekt sollte ein 8-bit
I/O Port mit Datenrichtungsregister (Port laesst sich bitweise auf
Eingang oder Ausgang umschalten) und Intel-Bus (z.B. fuer 8051) sein.
Hier ist mein Code, der fehlerfrei synthetisiert wird (ISE 13.1) und
auch in der Simulation korrekt laeuft (s. Anhang).
1
libraryIEEE;
2
useIEEE.STD_LOGIC_1164.ALL;
3
4
-- Uncomment the following library declaration if using
5
-- arithmetic functions with Signed or Unsigned values
6
--use IEEE.NUMERIC_STD.ALL;
7
8
-- Uncomment the following library declaration if instantiating
9
-- any Xilinx primitives in this code.
10
--library UNISIM;
11
--use UNISIM.VComponents.all;
12
13
entityintelbusis
14
Port(data:inoutSTD_LOGIC_VECTOR(7downto0);-- data bus
15
addr:inSTD_LOGIC;-- address bit
16
p0:inoutSTD_LOGIC_VECTOR(7downto0);-- i/o port
17
rd:inSTD_LOGIC;-- /RD
18
wr:inSTD_LOGIC;-- /WR
19
res:inSTD_LOGIC;-- /RESET
20
cs:inSTD_LOGIC);-- /CS
21
endintelbus;
22
23
architectureBehavioralofintelbusis
24
25
signalp0reg:std_logic_vector(7downto0);
26
signalddr0:std_logic_vector(7downto0);
27
28
begin
29
30
process(res,rd,wr,cs,data)is
31
begin
32
33
if(cs='1')then
34
data<=(others=>'Z');
35
36
else
37
iffalling_edge(wr)then
38
if(addr='0')then
39
p0reg<=data;
40
else
41
ddr0<=data;
42
endif;
43
endif;
44
45
iffalling_edge(rd)then
46
if(addr='0')then
47
data<=p0;
48
else
49
data<=ddr0;
50
endif;
51
endif;
52
endif;
53
54
--asynchronous reset
55
if(res='0')then
56
p0reg<=(others=>'0');
57
ddr0<=(others=>'0');
58
endif;
59
60
if(rd='1')then
61
data<=(others=>'Z');
62
endif;
63
64
endprocess;
65
66
G:foriin0to7generate
67
p0(i)<=p0reg(i)whenddr0(i)='1'else'Z';
68
endgenerateG;
69
70
endBehavioral;
Wuerde mich freuen wenn jemand kommentieren koennte ob alles OK ist oder
ob man etwas besser/anders machen koennte.
Dir fehlt jegliche Synchronisation auf einen Takt und noch dazu ein
asynchroner Reset.
Das wird in realer Hardware nur sehr glitchig laufen, denn du versuchst
auf Kontrollsignale taktmäßig zu triggern.
Eigentlich ist da alles falsch, was ein Anfänger falsch machen kann.
Aha, was waeren Deine konkreten Vorschlaege?
Ich will Dich ja nicht belehren, aber der Intel-Bus ist asynchron, da
gibts keinen Takt.
Der Schaltplan (s. Anhang) sieht fuer mich OK aus (etwas vereinfachter
Code, damit die Multiplexer rausfallen): die Register werden ueber das
/WR-Signal getaktet.
Das ganze ist uebrigens fuer ein CPLD gedacht (XC9500).
Marko B. schrieb:> Aha, was waeren Deine konkreten Vorschlaege?
Das muß nicht alles in 1 Prozess, dann passiert es auch nicht, dass
unnötige Signale in der Sensitivliste auftauchen (data)...
Die Richtungsumschaltung machst du besser concurrent:
1
signaldin:STD_LOGIC_VECTOR(7downto0);
2
signaldout:STD_LOGIC_VECTOR(7downto0);
3
:
4
:
5
-- Schreiben
6
process(res,wr)begin
7
if(res='0')then
8
p0reg<=(others=>'0');
9
ddr0<=(others=>'0');
10
elsifrising_edge(wr)then--< ressourcenschonender
11
-- elsif (wr='0') then --< eigentlich richtiger
12
if(addr='0')then
13
p0reg<=din;
14
else
15
ddr0<=din;
16
endif;
17
endif;
18
endprocess;
19
20
-- Daten fürs Lesen bereitstellen
21
dout<=p0whenaddr='0'else
22
ddr0;
23
24
-- Busverwaltung
25
din<=data;
26
data<=(others=>'Z')whenrd='1'orcs='1'else
27
dout;
> Erstes Projekt sollte ein 8-bit I/O Port mit Datenrichtungsregister> (Port laesst sich bitweise auf Eingang oder Ausgang umschalten) und> Intel-Bus (z.B. fuer 8051) sein.
Diese Busse sind eigentlich nicht getaktet (auch nicht auf rd bzw. wr).
Sondern da wird bei low-aktivem Signal gelatcht. Der richtige
Zeitpunkt zur Datenübernahme ist also die steigende Flanke des
wr-Signals...
Marko B. schrieb:> Das ganze ist uebrigens fuer ein CPLD gedacht (XC9500).
Das hätte ganz an den Anfang der Frage hingehört. Es ist nämlich ein
eklatanter Unterschied, ob du ein synchrones Design auf einem FPGA hast,
oder irgendwelche Tricksereien auf einem CPLD... :-/
Du hast recht, dein Takt ist das wr Signal. Da glitcht nichts wenn der
Busmaster sich an die Spec hält, und davon sollte man ausgehen können.
Auch ein 8051 benimmt sich nicht wenn man ihn falsch ansteuert.
Zum Lesen würde ich allerdings nicht falling_edge(rd) verwenden, das
lässt sich rein kombinatorisch ausführen.
Bah, ich schreibe zu langsam, bzw denke zuviel dabei.
Lothar Miller schrieb:> Das hätte ganz an den Anfang der Frage hingehört. Es ist nämlich ein> eklatanter Unterschied, ob du ein synchrones Design auf einem FPGA hast,> oder irgendwelche Tricksereien auf einem CPLD... :-/
Für die Aufgabe ist das finde ich egal. Es ist nunmal kein getaktetes
Design mit einer ständigen Clock.
Fertig hinschreiben hätte meine Ansicht nach nicht sein müssen, was
lernt er jetzt noch?
PS: Ich habe in meiner Antwort 8051 mit 8255 verwechselt.
Lattice User schrieb:> Für die Aufgabe ist das finde ich egal. Es ist nunmal kein getaktetes> Design mit einer ständigen Clock.
Klar, in so ein CPLD passt ja nicht arg viel mehr rein... ;-)
Aber man müsste die Sache wesentlich tiefer angehen, wenn da eine zweite
Taktdomäne mit im Spiel wäre...
Lothar Miller schrieb:> Das muß nicht alles in 1 Prozess, dann passiert es auch nicht, dass> unnötige Signale in der Sensitivliste auftauchen (data)...
Hatte ich sogar anfangs versucht, wurde aber durch "multiple drivers"
Fehler frustriert.
> Die Richtungsumschaltung machst du besser concurrent:>
1
>signaldin:STD_LOGIC_VECTOR(7downto0);
2
>signaldout:STD_LOGIC_VECTOR(7downto0);
3
>:
4
>:
5
>-- Schreiben
6
>process(res,wr)begin
7
>if(res='0')then
8
>p0reg<=(others=>'0');
9
>ddr0<=(others=>'0');
10
>elsifrising_edge(wr)then--< ressourcenschonender
11
>-- elsif (wr='0') then --< eigentlich richtiger
12
>if(addr='0')then
13
>p0reg<=din;
14
>else
15
>ddr0<=din;
16
>endif;
17
>endif;
18
>endprocess;
19
>
20
>-- Daten fürs Lesen bereitstellen
21
>dout<=p0whenaddr='0'else
22
>ddr0;
23
>
24
>-- Busverwaltung
25
>din<=data;
26
>data<=(others=>'Z')whenrd='1'orcs='1'else
27
>dout;
28
>
Ah, super. Das ist natuerlich deutlich eleganter :)
>> Erstes Projekt sollte ein 8-bit I/O Port mit Datenrichtungsregister>> (Port laesst sich bitweise auf Eingang oder Ausgang umschalten) und>> Intel-Bus (z.B. fuer 8051) sein.> Diese Busse sind eigentlich nicht getaktet (auch nicht auf rd bzw. wr).> Sondern da wird bei low-aktivem Signal gelatcht.
Ich hatte als erstes eine Level-getriggerte Version versucht, aber die
ganzen Warnungen bzgl. "Latch found" haben mich dann auf die obige
Version gefuehrt.
> Der richtige Zeitpunkt zur Datenübernahme ist also die steigende> Flanke des wr-Signals...
Das hatte ich aber anders gelesen:
"If the 8051 is writing data, it appears on the bus following the
address information, and the active-low write signal, WR_, indicates
that the data is available. The falling edge of WR_ is typically used to
capture the data from the bus."
http://www.design-reuse.com/articles/8692/fpga-design-from-the-outside-in.html
Fuer RD ist die kombinatorische Variante natuerlich viel eleganter.
>> Das ganze ist uebrigens fuer ein CPLD gedacht (XC9500).> Das hätte ganz an den Anfang der Frage hingehört. Es ist nämlich ein> eklatanter Unterschied, ob du ein synchrones Design auf einem FPGA hast,> oder irgendwelche Tricksereien auf einem CPLD... :-/
Wieso dieses? Koennte man obigen Code so nicht in ein FPGA packen?
Danke uebrigens fuer den Code und die Erklaerungen!
Lattice User schrieb:
> Fertig hinschreiben hätte meine Ansicht nach nicht sein müssen, was> lernt er jetzt noch?
Ich glaube fuer einen Anfaenger ist es schon extrem hilfreich, wenn man
einen kompletten lauffaehigen Code hat, an dem man sich orientieren
kann. Ausserdem ist das ja nur ein Hello World. Als naechstes kommt eine
DMA Engine fuer einen 6502 :D
Marko B. schrieb:> Hatte ich sogar anfangs versucht, wurde aber durch "multiple drivers"> Fehler frustriert.
Und dann hast du dir selber was in die Tasche gelogen und alles in 1
Prozess gepackt... :-o
> The falling edge of WR_ is typically used to capture the data from the> bus."
Sieh dir die Timing-Diagramme an: an der steigenden Flanke hast du
wesentlich mehr Setupt-Zeit. Und die brauchst du eher, als die lange
Hold-Zeit...
> Koennte man obigen Code so nicht in ein FPGA packen?
Doch, aber idR. läuft so ein FPGA-Design mit einem Takt um 50-100MHz.
Und der externe uC/ISA ist dazu asynchron und damit wie ein solches
Signal zu behandeln. Will heissen: Einsynchronisieren tut Not.