@ Johann
Georg hat es schon gesagt, du wirst das Problem mit der Warning
niemals lösen können. Das ist eine Verletzung der Setup-Zeit
(alternativ könntest du auch die Hold-Zeit verletzen), die in einem
metastabilen Verhalten der betroffenen FFs resultieren wird. Bei deinem
Design sind das die FFs der State-Machine, die kann dann beligib hin und
her hüpfen.... :-o
Dein Problem lässt sich nicht sicher lösen, weil du 3 Steuersignale
gleichzeitig hast: CS, WR und CMD.
1 | when IDLE =>
|
2 | cmd_state <= IDLE;
|
3 | if CS='1' and CMD='1' and WR='0' then
|
4 | cmd_state <= DATA_CMD;
|
5 | elsif CS='1' and CMD='0' and WR='1' then
|
6 | cmd_state <= DATA_WRITE;
|
7 | elsif CS='1' and CMD='0' and WR='0' then
|
8 | cmd_state <= DATA_READ;
|
9 | end if;
|
Was passiert hier, wenn du ausgehend von CS='0', CMD='0' und WR='0' auf
CS='1', CMD='0' und WR='1' umschaltest und dabei das WR='1' nur eine
Nanosekunde später (und dazwischen der Takt) kommt?
Richtig: du bekommst über CS='1', CMD='0' und WR='0' zwischendurch den
Zustand DATA_READ. Und das dauert...., bis der beendet ist.
Zudem hast du in diesem Augenblick eine Buskollision, weil gleichzeitig
der uC und dein CPLD Daten auf den Bus legen.
Üblicherweise ist CS low-aktiv und pegelgesteuert, und WR low-aktiv und
flankengesteuert (steigende Flanke übernimmt Daten). Dann könntest du
das Design anders aufsetzen und die Daten synchron zum WR-Impuls
übernehmen und erst danach verarbeiten.
Die Richtung des Bustreibers wird direkt vom externen Steuersignal
umgeschaltet, denn der hat die Kontrolle über den Bus.
Du solltest auch die Daten innerhalb deines Designs in zwei Richtungen
auftrennen: data_in und data_out, dann wird das mit dem Mux einfacher.
Du wechselst von einer Taktdomäne (deine externe Signale) in eine andere
Taktdomäne (der CPLD-Takt). Dazwischen müssen 2 FF-Stufen zur
Synchronisation eingefügt werden.
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 | entity tap_ctl is
|
7 | Port ( DATA : inout STD_LOGIC_VECTOR (15 downto 0);
|
8 | BUSY : out STD_LOGIC;
|
9 | WR : in STD_LOGIC;
|
10 | CMD : in STD_LOGIC;
|
11 | CS : in STD_LOGIC;
|
12 | RESET : in STD_LOGIC;
|
13 | -- Clocks GCLK0, faster clock - GCLK0 --
|
14 | GCLK0 : in STD_LOGIC
|
15 | );
|
16 | end tap_ctl;
|
17 |
|
18 |
|
19 | architecture Behavioral of tap_ctl is
|
20 |
|
21 | signal CSsr : STD_LOGIC_VECTOR (1 downto 0) := (others => '0'); -- Synchronisations-Schieberegister für CS
|
22 | signal data_in : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
|
23 | signal data_out : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
|
24 | type cmd_states is ( IDLE, DATA_CMD, DATA_WRITE, DATA_READ );
|
25 | signal cmd_state : cmd_states := IDLE;
|
26 |
|
27 | begin
|
28 | process(GCLK0) begin
|
29 | if rising_edge(GCLK0) then
|
30 | CSsr <= CSsr(0) & CS;
|
31 | end if;
|
32 | end process;
|
33 |
|
34 | uc_iface: process(GCLK0, RESET)
|
35 | begin
|
36 | if RESET = '1' then
|
37 | cmd_state <= IDLE;
|
38 | tmp_data <= (others => '0');
|
39 | elsif rising_edge(GCLK0) then
|
40 | case cmd_state is
|
41 | when IDLE =>
|
42 | cmd_state <= IDLE;
|
43 | if CSsr(1)='1' and CMD='1' and WR='0' then
|
44 | cmd_state <= DATA_CMD;
|
45 | elsif CSsr(1)='1' and CMD='0' and WR='1' then
|
46 | cmd_state <= DATA_WRITE;
|
47 | elsif CSsr(1)='1' and CMD='0' and WR='0' then
|
48 | cmd_state <= DATA_READ;
|
49 | end if;
|
50 |
|
51 | when DATA_CMD =>
|
52 | data_out <= irgendwas;
|
53 | cmd_state <= IDLE;
|
54 |
|
55 | when DATA_WRITE =>
|
56 | cmd_state <= IDLE;
|
57 |
|
58 | when DATA_READ =>
|
59 | data_out <= irgendwasanderes;
|
60 | cmd_state <= IDLE;
|
61 | end case;
|
62 | end if;
|
63 | end process uc_iface;
|
64 |
|
65 | process (WRn) begin
|
66 | if rising_edge(WRn) then
|
67 | data_in <= DATA;
|
68 | end if;
|
69 | end process;
|
70 |
|
71 | DATA <= data_out when WRn='1' else (others => 'Z'); -- Der Datenbus wird direkt vom externen signal kontrolliert
|
72 | BUSY <= '0' when cmd_state = IDLE else '1';
|
73 |
|
74 | end Behavioral;
|
BTW:
Am einfachsten wäre es allerdings, wenn du den Takt vom uC auf das CPLD
geben würdest, denn dann ist dein Design synchron zur Taktdomäne des uC.