【tusterのFPGA作业教程】第四章:实验3——俄罗斯方块的旋转测试与动作(1)

任务1:I型模块的逆时针旋转测试与动作

        1. 完成实验表格

        本实验的解决关键在于能否正确填写下发的实验表格。如果能理解表格中填写的各位置函数关系并在代码相应位置对应更改,就可以轻松完成所有实验内容。

        上图为下发的实验表格,经观察可知:示例的I型模块旋转过程分为四个form,每旋转90°为一个form,依次对应“00”“01”“10”“11”状态。旋转前组成I型模块的四个点阵由数字1-4表示,旋转后的I型模块位置用〇表示,旋转过程中的阻挡位置用×表示。旋转中心用带圈的数字③表示。每个点阵由两个坐标函数pnx, pny表示。坐标原点位于点阵屏的左上角,即从左往右,八列点阵的坐标分别为000, 001, 010, 011, 100, 101, 110, 111,从上往下,八行点阵的坐标分别为000, 001, 010, 011, 100, 101, 110, 111(注意是从0开始,0代表第一行,这里非常重要!!!)同时,表中还给出了旋转中心的坐标限制”000″<p3y<“110″,即点阵3需要保证位于第二行至第六行。
        旋转过程中,测试空位和测试阻挡的坐标均由原始点阵坐标导出。以forms=”00″点“4”上方的阻挡为例(下图标红×),其坐标可由点“4”写出,由于其与“4”位于同一列,故横坐标相同,其位于“4”上方一个单位,故纵坐标为p4y-1。因此此阻挡的坐标可表示为p4x, p4y-1。

        旋转后的坐标由对应的点坐标导出。以forms=”00″点“1”为例,其逆时针旋转90°后位置见下图标红〇。与原坐标相比,向右移动两个单位,向下移动两个单位。故其旋转后坐标可表示为p1x+2, p1y+2。

        综上,我们可以补全表1,得到以下完整表格。

 2. 理解表格中坐标如何在代码中实现

        本实验的主要控制过程代码在模块ctrl_Irotate.vhd中给出,故我们可以研究此模块代码,来分析如何实现模块的旋转功能。通过观察给出的代码,我们可以发现影响模块旋转功能的代码主要有以下几个部分组成:

        2.1 test_n函数

when test_n=>
    case next_n is--共4种测试项
	    when"00"=>--测试旋转
		    forms<="00";--I型模块,p1 p2 p3 p4
		        --
				--
				--p1 p2 p3 p4,左上,第三行
				p1x<="000";p2x<="001";p3x<="010";p4x<="011";
				p1y<="010";p2y<="010";p3y<="010";p4y<="010";
				p5x<="111";p5y<="010";
				
        when"01"=>--测试边界
		    forms<="00";
				--
				--p1 p2 p3 p4,左上角,第2行
				p1x<="000";p2x<="001";p3x<="010";p4x<="011";
				p1y<="001";p2y<="001";p3y<="001";p4y<="001";
				p5x<="110";p5y<="111";
				
		when"10"=>--测试位置被占
		    forms<="00";
				--p1 p2 p3 p4,居中
				--      p5
				p1x<="010";p2x<="011";p3x<="100";p4x<="101";
				p1y<="100";p2y<="100";p3y<="100";p4y<="100";
				p5x<="100";p5y<="101";
				
		when"11"=>--测试旋转路径有阻挡
		    forms<="00";
				--p1 p2 p3 p4,居中
				--         p5
				p1x<="010";p2x<="011";p3x<="100";p4x<="101";
				p1y<="100";p2y<="100";p3y<="100";p4y<="100";
				p5x<="101";p5y<="101";
				
		when others=>null;
	end case;
		make<=X"1";  state<=display;

        这里给出的是四种测试项,对应实验设计任务上的正常旋转、靠近点阵四周、位置被占、旋转路径有阻挡。由第一节已知各点坐标的表示方法,即可表示出四种情况的对应坐标。其中p5表示一种可能的阻挡,在前两种情况中无需考虑,将p5设置为任意远离模块的坐标即可。在第三种情况中,需要考虑测试位置被占的情况,因此可以将p5置于p3下方,模拟旋转目标点阵位置被占的情况。同理,在第四种情况中,将p5置于p4下方。

        2.2 测试边界、空位与阻挡

