I am developing TS-CAN1 emulator on Atmel's ATF1508AS. One part of an application is an address decoder implemented as follows (only interesting parts are left):
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;
The problem is that sometimes an address between
0x11F is decoded as it would be between
0x157. Picture below presents timing analysis taken from buses. First row is an address on ISA bus (this is address I need to decode). Fourth row (
IOW) is a signal thats high to low transition can trigger change of state, if address matches.
DEBUG signal is high when
handle_tscan1 state is entered.
As you can see address of
IOW = 0 correctly triggers transition. But wrong transition is selected. Since
0x100 < 0x114 < 0x11f, transition to
hold_address_and_ale should be selected, but
handle_tscan1 is selected instead.
I am quite new in PLD world, so I don't know all the pitfalls yet. Maybe I am doing something wrong (converting bus to integer, comparing integer with constants?). Please advise.
If more code is needed, please tell me, I will post it.