------------------------------------------------------------------------------- -- Title : pilote de souris PS/2 -- Project : ------------------------------------------------------------------------------- -- File : pilote_souris.vhd -- Author : -- Company : ENSEIRB -- Last update: 2007/04/06 -- Platform : ------------------------------------------------------------------------------- -- Description: ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2002/09/24 1.0 nouel Created ------------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY pilote_souris IS PORT ( horloge_24MHz : IN std_ulogic; -- horloge systeme initialiser : IN std_ulogic; -- reset general du circuit donnee_souris : INOUT std_logic; -- bidirectionnel horloge_souris : INOUT std_logic; -- la souris fournie l'horloge bouton_gauche : OUT std_ulogic; -- indique un appui bouton_milieu : OUT std_ulogic; -- indique un appui bouton_droit : OUT std_ulogic; -- indique un appui position_h : OUT signed(9 DOWNTO 0); -- excursion -512 à +511 position_v : OUT signed(9 DOWNTO 0)); -- -512 +511 END pilote_souris; ARCHITECTURE enseirb OF pilote_souris IS SIGNAL registre_emission : std_logic_vector(11 DOWNTO 0); SIGNAL recevoir, emettre, calculer : boolean; SIGNAL init_tempo, direction_donnee: boolean; SIGNAL direction_horloge : boolean; SIGNAL mouvement_h : signed(8 DOWNTO 0); SIGNAL mouvement_v : signed(8 DOWNTO 0); SIGNAL droit : std_ulogic; SIGNAL gauche : std_ulogic; SIGNAL milieu : std_ulogic; TYPE t_etat IS (debut, tempo, rts, emission, reception1, debut_trame, reception3,calcul); SIGNAL etat : t_etat; SIGNAL fin_tempo : std_ulogic; SIGNAL fin_octet : std_ulogic; SIGNAL fin_emission : std_ulogic; SIGNAL fin_trame : std_ulogic; SIGNAL data_in : std_ulogic; SIGNAL data_out : std_ulogic; SIGNAL clk_in : std_ulogic; SIGNAL hs_filtree : std_ulogic; -- horloge souris filtree BEGIN -- enseirb -- separation des donnes en entree et sortie data_in <= donnee_souris; donnee_souris <= data_out WHEN direction_donnee ELSE 'Z'; -- separation des horloges en entree et sortie horloge_souris <= '0' WHEN direction_horloge ELSE 'Z'; clk_in <= horloge_souris ; -- par securite, on introduit un filtre anti-parasite sur -- l'horloge souris 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(horloge_24MHz); registre := registre(6 DOWNTO 0) & clk_IN ; IF registre = "11111111" THEN hs_filtree <= '1'; -- filtre de 320 ns END IF; IF registre = "00000000" THEN hs_filtree <= '0'; END IF; END PROCESS filtre; -- la temporisation sert à maintenir l'horloge souris -- pendant 100 us environ lorsque le systeme veut commander -- la souris temporisation: PROCESS CONSTANT duree : natural := 2400; -- 100 us VARIABLE decompteur : natural RANGE 0 TO duree; BEGIN -- PROCESS temporisation WAIT UNTIL rising_edge(horloge_24MHz); -- synchrone IF init_tempo THEN decompteur := duree; fin_tempo <= '0'; ELSIF decompteur /= 0 THEN decompteur := decompteur -1; ELSE fin_tempo <= '1'; END IF; END PROCESS temporisation; -- le registre emission ne sert qu'a emettre la commande "stream mode" emiss: PROCESS(emettre, hs_filtree) VARIABLE nb_bits : natural RANGE 0 TO 11; VARIABLE registre_emission : std_logic_vector(11 DOWNTO 0); CONSTANT mot_f4 : std_logic_vector(11 DOWNTO 0) := "010111101000"; BEGIN -- PROCESS emission IF emettre = false THEN -- asynchrone registre_emission := mot_f4; nb_bits := 0; ELSIF falling_edge(hs_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; data_out <= registre_emission(0); END PROCESS emiss; -- le registre de reception sert soit à recevoir l'acquittement -- du mot de commande precedent -- soit de recevoir une trame complete reception : PROCESS(recevoir, hs_filtree) VARIABLE nb_bits : natural RANGE 0 TO 33; VARIABLE registre_reception : std_logic_vector(32 DOWNTO 0); BEGIN -- PROCESS emission IF recevoir = false THEN -- asynchrone nb_bits := 0; ELSIF falling_edge(hs_filtree) THEN -- synchrone registre_reception := data_in & registre_reception(32 DOWNTO 1) ; nb_bits := nb_bits + 1; END IF; IF nb_bits = 11 THEN fin_octet <= '1'; -- traitement ignoré pour l'instant ELSE fin_octet <= '0'; END IF; IF nb_bits = 33 THEN fin_trame <= '1'; ELSE fin_trame <= '0'; END IF; mouvement_v <= signed(registre_reception(6) & registre_reception(30 DOWNTO 23)); mouvement_h <= signed(registre_reception(5) & registre_reception(19 DOWNTO 12)); gauche <= registre_reception(1); milieu <= registre_reception(3); droit <= registre_reception(2); END PROCESS reception; -- pour le calcul de position, on considere que la sortie -- est un écran de 640 (horizontal)par 480 (vertical) pixels . -- Au départ on se situe au milieu de l'ecran (0,0) -- on doit limiter les excursions à +319 -320 et +239 et -240 calc: PROCESS VARIABLE registre_h : signed(10 DOWNTO 0); VARIABLE registre_v : signed(10 DOWNTO 0); CONSTANT limite_gh : integer := -320; CONSTANT limite_dh : integer := +319; CONSTANT limite_bv : integer := -240; CONSTANT limite_hv : integer := +239; BEGIN -- PROCESS WAIT UNTIL rising_edge(horloge_24MHz); -- synchrone IF init_tempo THEN -- initialisation au depart registre_h := (OTHERS => '0'); registre_v := (OTHERS => '0'); bouton_gauche <= '0'; bouton_droit <= '0'; bouton_milieu <= '0'; ELSIF calculer THEN -- accumulation registre_h := registre_h + mouvement_h; registre_v := registre_v + mouvement_v; IF registre_h > limite_dh THEN -- saturation de la sortie registre_h := to_signed(limite_dh,11); ELSIF registre_h < limite_gh THEN registre_h := to_signed(limite_gh,11); END IF; IF registre_v > limite_hv THEN registre_v := to_signed(limite_hv,11); ELSIF registre_v < limite_bv THEN registre_v := to_signed(limite_bv,11); END IF; position_v <= registre_v(9 DOWNTO 0); -- les sorties position_h <= registre_h(9 DOWNTO 0); bouton_gauche <= gauche; bouton_droit <= droit; bouton_milieu <= milieu; END IF; END PROCESS; -- le sequenceur enchaine les differentes etapes et boucle -- sur la reception des trames et leur traitement sequenceur: PROCESS BEGIN -- PROCESS sequenceur WAIT UNTIL rising_edge(horloge_24MHz); -- synchrone IF initialiser = '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 <= reception1; END IF; WHEN reception1 => IF fin_octet = '1' THEN etat <= debut_trame ; END IF; WHEN debut_trame => etat <= reception3; WHEN reception3 => IF fin_trame = '1' THEN etat <= calcul; END IF; WHEN calcul => etat <= reception3; END CASE; END IF; END PROCESS sequenceur; init_tempo <= (etat = debut); direction_horloge <= (etat = tempo); emettre <= (etat = emission); direction_donnee <= (etat = emission) OR (etat = rts) ; recevoir <= (etat = reception1) OR (etat = reception3); calculer <= (etat = calcul); END enseirb;