--测试I型模块能否以p3为轴心逆时针旋转--
--测试边界、空位与阻挡--
when test_Lp3=>
	case test is
	--测试边界与空位1--
	when X"1"=>--test
		if(forms="00")then
			if(p3y>"000" and p3y<"110")then--边界条件
				cx<=p3x; cy<=p3y-1;  test<=X"2";--测试空位1
			else
				state<=wait_btn;--不能旋转,等待操作键
			end if;
		elsif(forms="01")then
			if(p3x>"000" and p3x<"110")then
				cx<=p3x-1; cy<=p3y;  test<=X"2";
			else
				state<=wait_btn;
			end if;
		elsif(forms="10")then
			if(p3y>"001" and p3y<"111")then
				cx<=p3x; cy<=p3y-2;  test<=X"2";
			else
				state<=wait_btn;
			end if;
		elsif(forms="11")then
			if(p3x>"001" and p3x<"111")then
				cx<=p3x-2; cy<=p3y;  test<=X"2";
			else
				state<=wait_btn;
			end if;
		end if;
	when X"2"=>
		if(dotin="1")then--高电平点亮,位置已被占
			state<=wait_btn;--不能旋转,等待操作键
		else
			test<=X"3";--有空位,测试下一个位置
	end if;
		 
	--测试空位2--
	when X"3"=>--test
		if(forms="00")then
			cx<=p3x; cy<=p3y+1;  test<=X"4";
		elsif(forms="01")then
			cx<=p3x+1; cy<=p3y;  test<=X"4";
		elsif(forms="10")then
			cx<=p3x; cy<=p3y-1;  test<=X"4";
		elsif(forms="11")then
			cx<=p3x-1; cy<=p3y;  test<=X"4";
		end if;
	when X"4"=>
		if(dotin="1")then state<=wait_btn;
		else
			test<=X"5";
	end if;
		  
	--测试空位3--
	when X"5"=>--test
		if(forms="00")then
			cx<=p3x; cy<=p3y+2;  test<=X"6";
		elsif(forms="01")then
			cx<=p3x+2; cy<=p3y;  test<=X"6";
		elsif(forms="10")then
			cx<=p3x; cy<=p3y+1;  test<=X"6";
		elsif(forms="11")then
			cx<=p3x+1; cy<=p3y;  test<=X"6";
		end if;
	when X"6"=>
		if(dotin="1")then state<=wait_btn;
		else
			test<=X"7";
	end if;
		  
	--测试阻挡1--
	when X"7"=>--test
		if(forms="00")then
			cx<=p1x; cy<=p1y+1;  test<=X"8";
		elsif(forms="01")then
			cx<=p1x+1; cy<=p1y;  test<=X"8";
		elsif(forms="10")then
			cx<=p1x; cy<=p1y-1;  test<=X"8";
		elsif(forms="11")then
			cx<=p1x-1; cy<=p1y;  test<=X"8";
		end if;
	when X"8"=>
		if(dotin="1")then --高电平点亮,有阻挡
			state<=wait_btn;--不能旋转,等待操作键
		else 
			test<=X"9";--无阻挡,测试下一个位置
	end if;
		  
	--测试阻挡2--
	when X"9"=>--test
		if(forms="00")then
			cx<=p2x; cy<=p2y+1;  test<=X"A";
		elsif(forms="01")then
			cx<=p2x+1; cy<=p2y;  test<=X"A";
		elsif(forms="10")then
			cx<=p2x; cy<=p2y-1;  test<=X"A";
		elsif(forms="11")then
			cx<=p2x-1; cy<=p2y;  test<=X"A";
		end if;
	when X"A"=>
		if(dotin="1")then 
			state<=wait_btn;
		else 
			test<=X"B";
	end if;
		  
	--测试阻挡3--
	when X"B"=>--test
		if(forms="00")then
			cx<=p2x; cy<=p2y+2;  test<=X"C";
		elsif(forms="01")then
			cx<=p2x+2; cy<=p2y;  test<=X"C";
		elsif(forms="10")then
			cx<=p2x; cy<=p2y-2;  test<=X"C";
		elsif(forms="11")then
			cx<=p2x-2; cy<=p2y;  test<=X"C";
		end if;
	when X"C"=>
		if(dotin="1")then 
			state<=wait_btn;
		else 
			test<=X"D";
	end if;
		  
	--测试阻挡4--
	when X"D"=>--test
		if(forms="00")then
			cx<=p4x; cy<=p4y-1;  test<=X"E";
		elsif(forms="01")then
			cx<=p4x-1; cy<=p4y;  test<=X"E";
		elsif(forms="10")then
			cx<=p4x; cy<=p4y+1;  test<=X"E";
		elsif(forms="11")then
			cx<=p4x+1; cy<=p4y;  test<=X"E";
		end if;
	when X"E"=>
		if(dotin="1")then 
			state<=wait_btn;
		else 
			make<=X"8";  state<=rotate_Lp3;
	end if;
	
	when others=>null;
		 
