-- Command Parser for Bresenham Lineplot
-- (c) 5/2009 by C.Meyer cm@ctmagazin.de
-- commercial use granted by request
-- clk driven latches GCMD_WR and TCMD_WR -cm 02.06.2009

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

entity parser is

generic (
	constant width : integer := 8
	);

port (
	clk : in std_logic;
	reset : in std_logic;
--	enable : in std_logic;
	X1 : out std_logic_vector(width-1 downto 0);
	Y1 : out std_logic_vector(width-1 downto 0);
	X2 : out std_logic_vector(width-1 downto 0);
	Y2 : out std_logic_vector(width-1 downto 0);
	GCMD_WR : in std_logic;
	TCMD_WR : in std_logic;
	XY_wr : out std_logic:='0';
	GDONE : out std_logic:='1';
	plot_done : in std_logic;
	-- Farb-Nibble INVERT(3), R(2), G(1), B(0)
	FRAMECOLOR : out std_logic_vector(3 downto 0);
	GRAPHCOLOR : out std_logic_vector(3 downto 0);
	TEXTCOLOR : out std_logic_vector(3 downto 0);
	CURSX : out std_logic_vector(7 downto 0);
	CURSY : out std_logic_vector(7 downto 0);
	
	GSMALL : out std_logic:='0';	
	GSTARTX : out std_logic_vector(7 downto 0);
	GSTARTY : out std_logic_vector(7 downto 0);
	GSIZEX : out std_logic_vector(7 downto 0);
	GSIZEY : out std_logic_vector(7 downto 0);
	GRIDX : out std_logic_vector(7 downto 0);
	GRIDY : out std_logic_vector(7 downto 0);
	
	CMD : in std_logic_vector(3 downto 0);
	DATA : in std_logic_vector(7 downto 0)
	);
end parser;

architecture behavioral of parser is
	type stateT is (sDecode,sRect1,sRect2,sRect3,sRect4,sFill1,sFill2,sNew2Old,sWait,sDone,sStop);
	signal state : stateT := sStop;
	signal nextstate : stateT := sStop;
	signal CMD_latched :std_logic_vector(3 downto 0);
	signal Xnew: std_logic_vector(width-1 downto 0):=(others =>'0');
	signal Ynew: std_logic_vector(width-1 downto 0):=(others =>'0');
	signal Xold: std_logic_vector(width-1 downto 0):=(others =>'0');
	signal Yold: std_logic_vector(width-1 downto 0):=(others =>'0');
	signal Ytemp: std_logic_vector(width-1 downto 0):=(others =>'0');
begin

-- $32x Registers/Commands, Grafik-Befehle
process(clk, GCMD_WR, CMD, reset)
begin
	if reset='1' then
		FRAMECOLOR<="0000";
		GRAPHCOLOR<="0111";
	else
		if rising_edge(clk) then --  Write to Port $32x
			if GCMD_WR='1' then
				case CMD is
				when x"0" =>	-- übernehme Xnew aus DATA
					Xnew<=DATA;
				when x"1" =>	-- übernehme Ynew aus DATA
					Ynew<=DATA;
-- in MIdpoint-Prozess dekodiert:
-- CMD = 2 - MOVETO XY
-- CMD = 3 - POINT XY (XY reg to X1Y1 and X2Y2, XY_wr), DATA ignored
-- CMD = 4 - LINE old XY to new XY (XY reg to X2Y2, XY_wr), DATA ignored
-- weitere reserviert
				when x"7" =>  -- Grafik Pixelgröße
					GSMALL<=DATA(0);
				when x"8" =>  -- Grafik Fensterposition links oben
					GSTARTX<=DATA;
				when x"9" =>  -- 
					GSTARTY<=DATA;
				when x"A" =>  -- Grafik Fenstergröße
					GSIZEX<=DATA;
				when x"B" =>  -- 
					GSIZEY<=DATA;			
				when x"C" =>  -- Grafik Grid-Weite
					GRIDX<=DATA;
				when x"D" =>  -- 
					GRIDY<=DATA;
				when x"E" =>  -- FrameColor Byte
					FRAMECOLOR<=DATA(3 downto 0);
				when x"F" =>  -- GraphColor Byte
					GRAPHCOLOR<=DATA(3 downto 0);
				when others =>
				end case;
			end if;
		end if; --end Write
	end if;
