------------------------------------------------------------------------------- -- Title : pilote de clavier PS/2 -- Project : ------------------------------------------------------------------------------- -- File : clavier_ps2.vhd -- Author : Patrice Nouel -- Company : ENSEIRB -- Last update: 2006/01/24 -- Platform : ------------------------------------------------------------------------------- -- Description: Peripherique pour systeme altera excalibur -- : Version 2.0 avec possibilité de commande -- : Par défaut Scan Code Set 2 -- : Sur circuit Stratix 1S10 169 Mhz (precision) et 138 LC ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2002/09/24 1.0 nouel Created -- Juin 2003 : -- Mars 2004 : Version 2.0 nouel Rajout ecriture et plusieurs ameliorations -- : Un cycle d'ecriture est toujours suivi d'un cycle de lecture -- - ------------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY clavier_ps2 IS PORT ( clk : IN std_logic; -- horloge systeme (33 MHZ par défaut) reset : IN std_logic; -- reset general du circuit address : IN std_logic; -- 0 status, irqen, 1 data cs : IN std_logic; -- selection du periph rd, wr : IN std_logic; -- lecture /ecriture data_in : IN std_logic_vector(15 DOWNTO 0); -- connexion au data_out : OUT std_logic_vector(15 DOWNTO 0); -- bus avalon irq : OUT std_logic; -- interruption key_data : INOUT std_logic; -- bidirectionnel key_clk : INOUT std_logic); -- le clavier fournie l'horloge END clavier_ps2; ARCHITECTURE enseirb OF clavier_ps2 IS SIGNAL recevoir, memoriser , emettre: boolean; SIGNAL initialiser, direction_donnee: boolean; TYPE t_etat IS (debut,tempo, rts, emission, reception, memo); SIGNAL etat : t_etat; SIGNAL fin_tempo : std_logic; SIGNAL fin_octet : std_logic; SIGNAL hc_filtree : std_logic; -- horloge clavier filtree SIGNAL registre_etat : std_logic_vector(15 DOWNTO 0); -- addresse 0 SIGNAL registre_donnee : std_logic_vector(15 DOWNTO 0); -- addresse 1 SIGNAL registre_reception : std_logic_vector(10 DOWNTO 0); SIGNAL registre_commande : std_logic_vector(7 DOWNTO 0); SIGNAL aut_irq : std_logic; -- autorisation irq SIGNAL direction_horloge : boolean; SIGNAL parite : std_logic; -- cycle ecriture SIGNAL fin_emission : std_logic; -- cycle ecriture SIGNAL donnee_e : std_logic; SIGNAL donnee_s : std_logic; SIGNAL h_e : std_logic; BEGIN -- enseirb -- par securite, on introduit un filtre anti-parasite sur -- l'horloge clavier qui consiste à valider un 1 ou un 0 par 8 echantillons filtre: PROCESS VARIABLE registre : std_logic_vector(7 DOWNTO 0); BEGIN -- PROCESS filtre WAIT UNTIL rising_edge(clk); registre := registre(6 DOWNTO 0) & h_e ; IF registre = "11111111" THEN hc_filtree <= '1'; -- filtre de 8 periodes horloge END IF; IF registre = "00000000" THEN hc_filtree <= '0'; END IF; END PROCESS filtre; -- la temporisation sert à maintenir l'horloge clavier -- pendant 100 us environ lorsque le systeme veut commander -- le peripherique. temporisation: PROCESS -- duree doit être ajustée à une valeur correspondante à 100 us CONSTANT duree : natural := 8000; -- 100 us a 80 Mhz VARIABLE decompteur : natural RANGE 0 TO duree; BEGIN -- PROCESS temporisation WAIT UNTIL rising_edge(clk); -- synchrone IF initialiser THEN decompteur := duree; fin_tempo <= '0'; ELSIF decompteur /= 0 THEN decompteur := decompteur -1; ELSE fin_tempo <= '1'; END IF; END PROCESS temporisation; registres_com: PROCESS CONSTANT mot_f4 : std_logic_vector(7 DOWNTO 0) := "11110100"; BEGIN -- PROCESS WAIT UNTIL rising_edge(clk); -- synchrone IF reset = '1' THEN registre_commande <= mot_f4; aut_irq <= '0'; ELSIF cs = '1' AND wr = '1' THEN IF address = '0' THEN aut_irq <= data_IN(0); ELSE registre_commande <= data_IN(7 DOWNTO 0); END IF; END IF; END PROCESS registres_com; -- le registre emission contient FA par défaut emiss: PROCESS(emettre, hc_filtree, registre_commande, parite) VARIABLE nb_bits : natural RANGE 0 TO 11; VARIABLE registre_emission : std_logic_vector(11 DOWNTO 0); BEGIN -- PROCESS emission IF emettre = false THEN -- asynchrone registre_emission := ("01" & parite & registre_commande(7 DOWNTO 0) & '0') ; nb_bits := 0; ELSIF falling_edge(hc_filtree) THEN -- synchrone registre_emission := ('0' & registre_emission(11 DOWNTO 1)); nb_bits := nb_bits + 1; END IF; IF nb_bits = 11 THEN fin_emission <= '1'; ELSE fin_emission <= '0'; END IF; donnee_s <= registre_emission(0); END PROCESS emiss; -- le registre de reception sert soit à recevoir les octets --ou l'acquittement du mot de commande recept: PROCESS(recevoir, hc_filtree) VARIABLE nb_bits : natural RANGE 0 TO 11; BEGIN -- PROCESS reception IF recevoir = false THEN -- asynchrone nb_bits := 0; ELSIF falling_edge(hc_filtree) THEN -- synchrone registre_reception <=donnee_e & registre_reception(10 DOWNTO 1) ; nb_bits := nb_bits + 1; END IF; IF nb_bits = 11 THEN fin_octet <= '1'; ELSE fin_octet <= '0'; END IF; END PROCESS recept; -- Les 2 registres en lecture -- Status register: bit b1 : donnee dispponible -- : bit 0 est le flag d'interruption -- Data Register : octet de poids faible memor: PROCESS BEGIN -- PROCESS memor WAIT UNTIL rising_edge(clk); -- synchrone IF initialiser THEN -- reset indirect registre_etat <= (OTHERS => '0'); registre_donnee <= (OTHERS => '0'); ELSIF memoriser THEN registre_etat <= "00000000000000"& '1' & aut_irq; registre_donnee <= "00000000" & registre_reception(8 DOWNTO 1); END IF; IF cs = '1' AND rd = '1' AND address = '1' THEN registre_etat <= (OTHERS => '0'); -- acquittement par lecture des donnees END IF; END PROCESS memor; irq <= registre_etat(0); -- sortie vraie -- le sequenceur enchaine les differentes etapes et boucle -- sur la reception des octets sans aucune vérification sequenceur: PROCESS BEGIN -- PROCESS sequenceur WAIT UNTIL rising_edge(clk); -- synchrone IF reset = '1' OR (cs = '1' AND wr = '1' AND address = '1') THEN etat <= debut; ELSE CASE etat IS WHEN debut => etat <= tempo; WHEN tempo => IF fin_tempo = '1' THEN etat <= rts; END IF; WHEN rts => etat <= emission; WHEN emission => IF fin_emission = '1' THEN etat <= reception; END IF; WHEN reception => IF fin_octet = '1' THEN etat <= memo; END IF; WHEN memo => etat <= reception; END CASE; END IF; END PROCESS sequenceur; ------------------------------------------------------------------------------- -- ---------------------------------------------------------------------------- -- ---------------------------------------------------------------------------- -- Fonctions COMBINATOIRES ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- parite <= not( registre_commande(7) XOR registre_commande(6) XOR registre_commande(5) XOR registre_commande(4) XOR registre_commande(3) XOR registre_commande(2) XOR registre_commande(1) XOR registre_commande(0)); initialiser <= (etat=debut); direction_horloge <= (etat = tempo); direction_donnee <= (etat = emission) OR (etat = rts) ; emettre <= (etat = emission); recevoir <= (etat = reception); memoriser <= (etat = memo); -- separation des donnes en entree et sortie donnee_e <= key_data; key_data <= donnee_s WHEN direction_donnee ELSE 'Z'; -- separation des horloges en entree et sortie key_clk <= '0' WHEN direction_horloge ELSE 'Z'; h_e <= key_clk ; -- selection des registres sur le bus de sortie data_OUT <= registre_etat WHEN (address = '0' AND cs = '1' AND rd = '1') ELSE registre_donnee WHEN (address = '1' AND cs = '1' AND rd = '1') ELSE (OTHERS => 'Z'); END enseirb;