end case;

        在以上函数中,依次判断表中填写的边界条件、空位和阻挡。首先判断旋转中心p3位置是否在边界之内,否则无法旋转,跳出。在满足边界条件的情况下,依次判断空位1、空位2、空位3、阻挡1、阻挡2、阻挡3、阻挡4的点是否亮起(高电平),如果亮起则表示该位置无法旋转,跳出。注意这里的空位和阻挡要按顺序写,即空位1为表中每种状态下填写的第一个空位点(下图用黄色标出),以此类推。空位和阻挡的个数可视具体问题增删,在后续实验任务中会解释。

         2.3 I型模块以p3为轴逆时针旋转

--I型模块以p3为轴心逆时针旋转--
when rotate_Lp3=>
	case make is  --make:8~F
	--清空原片--
		when X"8"=>
			wen_tmp<="1";--开写使能
				dotout_tmp<="0";--低电平,熄灭led灯
				cx<=p1x; cy<=p1y;  make<=X"9";
			when X"9"=>
				cx<=p2x; cy<=p2y;  make<=X"A";
			when X"A"=>
				cx<=p4x; cy<=p4y;  make<=X"B";
				
			--更新p1,p2,p4新片位置--
			when X"B"=>--make
				if(forms="00")then
					p1x<=p1x+2; p1y<=p1y+2;
					p2x<=p2x+1; p2y<=p2y+1;
					p4x<=p4x-1; p4y<=p4y-1;
				elsif(forms="01")then
					p1x<=p1x+2; p1y<=p1y-2;
					p2x<=p2x+1; p2y<=p2y-1;
					p4x<=p4x-1; p4y<=p4y+1;
				elsif(forms="10")then
					p1x<=p1x-2; p1y<=p1y-2;
					p2x<=p2x-1; p2y<=p2y-1;
					p4x<=p4x+1; p4y<=p4y+1;
				elsif(forms="11")then
					p1x<=p1x-2; p1y<=p1y+2;
					p2x<=p2x-1; p2y<=p2y+1;
					p4x<=p4x+1; p4y<=p4y-1;
				end if;
				make<=X"C";
				
			--显示新片--
			when X"C"=>--make
				dotout_tmp<="1";--高电平,点亮led灯
				cx<=p1x; cy<=p1y;  make<=X"D";
			when X"D"=>
			   cx<=p2x; cy<=p2y;  make<=X"E";
			when X"E"=>
			   cx<=p4x; cy<=p4y;  make<=X"F";
				
			when X"F"=>--make
				wen_tmp<="0";--关写使能

        此函数内需要我们填写旋转后的各点坐标,与表中最后一列内容对应。注意最后“显示新片”位置需要考虑旋转轴,示例的旋转轴为p3,因此p3位置始终不更新,只需要更新p1, p2, p4的位置。 

至此,I型模块的逆时针旋转测试与动作实验所有内容全部实现,相信你也掌握了旋转控制代码的原理。接下来将更新任务2:I型模块的顺时针旋转测试与动作。敬请期待。

附:本章节需要用到的代码:

Irotate_top.vhd: 

--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

--实体
entity Irotate_top is
  port (clk_50M : in std_logic;  --50MHz
		rst : in std_logic;
		btn_in : in std_logic_vector(2 downto 0);
		
		DIN: out std_logic;
		CS: out std_logic;
		CLK_MAX7219 : out std_logic);
end;

--结构体
architecture behavioral of Irotate_top is
	component clkdiv_50M 
		port (clk_50M : in std_logic;  --50MHz
				rst : in std_logic;
				clk_btn: out std_logic;
				clk_game:out std_logic;
				clk_rama : out std_logic);
	end component;

	component btn_detect
		port (clk_btn : in std_logic;
			   rst : in std_logic;
			   btn_in : in std_logic_vector(2 downto 0);
			   btn_en : out std_logic;
			   btn_nlr : out std_logic_vector(2 downto 0));	
	end component;

	component ctrl_Irotate
		port (clk_game : in std_logic;
			   rst : in std_logic;
			   btn_en : in std_logic;
			   dotin : in std_logic_vector(0 downto 0);
			   btn_nlr : in std_logic_vector(2 downto 0);
			   addrb : out std_logic_vector(8 downto 0);
			   web : out std_logic_vector(0 downto 0);
			   dotout : out std_logic_vector(0 downto 0));
	end component;

	component ctrl_dotcasebitT
		port (clk_rama : in std_logic;
			   rst : in std_logic;
			   dataa : in std_logic_vector(0 downto 0);
			   btn_en:in std_logic;
			   dispgame:in std_logic;
			   din : out std_logic;
		 	   load_cs : out std_logic;
		 	   clk_max7219 : out std_logic;	
			   addra : out std_logic_vector(8 downto 0));	
	end component;

	component ram2ip
		port (clka : in std_logic;
			   addra : in std_logic_vector(8 downto 0);
			   wea : in std_logic_vector(0 downto 0):="0";
			   dina : in std_logic_vector(0 downto 0):="0";
			   clkb : in std_logic;
			   addrb : in std_logic_vector(8 downto 0);
			   web : in std_logic_vector(0 downto 0);
			   dinb : in std_logic_vector(0 downto 0); 
			   douta : out std_logic_vector(0 downto 0);
			   doutb : out std_logic_vector(0 downto 0));
	end component;
		 
