Ich entwickle einen TS-CAN1-Emulator auf Atmels ATF1508AS. Ein Teil einer Anwendung ist ein wie folgt implementierter Adressdecoder (nur interessante Teile bleiben übrig):
library ieee;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity can_decoder is
port (
clk: in std_logic;
reset: in std_logic;
isa_addr: in std_logic_vector(9 downto 0);
isa_data: inout std_logic_vector(7 downto 0);
isa_ior: in std_logic;
isa_iow: in std_logic;
isa_irq: out std_logic;
isa_iochrdy: out std_logic;
sja_bus: inout std_logic_vector(7 downto 0);
sja_ior: out std_logic;
sja_iow: out std_logic;
sja_ale: out std_logic;
sja_cs: out std_logic;
sja_irq: in std_logic;
debug: out std_logic);
end can_decoder;
architecture behavioral of can_decoder is
constant SJA_ADDRESS_LOW: integer := 256; -- 0x100
constant SJA_ADDRESS_HIGH: integer := 287; -- 0x11F
constant TSCAN1_ADDRESS_LOW: integer := 336; -- 0x150
constant TSCAN1_ADDRESS_HIGH: integer := 343; -- 0x157
type state_type is (wait_for_isa,
handle_tscan1,
hold_address_and_set_ale,
hold_address_and_clear_ale,
set_read_data,
hold_read_data,
set_write_data,
hold_write_data);
signal current_state: state_type := wait_for_isa;
signal next_state: state_type := wait_for_isa;
signal address : integer;
signal next_page: std_logic_vector(1 downto 0) := "00";
signal page: std_logic_vector(1 downto 0) := "00";
signal mode_control: std_logic_vector(6 downto 0) := "0000000";
signal next_mode_control: std_logic_vector(6 downto 0) := "0000000";
signal sja_enabled: std_logic;
begin
process (clk)
begin
if (rising_edge(clk)) then
if (reset = '0') then
current_state <= wait_for_isa;
page <= "00";
mode_control <= "0000000";
else
current_state <= next_state;
page <= next_page;
mode_control <= next_mode_control;
end if;
end if;
end process;
process (current_state, isa_ior, isa_iow, isa_addr, sja_bus, sja_irq, isa_data, page, mode_control, address, sja_enabled, next_state)
begin
isa_irq <= (not sja_irq) and sja_enabled;
address <= conv_integer('0' & isa_addr);
sja_enabled <= mode_control(6);
-- this is how I know wrong state is selected
if (current_state = handle_tscan1) then
debug <= '1';
else
debug <= '0';
end if;
case current_state is
when wait_for_isa =>
if (isa_ior = '0' or isa_iow = '0') and ((address >= SJA_ADDRESS_LOW) and (SJA_ADDRESS_HIGH >= address)) and sja_enabled = '1' then
-- Address in SJA1000 range
next_state <= hold_address_and_set_ale;
elsif (isa_ior = '0' or isa_iow = '0') and ((address >= TSCAN1_ADDRESS_LOW) and (TSCAN1_ADDRESS_HIGH >= address)) then
-- Address is in TSCAN1 range
next_state <= handle_tscan1;
else
-- Address outside of interesting range (or no triggering signals)
next_state <= wait_for_isa;
end if;
when handle_tscan1 =>
if (isa_ior = '0') then
next_state <= handle_tscan1;
elsif (isa_iow = '0') then
-- next_mode_control and next_page are set here
next_state <= handle_tscan1;
else
next_state <= wait_for_isa;
end if;
when hold_address_and_set_ale =>
next_state <= hold_address_and_clear_ale;
when hold_address_and_clear_ale =>
if (isa_ior = '0') then
next_state <= set_read_data;
elsif (isa_iow = '0') then
next_state <= set_write_data;
else
next_state <= wait_for_isa;
end if;
when set_read_data =>
next_state <= hold_read_data;
when hold_read_data =>
if (isa_ior = '0' and next_state = hold_read_data) then
next_state <= hold_read_data;
else
next_state <= wait_for_isa;
end if;
when set_write_data =>
next_state <= hold_write_data;
when hold_write_data =>
if (isa_iow = '0' and next_state = hold_write_data) then
next_state <= hold_write_data;
else
next_state <= wait_for_isa;
end if;
end case;
end process;
end behavioral;
Das Problem ist, dass manchmal eine Adresse zwischen 0x100
und 0x11F
so dekodiert wird, als wäre sie zwischen 0x150
und 0x157
. Das Bild unten zeigt die Timing-Analyse von Bussen. Die erste Zeile ist eine Adresse auf dem ISA-Bus (dies ist die Adresse, die ich dekodieren muss). Die vierte Zeile ( IOW
) ist ein Signal, dessen Übergang von hoch nach niedrig eine Zustandsänderung auslösen kann, wenn die Adresse übereinstimmt. DEBUG
Signal ist hoch, wenn handle_tscan1
der Zustand erreicht wird.
Wie Sie sehen können, löst die Adresse von 0x114
und IOW = 0
den Übergang korrekt aus. Aber falscher Übergang ausgewählt. Da sollte 0x100 < 0x114 < 0x11f
der Übergang zu hold_address_and_ale
ausgewählt werden, ist aber handle_tscan1
stattdessen ausgewählt.
Ich bin ziemlich neu in der PLD-Welt, daher kenne ich noch nicht alle Fallstricke. Vielleicht mache ich etwas falsch (Bus in Ganzzahl konvertieren, Ganzzahl mit Konstanten vergleichen?). Bitte beraten.
Wenn mehr Code benötigt wird, sagen Sie es mir bitte, ich werde es posten.
Ich habe die Adresse in der Sensitivitätsliste übersehen, sie hätte so funktionieren sollen, wie sie ist. Ich dachte, ich würde mir Ihren erweiterten Code ansehen und bemerkte es.
Ist isaddr (9) in Bezug auf Dinge, die die Adresserkennung stoppen können, niedrig (ist es in der Wellenformanzeige Ihres Logikanalysators enthalten, die ISA_ADDR anzeigt?)? Wenn es hoch ist, würden Sie das Symptom erwarten, denke ich. Nach dem Vorbild eines noch nicht verbundenen Netzes.
Sie brauchen eigentlich keine Komparatoren für Adressbereiche:
constant SJA_ADDRESS_LOW: integer := 256; -- 0x100
constant SJA_ADDRESS_HIGH: integer := 287; -- 0x11F
constant TSCAN1_ADDRESS_LOW: integer := 336; -- 0x150
constant TSCAN1_ADDRESS_HIGH: integer := 343; -- 0x157
"01_0000_0000" -- 0x100
"01_0001_1111" -- 0x11F
"01_000" -- 5 bit value to recognize SJA_ADDRESS range.
SJA_ADDRESS kann mit den oberen 5 Bits von isa_addr dekodiert werden:
signal sja_address: std_logic;
sja_address <= not isa_addr(9) and isa_addr(8) and
not isa_addr(7) and not isa_addr(6) and
not isa_addr(5);
Dabei können Sie sja_address = '1' als Bedingungsausdruck verwenden.
Die Erkennung von TSCAN1_ADDRESS erfordert zwei zusätzliche Bits:
"01_0101_0000" -- 0x150
"01_0101_0111" -- 0x157
"01_0101_0" -- 7 bit value to recognize TSCAN1_ADDRESS range
signal tscan1_address: std_logic;
tscan1_address <= not isa_addr(9) and isa_addr(8) and
not isa_addr(7) and isa_addr(6) and
not isa_addr(5) and isa_addr(4) and
not isa_addr(3);
Dabei können Sie tscan1_address = '1' als Bedingungsausdruck verwenden.
Sie würden erwarten, dass sich ein gutes Synthese-Tool nicht darum kümmert und Ihnen das Äquivalent in Gates liefert.
Dieses Problem sieht so aus, als ob es eine Überprüfung der Syntheseberichte verdient, dann vielleicht eine Simulation.
Sie haben use-Klauseln in Ihrer Kontextklausel für die Pakete std_logic_arith und numeric_std beide. Die Verwendung von numeric_std für die Konvertierung in Integer würde wie folgt aussehen:
address <= to_integer(unsigned(isa_addr)); -- conv_integer('0' & isa_addr);
Sie verwenden außer conv_integer nichts anderes, was von std_logic_arith beobachtbar ist.
next_state
, damit die Flusskontrolle leicht nachverfolgt werden kann. Ich weiß nicht, ob es relevant ist, aber in jedem Flusssteuerungszweig weise ich jedes Signal zu, also gibt es keine Latches im Design. Ich habe keine Testbench bereitgestellt, weil ich keine schreiben konnte, die dieses Verhalten nachahmen würde. Die Zeitanalyse stammt von einem realen Gerät.
FRob
Adam
IOW
bei konstanter Adresse strobe. Haben Sie Ihre Eingabepfade eingeschränkt? Es tut mir leid, aber ich weiß nicht, was Sie damit meinen. Habe ich Klimmzüge/Pulldowns verwendet? Unglücklicherweise nicht. Ich habe jedoch ein Oszilloskop verwendet, um die Form und die Anstiegszeit des Busses zu überprüfen, und es sah gut aus.FRob