end process;

-- $33x Registers/Commands, Text-Befehle
process(clk, TCMD_WR, CMD, reset)
begin
	if reset='1' then
		TEXTCOLOR<="0010";
		CURSX<=x"00";
		CURSY<=x"00";
	else
		if rising_edge(clk) then --  Write to Port $32x
			if TCMD_WR='1' then
				case CMD is
				when x"0" =>  -- Cursor Position Xnew Byte
					CURSX<=DATA;
				when x"1" =>  -- Cursor Position Ynew Byte
					CURSY<=DATA;
					--$2 nicht belegt, reserviert für Cursor Style
				when x"3" =>  -- TextColor Byte
					TEXTCOLOR<=DATA(3 downto 0);
				when others =>
				end case;
			end if;
		end if; --end Write
	end if;
end process;

process(clk, state, reset)
begin
	if reset = '1' then
		state <= sStop;
		nextstate <= sStop;
		GDONE<='1';
	else
		if rising_edge(clk) then
			XY_wr<='0';
			case state is
			when sDecode =>
				nextstate <= sStop;
				state<=sStop;
				case CMD_latched is
				when x"2" =>		-- MOVETO (PLOT x,y,0 in BASIC)
					state <= sNew2Old;	-- sonst nichts zu tun
				when x"3" =>		-- POINT
					X1<=Xnew;
					Y1<=Ynew;
					X2<=Xnew;
					Y2<=Ynew;
					XY_wr<='1';
					nextstate <= sNew2Old;
					state<=sWait;
				when x"4" =>		-- LINE
					X1<=Xold;		
					Y1<=Yold;
					X2<=Xnew;
					Y2<=Ynew;
					XY_wr<='1';
					nextstate <= sNew2Old;
					state<=sWait;
				when x"5" =>		-- RECT
					state<=sRect1;
				when x"6" =>		-- FILL
					Ytemp<=Yold;
					state<=sFill1;
				when others =>
				end case;
			when sRect1 =>		-- erste Linie oben links nach oben rechts
				X1<=Xold;
				Y1<=Yold;
				X2<=Xnew;
				Y2<=Yold;
				XY_wr<='1'; -- Plot triggern
				nextstate <= sRect2;
				state<=sWait;
			when sRect2 =>		-- zweite Linie oben rechts nach unten rechts
				X1<=Xnew;
				Y2<=Ynew;
				XY_wr<='1';
				nextstate <= sRect3;	-- danach weiter mit sRect3
				state<=sWait;
			when sRect3 =>		-- dritte Linie unten rechts nach unten links
				Y1<=Ynew;
				X2<=Xold;
				XY_wr<='1';
				nextstate <= sRect4;	-- danach weiter mit sRect4
				state<=sWait;
			when sRect4 =>		-- vierte Linie unten links nach oben links
				X1<=Xold;
				Y2<=Yold;
				XY_wr<='1';
				nextstate <= sNew2Old;	-- danach weiter mit neu -> alt
				state<=sWait;
			when sFill1 =>	-- Rechteck füllen, von Yold nach Ynew
				X1<=Xold;
				Y1<=Ytemp;	-- war zu Beginn Yold
				X2<=Xnew;
				Y2<=Ytemp;
				XY_wr<='1'; -- Plot triggern
				nextstate <= sFill2;
				state<=sWait;
			when sFill2 =>	-- nächste Linie
				if Ytemp=Ynew then	-- Ende
					state <= sNew2Old;
				else
					if Ynew<Yold then
						Ytemp<=Ytemp-1;
					else
						Ytemp<=Ytemp+1;
					end if;
					state <= sFill1;
				end if;
			when sNew2Old =>
				Xold<=Xnew;	-- letzte Endposition wird neuer Start
				Yold<=Ynew;		
				nextstate <= sStop;
				state<=sDone;
			when sWait =>
				state<=sDone;
			when sDone =>		-- warten bis Lineplot beendet
				if plot_done='1' then
					state <= nextstate;
				else
					state <= sWait;		
				end if;
			when sStop =>
				if (GCMD_WR = '1') then
					GDONE<='0';
					CMD_latched<=CMD;	-- Adresse kann sich ändern
					state <= sDecode;
				else
					GDONE<='1';
					state <= sStop;
				end if;
			end case;
		end if; --end clock
	end if;
end process;

end behavioral;