signal clk_rama1:std_logic;
signal clk_game: std_logic;
signal clk_btn:std_logic;
signal btn_en1:std_logic;
signal btn_nlr: std_logic_vector(2 downto 0);
signal dotin1:std_logic_vector(0 downto 0);
signal addrb:std_logic_vector(8 downto 0);
signal web:std_logic_vector(0 downto 0);
signal dotout1:std_logic_vector(0 downto 0);
signal dataa1:std_logic_vector(0 downto 0);
signal addra:std_logic_vector(8 downto 0);

begin
--元件例化语句
	u1:clkdiv_50M port map(
		clk_50M => clk_50M,
		rst => rst,
		clk_rama => clk_rama1,
		clk_game => clk_game,
		clk_btn => clk_btn);
		
	u2:btn_detect port map(
		clk_btn => clk_btn,
		rst => rst,
		btn_in => btn_in,
		btn_en => btn_en1,
		btn_nlr => btn_nlr);
		
	u3:ctrl_Irotate port map(
		rst => rst,
		clk_game => clk_game,
		btn_en => btn_en1,
		btn_nlr => btn_nlr,
		dotin => dotin1,
		addrb => addrb,
		web => web,
		dotout => dotout1);
		
	u4:ctrl_dotcasebitT port map(
		clk_rama => clk_rama1,
		rst => rst,
		btn_en => btn_en1,
		dataa => dataa1,
		dispgame => btn_nlr(2),
		addra => addra,
		din => DIN,
		load_cs => CS,
		clk_max7219 => CLK_MAX7219);
		
	u5:ram2ip port map(
		clka => clk_rama1,
		addra => addra,
		clkb => clk_50M,
		addrb => addrb,
		web => web,
		dinb => dotout1,
		douta => dataa1,
		doutb => dotin1);

end behavioral;

clkdiv_50M.vhd: 

--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

--实体
entity clkdiv_50M is
  port (clk_50M : in std_logic;  --50MHz
		rst : in std_logic;
		clk_btn: out std_logic;
		clk_game:out std_logic;
		clk_rama : out std_logic);
end;

--结构体
architecture behavioral of clkdiv_50M is
    signal cnt:std_logic_vector(25 downto 0);
begin
  process(rst,clk_50M)
  begin
    if(rst='1')then
        cnt<=(others=>'0');
    elsif rising_edge(clk_50M)then
	    cnt<=cnt+1;
	end if;
  end process;

  clk_btn<=cnt(7);
  clk_game<=cnt(2);
  clk_rama<=cnt(8);
  
end behavioral;

btn_detect.vhd:

--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

--实体
entity btn_detect is
  port (clk_btn : in std_logic;
      rst : in std_logic;
		btn_in : in std_logic_vector(2 downto 0);
		btn_en : out std_logic;
		btn_nlr : out std_logic_vector(2 downto 0));	
end;
--结构体
architecture behavioral of btn_detect is
	component debounce is
		port(clk:in std_logic;
			  rst:in std_logic;
		     start:in std_logic;
		     done:out std_logic);
	end component;
	
	signal start,done:std_logic:='0';
	signal btn_down,en_tmp:std_logic:='0';
  
begin
	process(rst,clk_btn,btn_in)
	begin
		if(rst='1')then
			btn_down<='0';
		elsif rising_edge(clk_btn)then
			if(btn_in/="000")then --有键按下
				if(done='0')then
					start<='1';
				else
					start<='0';
				end if;
				if(start&done="11")then
					btn_nlr<=btn_in;
					btn_down<='1'; --确实有键按下
				end if;
			else
				btn_down<='0';
				start<='0';
			end if;
		end if;
	end process;
	
	--检测到有键按下,则btn_en翻转,控制ctrl_Irotate
	process(btn_down)
	begin
		if rising_edge(btn_down)then
		en_tmp<=not en_tmp;
		end if;
	end process;
	btn_en<=en_tmp;
	
	u2i:debounce port map(
	    clk=>clk_btn,
		 rst=>rst,
		 start=>start,
		 done=>done);
		
