Hola a tod@s
Estoy intentando diseñar un interface de entradas y salidas en VHDL para una XC95144XL controlada por el bus LPC del PC
, antiguo bus ISA.
Para el que no sepa de que hablo le paso estos dos links.
http://en.wikipedia.org/wiki/Low_Pin_Counthttp://www.intel.com/design/chipsets/industry/25128901.pdfEl caso es que buscando por la red encontre un ejemplo en varias páginas para monitorizar el puerto 80H y lo implemente y funciona.
Más tarde hice un pequeño programa en vB que, mediante unos botones, activar salidas de la CPLD y funciona tanto en la dirección 37FH como en cualquier otra dirección de I/O del PC, siempre y cuando el la CPLD este programada la misma dirección.
En cambio para leer entradas me encuentro encayado, ya que el bus con el que se comunican PC y CPLD es bidireccional y en el momento en que se escribe sobre el, dejan de funcionar las salidas.
El codigo de ejemplo que monitoriza el puerto 80H es el siguiente:
----------------------------------------------------------------------------------
-- IO80 catcher for LPC bus.
-- File: LPC_IOW80_1.1.VHD
-- Revision: 1.1
-- Author: Eric Leonard (partially based on Nicolas Gonthier's T3001)
-- Subsequent modifications by:
-- Detlef Herbst and Travis Evans - 08/10/05
-- Decode only I/O writes to 80h
-- Features:
-- - I/O 80 access only (internally decoded)
-- - No support for read, only write.
-- - All signals synchronous to LPC clock
-- Notes:
-- - Unless otherwise noted, all signals are active high.
-- - Suffix "n" indicate active low logic.
--
-- - Successfully implemented on Brownsville baseboard with Seven Segment
-- - display P/N SA39-11 (common Anode - Low turns on segment) from Kingbright
-- Related documents:
-- - Low Pin Count (LPC) Interface Specification, Revision 1.0 (sept 1997)
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_ARITH.ALL;
--use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity LPC_IOW80 is
Port
(
lclk: in std_logic; -- LPC: 33MHz clock (rising edge)
lframe_n: in std_logic; -- LPC: frame, active low
lreset_n: in std_logic; -- LPC: reset, active low
lad: in std_logic_vector(3 downto 0); -- LPC: multiplexed bus
seven_seg_L:out std_logic_vector(7 downto 0); -- SSeg Data output
seven_seg_H:out std_logic_vector(7 downto 0) -- SSeg Data output
);
end LPC_IOW80;
architecture RTL of LPC_IOW80 is
type LPC_State_Type is
(
IDLE, -- Waiting for a start condition
START, -- Start condition detected
WADDN3, -- I/O write address nibble 3 (A15..A12)
WADDN2, -- I/O write address nibble 2 (A11..A8 )
WADDN1, -- I/O write address nibble 1 (A7..A4)
WADDN0, -- I/O write address nibble 0 (A3-A0)
WDATN1, -- I/O write data nibble 0 (D7..D4)
WDATN0, -- I/O write data nibble 1 (D3..D0)
WHTAR0, -- I/O write host turn around phase 0
WHTAR1, -- I/O write host turn around phase 1
WSYNC, -- I/O write sync
WPTAR -- I/O write peripheral turn around
);
signal LPC_State: LPC_State_Type;
signal lframe_nreg: std_logic; -- LPC frame register
signal lad_rin: std_logic_vector(lad'range); -- LPC input registers
signal W_Data: std_logic_vector(7 downto 0); -- LPC input Post Code
begin
---------------------------------------------------------------------------
-- LPC bidirectional pins definition.
---------------------------------------------------------------------------
-- Input register to get some timing margin
P_input_register: process(lclk)
begin
if (lclk'event and lclk='1') then
lad_rin <= lad;
lframe_nreg <= lframe_n;
end if;
end process;
---------------------------------------------------------------------------
-- LPC state machine
-- LPC_State value is actually one clock cycle late.
---------------------------------------------------------------------------
P_LPC_StatMachine: process(lclk)
begin
if (lclk'event and lclk='1') then
-- Synchronous reset
if (lreset_n = '0') then
LPC_State <= IDLE;
W_Data(7 downto 0) <= "00000000"; -- init. both displays to all on
else
case LPC_State is
-- Looking for a START condition
when IDLE =>
if (lframe_nreg = '0') and (lad_rin = "0000") then
LPC_State <= START; -- START condition detected
end if;
-- Skip extra cycles on START frame
-- (can be many clock cycles)
-- and then, check for I/O write transaction
when START =>
if (lframe_nreg = '0') then -- frame still asserted
if (lad_rin /= "0000") then
LPC_State <= IDLE; -- unsupported start code
end if;
else
if (lad_rin(3 downto 1) = "001") then
LPC_State <= WADDN3; -- I/O write detected
else
LPC_State <= IDLE; -- unsupported command
end if;
end if;
-- --------------------------------
-- I/O write transaction processing
-- --------------------------------
when WADDN3 => -- Write Data Address Nibble 3
-- Find next state
if (lframe_nreg = '0') or (lad_rin /= "0000") then
LPC_State <= IDLE; -- abort cycle, bad frame
-- or address mismatch
else
LPC_State <= WADDN2;
end if;
when WADDN2 => -- Write Data Address Nibble 2
-- Find next state
if (lframe_nreg = '0') or (lad_rin /= "0000") then
LPC_State <= IDLE; -- abort cycle, bad frame
-- or address mismatch
else
LPC_State <= WADDN1;
end if;
when WADDN1 => -- Write Data Address Nibble 1
-- Find next state
if (lframe_nreg = '0') or (lad_rin /= "1000") then
LPC_State <= IDLE; -- abort cycle, bad frame
-- or address mismatch
else
LPC_State <= WADDN0;
end if;
when WADDN0 => -- Write Data Address Nibble 0
-- Find next state
if (lframe_nreg = '0') or (lad_rin /= "0000") then
LPC_State <= IDLE; -- abort cycle, bad frame
-- or address mismatch
else
-- Write address valid. Subsequent Data displays.
LPC_State <= WDATN0; -- Next state will get
-- first data nibble
end if;
when WDATN0 => -- Data LSN (Least Significant Nibble)is
-- sent first
W_Data(3 downto 0) <= lad_rin; -- latch data (LSN)
if (lframe_nreg = '1') then
LPC_State <= WDATN1; -- Next state gets
-- 2nd data nibble
else
LPC_State <= IDLE;
end if;
when WDATN1 => -- Data MSN (Most Significant Nibble)
W_Data(7 downto 4) <= lad_rin; -- latch data (MSN)
if (lframe_nreg = '1') then
LPC_State <= WHTAR0;
else
LPC_State <= IDLE;
end if;
when WHTAR0 => -- Write Data Turn Around Cycle 0
if (lframe_nreg = '1') and (lad_rin = "1111") then
LPC_State <= WHTAR1;
else
LPC_State <= IDLE;
end if;
when WHTAR1 => -- Write Data Turn Around Cycle 1
if (lframe_nreg = '1') then
LPC_State <= WSYNC;
else
LPC_State <= IDLE;
end if;
when WSYNC => -- Write Data Sync Cycle
-- Note: No device to respond with a synch at I\O addr
-- 080h. Therefore bus should time out and abort.
-- State ==> to IDLE
if (lframe_nreg = '1') then
LPC_State <= WPTAR;
else
LPC_State <= IDLE;
end if;
when WPTAR => -- Write Data Final Turn Around Cycle
-- (not needed -- see WSYNC)
LPC_State <= IDLE; -- I/O write cycle end
when others =>
LPC_State <= IDLE; -- all other cases
end case;
end if;
end if;
end process;
P_sseg_decode: process(lclk) -- decode section for 7 seg displays
begin
if (lclk'event and lclk='1') then
case W_Data(7 downto 4) is -- Most sig digit for display
when "0000" => seven_seg_H <= "00000011"; -- Hex 03 displays a 0
when "0001" => seven_seg_H <= "10011111"; -- Hex 9f displays a 1
when "0010" => seven_seg_H <= "00100101"; -- Hex 25 displays a 2
when "0011" => seven_seg_H <= "00001101"; -- Hex 0d displays a 3
when "0100" => seven_seg_H <= "10011001"; -- Hex 99 displays a 4
when "0101" => seven_seg_H <= "01001001"; -- Hex 49 displays a 5
when "0110" => seven_seg_H <= "01000001"; -- Hex 41 displays a 6
when "0111" => seven_seg_H <= "00011111"; -- Hex 1f displays a 7
when "1000" => seven_seg_H <= "00000001"; -- Hex 01 displays a 8
when "1001" => seven_seg_H <= "00001001"; -- Hex 09 displays a 9
when "1010" => seven_seg_H <= "00010001"; -- Hex 11 displays a A
when "1011" => seven_seg_H <= "11000001"; -- Hex c1 displays a b
when "1100" => seven_seg_H <= "01100011"; -- Hex 63 displays a C
when "1101" => seven_seg_H <= "10000101"; -- Hex 85 displays a d
when "1110" => seven_seg_H <= "01100001"; -- Hex 61 displays a E
when "1111" => seven_seg_H <= "01110001"; -- Hex 71 displays a F
when others => seven_seg_H <= "00000001"; -- Hex 01 displays a 8
end case;
case W_Data(3 downto 0) is -- Least sig digit for display
when "0000" => seven_seg_L <= "00000011"; -- Hex 03 displays a 0
when "0001" => seven_seg_L <= "10011111"; -- Hex 9f displays a 1
when "0010" => seven_seg_L <= "00100101"; -- Hex 25 displays a 2
when "0011" => seven_seg_L <= "00001101"; -- Hex 0d displays a 3
when "0100" => seven_seg_L <= "10011001"; -- Hex 99 displays a 4
when "0101" => seven_seg_L <= "01001001"; -- Hex 49 displays a 5
when "0110" => seven_seg_L <= "01000001"; -- Hex 41 displays a 6
when "0111" => seven_seg_L <= "00011111"; -- Hex 1f displays a 7
when "1000" => seven_seg_L <= "00000001"; -- Hex 01 displays a 8
when "1001" => seven_seg_L <= "00001001"; -- Hex 09 displays a 9
when "1010" => seven_seg_L <= "00010001"; -- Hex 11 displays a A
when "1011" => seven_seg_L <= "11000001"; -- Hex c1 displays a b
when "1100" => seven_seg_L <= "01100011"; -- Hex 63 displays a C
when "1101" => seven_seg_L <= "10000101"; -- Hex 85 displays a d
when "1110" => seven_seg_L <= "01100001"; -- Hex 61 displays a E
when "1111" => seven_seg_L <= "01110001"; -- Hex 71 displays a F
when others => seven_seg_L <= "00000001"; -- Hex 01 displays a 8
end case;
end if;
end process;
end RTL;
Agradezco de antemano vuestras aportaciones.
Salu2.