end behavioral;

debounce.vhd:

--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

--实体
entity debounce is
  port (clk: in std_logic;
        rst: in std_logic;
		  start: in std_logic;
		  done: out std_logic);	
end;

--结构体
architecture behavioral of debounce is
	signal cnt_delay:std_logic_vector(13 downto 0);--延时计数
	signal done_tmp:std_logic:='0';
  
begin
	process(rst,clk,start)
	begin
		if(rst='1')then
			done_tmp<='0';
			cnt_delay<=(others=>'0');
		elsif rising_edge(clk)then
			if(start='1')then --有键按下
				if(cnt_delay>X"300")then
					done_tmp<='1'; --确实有键按下
				else
					cnt_delay<=cnt_delay+1;
				end if;
			else --无键按下
				done_tmp<='0';
				cnt_delay<=(others=>'0');
			end if;
		end if;
		done<=done_tmp;
	end process;
 
end behavioral;

crtl_Irotate.vhd:

--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

--实体
entity ctrl_Irotate is
    port (clk_game: in std_logic;
          rst: in std_logic;
		  btn_en: in std_logic;
		  dotin: in std_logic_vector(0 downto 0);
		  btn_nlr: in std_logic_vector(2 downto 0);
		  addrb: out std_logic_vector(8 downto 0);
		  web: out std_logic_vector(0 downto 0);
		  dotout: out std_logic_vector(0 downto 0));	
end;


--结构体
architecture behavioral of ctrl_Irotate is
    type state_group is(wait_btn,clr_screen,test_n,display,test_Lp3,rotate_Lp3);
    signal state:state_group:=wait_btn;
  
    signal test:std_logic_vector(3 downto 0):=X"0";--测试
    signal make:std_logic_vector(3 downto 0):=X"0";--动作
    signal makex,makey:std_logic_vector(3 downto 0):=X"0";--清屏
  
    signal next_n:std_logic_vector(1 downto 0):="00";--切换测试项
    signal rst_en,btnen_tmp:std_logic:='0';
    signal wen_tmp:std_logic_vector(0 downto 0):="0";
    signal dotout_tmp:std_logic_vector(0 downto 0);
  
    signal cy:std_logic_vector(2 downto 0):="000";--8行
    signal cx:std_logic_vector(2 downto 0):="000";--8列
  
    signal p1x,p2x,p3x,p4x,p5x:std_logic_vector(2 downto 0):="000";
    signal p1y,p2y,p3y,p4y,p5y:std_logic_vector(2 downto 0):="000";

    signal forms:std_logic_vector(1 downto 0):="00";--I型模块的形状
begin
    web<=wen_tmp;
    addrb<="01"&cy&"1"&cx;--俄罗斯方块旋转测试界面的地址
    dotout<=dotout_tmp;
  
    process(rst,clk_game,btn_en,dotin,state,make,test)
    begin
    if(rst='1')then
        rst_en <= '1';
        btnen_tmp <= btn_en;
	    makey <= X"0";
        makex <= X"0";
        state <= clr_screen;
    elsif rising_edge(clk_game)then
        --识别操作键
        if(btnen_tmp/=btn_en)then
	       btnen_tmp<=not btnen_tmp;
		   --BTN3:切换测试项
		if(btn_nlr="100" and state=wait_btn)then
		  next_n<=next_n+1;
		  makey<=X"0";  makex<=X"0";  state<=clr_screen;
		--BTN2:逆时针旋转(向左转)
		elsif(btn_nlr="010"and state=wait_btn)then
		  test<=X"1";  state<=test_Lp3;
		--BTN1:顺时针旋转(向右转),此功能待开发(实验任务)
	    elsif(btn_nlr="001"and state=wait_btn)then
		  test<=X"1";state<=test_Rp3;
		end if;
	 else
	   case state is
		--等待按键操作--
		when wait_btn=>null;
		
		
		--清屏--
		when clr_screen=>
		  if(makex<X"8")then
		    wen_tmp<="1";--开写使能
			 dotout_tmp<="0";--清空点阵显示,低电平不亮
			 cx<=makex(2 downto 0);  makex<=makex+1;
			 cy<=makey(2 downto 0);
		  else
		    if(makey<X"8")then
			    makey<=makey+1;  makex<=X"0";
			 else
			   wen_tmp<="0";--关写使能
				if(rst_en='1')then
				  rst_en<='0';  state<=wait_btn;
				else state<=test_n;
				end if;
			  end if;
			end if;
			
			
		--选择新的测试项--
		when test_n=>
		  case next_n is--共4种测试项
		    when"00"=>--测试旋转
			  forms<="00";--I型模块,p1 p2 p3 p4
				--
				--
				--p1 p2 p3 p4,左上,第三行
				p1x<="000";p2x<="001";p3x<="010";p4x<="011";
				p1y<="010";p2y<="010";p3y<="010";p4y<="010";
				p5x<="111";p5y<="010";
				
      when"01"=>--测试边界
			  forms<="00";
				--
				--p1 p2 p3 p4,左上角,第2行
				p1x<="000";p2x<="001";p3x<="010";p4x<="011";
				p1y<="001";p2y<="001";p3y<="001";p4y<="001";
				p5x<="110";p5y<="111";
				
		when"10"=>--测试位置被占
			  forms<="00";
				--p1 p2 p3 p4,居中
				--      p5
				p1x<="010";p2x<="011";p3x<="100";p4x<="101";
				p1y<="100";p2y<="100";p3y<="100";p4y<="100";
				p5x<="100";p5y<="101";
				
		when"11"=>--测试旋转路径有阻挡
			  forms<="00";
				--p1 p2 p3 p4,居中
				--         p5
				p1x<="010";p2x<="011";p3x<="100";p4x<="101";
				p1y<="100";p2y<="100";p3y<="100";p4y<="100";
				p5x<="101";p5y<="101";
				
		when others=>null;
		end case;
		make<=X"1";  state<=display;
		
		--显示新的测试项形状--
		when display=>
		  case make is  --make:1~5
		    when X"1"=>
			   wen_tmp<="1";--开写使能
				dotout_tmp<="1";--高电平,点亮led灯
				cx<=p1x; cy<=p1y;  make<=X"2";
			 when X"2"=>
			   cx<=p2x; cy<=p2y;  make<=X"3";
			 when X"3"=>
			   cx<=p3x; cy<=p3y;  make<=X"4";
			  when X"4"=>
			   cx<=p4x; cy<=p4y;  make<=X"5";
			 when X"5"=>
			   cx<=p5x; cy<=p5y;  make<=X"0";
			 when others=>
			   wen_tmp<="0";--关写使能
				state<=wait_btn;--等待操作键
			 end case;
			 
				 --测试I型模块能否以p3为轴心逆时针旋转--
				 --测试边界、空位与阻挡--
			when test_Lp3=>
			  case test is
			  --测试边界与空位1--
			  when X"1"=>--test
				 if(forms="00")then
					if(p3y>"000" and p3y<"110")then--边界条件
					  cx<=p3x; cy<=p3y-1;  test<=X"2";--测试空位1
					else
					  state<=wait_btn;--不能旋转,等待操作键
					end if;
				 elsif(forms="01")then
					if(p3x>"000" and p3x<"110")then
					  cx<=p3x-1; cy<=p3y;  test<=X"2";
					else state<=wait_btn;
					end if;
					elsif(forms="10")then
					if(p3y>"001" and p3y<"111")then
					  cx<=p3x; cy<=p3y-2;  test<=X"2";
					else state<=wait_btn;
					end if;
				 elsif(forms="11")then
					if(p3x>"001" and p3x<"111")then
					  cx<=p3x-2; cy<=p3y;  test<=X"2";
					else state<=wait_btn;
					end if;
				  end if;
				when X"2"=>
				 if(dotin="1")then--高电平点亮,位置已被占
					state<=wait_btn;--不能旋转,等待操作键
				 else
					test<=X"3";--有空位,测试下一个位置
				 end if;
				 
				 --测试空位2--
				  when X"3"=>--test
				 if(forms="00")then
					 cx<=p3x; cy<=p3y+1;  test<=X"4";
				 elsif(forms="01")then
				 cx<=p3x+1; cy<=p3y;  test<=X"4";
				 elsif(forms="10")then
				 cx<=p3x; cy<=p3y-1;  test<=X"4";
				 elsif(forms="11")then
				 cx<=p3x-1; cy<=p3y;  test<=X"4";
				 end if;
				  when X"4"=>
				  if(dotin="1")then state<=wait_btn;
				  else test<=X"5";
				  end if;
				  
				  --测试空位3--
				  when X"5"=>--test
				 if(forms="00")then
					 cx<=p3x; cy<=p3y+2;  test<=X"6";
				 elsif(forms="01")then
				 cx<=p3x+2; cy<=p3y;  test<=X"6";
				 elsif(forms="10")then
				 cx<=p3x; cy<=p3y+1;  test<=X"6";
				 elsif(forms="11")then
				 cx<=p3x+1; cy<=p3y;  test<=X"6";
				 end if;
				  when X"6"=>
				  if(dotin="1")then state<=wait_btn;
				  else test<=X"7";
				  end if;
				  
				  --测试阻挡1--
				  when X"7"=>--test
				 if(forms="00")then
				 cx<=p1x; cy<=p1y+1;  test<=X"8";
				 elsif(forms="01")then
				 cx<=p1x+1; cy<=p1y;  test<=X"8";
				 elsif(forms="10")then
				 cx<=p1x; cy<=p1y-1;  test<=X"8";
				 elsif(forms="11")then
				 cx<=p1x-1; cy<=p1y;  test<=X"8";
				 end if;
				  when X"8"=>
				  if(dotin="1")then --高电平点亮,有阻挡
				  state<=wait_btn;--不能旋转,等待操作键
				  else 
				  test<=X"9";--无阻挡,测试下一个位置
				  end if;
				  
				  --测试阻挡2--
				  when X"9"=>--test
				 if(forms="00")then
				 cx<=p2x; cy<=p2y+1;  test<=X"A";
				 elsif(forms="01")then
				 cx<=p2x+1; cy<=p2y;  test<=X"A";
				 elsif(forms="10")then
				 cx<=p2x; cy<=p2y-1;  test<=X"A";
				 elsif(forms="11")then
				 cx<=p2x-1; cy<=p2y;  test<=X"A";
				 end if;
				  when X"A"=>
				  if(dotin="1")then 
				  state<=wait_btn;
				  else 
				  test<=X"B";
				  end if;
				  
				  --测试阻挡3--
				  when X"B"=>--test
				 if(forms="00")then
				 cx<=p2x; cy<=p2y+2;  test<=X"C";
				 elsif(forms="01")then
				 cx<=p2x+2; cy<=p2y;  test<=X"C";
				 elsif(forms="10")then
				 cx<=p2x; cy<=p2y-2;  test<=X"C";
				 elsif(forms="11")then
				 cx<=p2x-2; cy<=p2y;  test<=X"C";
				 end if;
				  when X"C"=>
				  if(dotin="1")then 
				  state<=wait_btn;
				  else 
				  test<=X"D";
				  end if;
				  
				  --测试阻挡4--
				  when X"D"=>--test
				 if(forms="00")then
				 cx<=p4x; cy<=p4y-1;  test<=X"E";
				 elsif(forms="01")then
				 cx<=p4x-1; cy<=p4y;  test<=X"E";
				 elsif(forms="10")then
				 cx<=p4x; cy<=p4y+1;  test<=X"E";
				 elsif(forms="11")then
				 cx<=p4x+1; cy<=p4y;  test<=X"E";
				 end if;
				  when X"E"=>
				  if(dotin="1")then 
				  state<=wait_btn;
				  else 
				  make<=X"8";  state<=rotate_Lp3;
				  end if;
				  when others=>null;
				 end case;
				 
				 
			--I型模块以p3为轴心逆时针旋转--
			when rotate_Lp3=>
			  case make is  --make:8~F
			  --清空原片--
				 when X"8"=>
					wen_tmp<="1";--开写使能
					dotout_tmp<="0";--低电平,熄灭led灯
					cx<=p1x; cy<=p1y;  make<=X"9";
				 when X"9"=>
					cx<=p2x; cy<=p2y;  make<=X"A";
				 when X"A"=>
					cx<=p4x; cy<=p4y;  make<=X"B";
					
					--更新p1,p2,p4新片位置--
					when X"B"=>--make
					if(forms="00")then
					p1x<=p1x+2; p1y<=p1y+2;
					p2x<=p2x+1; p2y<=p2y+1;
					p4x<=p4x-1; p4y<=p4y-1;
					elsif(forms="01")then
					p1x<=p1x+2; p1y<=p1y-2;
					p2x<=p2x+1; p2y<=p2y-1;
					p4x<=p4x-1; p4y<=p4y+1;
					elsif(forms="10")then
					p1x<=p1x-2; p1y<=p1y-2;
					p2x<=p2x-1; p2y<=p2y-1;
					p4x<=p4x+1; p4y<=p4y+1;
					elsif(forms="11")then
					p1x<=p1x-2; p1y<=p1y+2;
					p2x<=p2x-1; p2y<=p2y+1;
					p4x<=p4x+1; p4y<=p4y-1;
					end if;
					make<=X"C";
					
					--显示新片--
					when X"C"=>--make
						dotout_tmp<="1";--高电平,点亮led灯
						cx<=p1x; cy<=p1y;  make<=X"D";
					when X"D"=>
						cx<=p2x; cy<=p2y;  make<=X"E";
					when X"E"=>
						cx<=p4x; cy<=p4y;  make<=X"F";
					
					when X"F"=>--make
						wen_tmp<="0";--关写使能
						--切换I型模块的形状--
						if(forms="00")then forms<="01";
						elsif(forms="01")then forms<="10";
						elsif(forms="10")then forms<="11";
						elsif(forms="11")then forms<="00";
						end if;
						make<=X"0"; state<=wait_btn;
				  
						when others=>null;
					end case;
			  	
				end case;
			end if;
		end if;
			 
	end process;
end behavioral;		 

ctrl_dotcasebitT.vhd:

--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

--实体
entity ctrl_dotcasebitT is
  port (clk_rama : in std_logic;
      rst : in std_logic;
		dataa : in std_logic_vector(0 downto 0);
		btn_en:in std_logic;
		dispgame:in std_logic;
		
		din : out std_logic;
		load_cs : out std_logic;
		clk_max7219 : out std_logic;	
		addra : out std_logic_vector(8 downto 0));	
end;

--结构体
architecture behavioral of ctrl_dotcasebitT is
  type state_group is(load_shiften,SISO_16,clkedgeR_upaddr);
  signal state:state_group:=load_shiften;
  
  signal shift_en:std_logic:='0';
  signal btnen_tmp:std_logic:='0';
  
  signal addr_init:std_logic:='1';--1控制寄存器,0数据寄存器
  signal addr_game:std_logic:='0';--游戏界面/go
  signal addr_reg:std_logic_vector(2 downto 0):="000";
  signal addr_bit:std_logic_vector(3 downto 0):=X"0"; --16位数据的每一位
  
begin
  addra<=addr_init&addr_game&addr_reg&addr_bit;
  
  process(rst,clk_rama,btn_en,state,dataa)
    variable cnt_shift:std_logic_vector(3 downto 0):=X"0";--移位计数
	 variable cnt_delay:std_logic_vector(2 downto 0):="000";--延时计数
  begin
    if(rst='1')then
	 addr_init<='0';  addr_game<='0'; --进入go界面
	 addr_reg<="000";  addr_bit<=X"0";
	 btnen_tmp<=btn_en;
	 shift_en<='0';  load_cs<='1';  clk_max7219<='0';
	 cnt_shift:=X"0";  cnt_delay:="000";
	 state<=load_shiften;
  elsif rising_edge(clk_rama)then
    if(btnen_tmp/=btn_en and dispgame='1')then--切换测试项按钮
	   btnen_tmp<=not btnen_tmp;
	   addr_init<='0';  addr_game<='1'; --进入游戏的旋转测试界面
	   addr_reg<="000";  addr_bit<=X"0";
	   shift_en<='0';  load_cs<='1';  clk_max7219<='0';
	   cnt_shift:=X"0";  cnt_delay:="000";
		state<=load_shiften;
	 else
	   case state is
		  when load_shiften=>--装载锁存数据/移位使能
		    clk_max7219<='0';
		    if(shift_en='1')then
			   load_cs<='0';--允许移位
			   state<=SISO_16;
		    else
		      load_cs<='1';--装载锁存数据
			 if(cnt_delay="111")then--延时,间隔各寄存器信息
			   shift_en<='1';  cnt_delay:="000";
			 else
			   cnt_delay:=cnt_delay+1;
			 end if;
			end if;
			
    		  when SISO_16=>--16位数据串行输入、串行输出
		    clk_max7219<='0';
			 din<=dataa(0);
			 addr_bit<=addr_bit+1;--16位数据中的下一位
			 state<=clkedgeR_upaddr;
			 
			 when clkedgeR_upaddr=>--产生时钟上升沿,切换寄存器地址
			   clk_max7219<='1';--产生时钟clk_max7219上升沿
				--MAX7219各寄存器的切换
			   if(cnt_shift=X"F")then--16位移完
				  if(addr_init='1')then--MAX7219初始化
				    if(addr_reg="100")then--初始化只执行一遍
					   addr_init<='0';  addr_reg<="000";
					 else
					   addr_reg<=addr_reg+1;--下一个控制寄存器
					 end if;
				  else
				    addr_reg<=addr_reg+1;--下一个数据寄存器
				  end if;
				  shift_en<='0'; 
			     cnt_shift:=X"0";  state<=load_shiften;
			 else
			   cnt_shift:=cnt_shift+1;  state<=SISO_16;
			 end if;
		  end case;
	  end if; 
  end if;
 end process;
end behavioral;

版权声明:本文为博主作者:算了我还是睡觉吧原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/luomucraft/article/details/137783392

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2024年5月6日
下一篇 2024年5月6日

相关推荐