--====================================================================
--                  FPGA OS ver 0.1 for XILINX Edition
--           (C)Copyright 2003 Nahitafu all rights reserved.
--
--This design implements command line interface to FPGA via USB serial!
--Now, memory write, dump and I/O operations are available.
--
--License: GPL(GNU General Public License).
--Contact: http://www.nahitech.com/
--=====================================================================
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity fpgaos01 is
	Port (		CLK0      : in std_logic;
				CLK1      : in std_logic;
				CLK2      : in std_logic;
				CLK3      : in std_logic;
				USER      : inout std_logic_vector(36 downto 0);
				SD_D      : inout std_logic_vector(15 downto 0);
				SD_A      : out std_logic_vector(12 downto 0);
				SD_BS1    : out std_logic;
				SD_BS0    : out std_logic;
				SD_LDQM   : out std_logic;
				SD_UDQM   : out std_logic;
				SD_WEN    : out std_logic;
				SD_RAS    : out std_logic;
				SD_CAS    : out std_logic;
				SD_CLK    : out std_logic;
				SD_CKE    : out std_logic;
				SD_CS     : out std_logic;
				USB_D     : inout std_logic_vector(7 downto 0);
				USB_WR    : out std_logic;
				USB_RD    : out std_logic;
				USB_TXE   : in std_logic;
				USB_RXF   : in std_logic;
				USB_PWREN : in std_logic;
				USB_RSTO  : in std_logic
		);
end fpgaos01;

architecture Behavioral of fpgaos01 is
	signal CLK          : std_logic;
	signal logicH       : std_logic;
	signal logicL       : std_logic;
	signal dumpx        : std_logic_vector(3 downto 0);
	signal dumpy        : std_logic_vector(4 downto 0);
	signal OutputData   : std_logic_vector(7 downto 0);
	signal InputData    : std_logic_vector(7 downto 0);
	signal TempAddr     : std_logic_vector(8 downto 0);

	signal USB_STATE        : integer range 0 to 15;
	signal USB_RXF_node     : std_logic;
	signal USB_TXE_node     : std_logic;
	signal USB_RX_Ready     : std_logic;
	signal USB_TX_Ready     : std_logic;
	signal USB_Received     : std_logic;
	signal USB_Transmitted  : std_logic;
	signal USB_Tx_DATA      : std_logic_vector(7 downto 0);
	signal USB_Rx_DATA      : std_logic_vector(7 downto 0);
	signal USB_WR_node      : std_logic;
	signal USB_RD_node      : std_logic;

	signal   MesAddr     : integer range 0 to 511;
	constant Mes_prompt  : integer := 0;
	constant Mes_version : integer := 11;
	constant Mes_error   : integer := 73;
	constant Mes_output  : integer := 88;
	constant Mes_input   : integer := 115;
	constant Mes_help    : integer := 137;
	signal   cline       : integer range 0 to 10;
	signal   clmax       : integer range 0 to 10;
	type   charstring is array (0 to 10) of std_logic_vector(7 downto 0);
	signal   inputstr    : charstring;

	signal BRAM_STATE    : integer range 0 to 15;
	signal BRAM_ADDR     : std_logic_vector(11 downto 0);
	signal BRAM_DO       : std_logic_vector(7 downto 0);
	signal BRAM_DO0      : std_logic_vector(7 downto 0);
	signal BRAM_DO1      : std_logic_vector(7 downto 0);
	signal BRAM_DO2      : std_logic_vector(7 downto 0);
	signal BRAM_DO3      : std_logic_vector(7 downto 0);
	signal BRAM_DO4      : std_logic_vector(7 downto 0);
	signal BRAM_DO5      : std_logic_vector(7 downto 0);
	signal BRAM_DI       : std_logic_vector(7 downto 0);
	signal BRAM_WE       : std_logic;
	signal BRAM_SELECT   : std_logic_vector(5 downto 0);

	constant BRAM_ADDR_MAX : integer := 3071;
	component RAMB4_S8
		port ( DI     : in STD_LOGIC_VECTOR (7 downto 0);
        EN     : in STD_ULOGIC;
        WE     : in STD_ULOGIC;
        RST    : in STD_ULOGIC;
        CLK    : in STD_ULOGIC;
        ADDR   : in STD_LOGIC_VECTOR (8 downto 0);
        DO     : out STD_LOGIC_VECTOR (7 downto 0)
); 
	end component;

	signal   H2Ain        : std_logic_vector(3 downto 0);
	signal   H2Aout       : std_logic_vector(7 downto 0);
	signal   A2Hin        : std_logic_vector(7 downto 0);
	signal   A2Hout       : std_logic_vector(3 downto 0);
	signal   A2Herr       : std_logic;
	signal   GState       : integer range 0 to 63;
	signal   NextGState   : integer range 0 to 63;
	signal   GStateL      : std_logic_vector(5 downto 0);
	component CLKDLL port(
	    CLKFB  : in std_logic;
	    CLKIN  : in std_logic;
	    RST    : in std_logic;
	    CLK0   : out std_logic;
	    CLK180 : out std_logic;
	    CLK270 : out std_logic;
	    CLK2X  : out std_logic;
	    CLK90  : out std_logic;
	    CLKDV  : out std_logic;
	    LOCKED : out std_logic
	);
	end component;
	component BUFG port(
	    I  : in std_logic;
	    O  : out std_logic
	);
	end component;
	component IBUFG port(
	    I  : in std_logic;
	    O  : out std_logic
	);
	end component;

	signal CLK_I,CLK_O,CLK_2X : std_logic;
	signal CLK_1X_OP,CLK_2X_OP : std_logic;

begin
-- ****************************************
--    MODIFY HERE TO CUSTOMIZE I/O
	InputData <= USER(35 downto 28);
	USER(27 downto 20) <= (others=>'0');
	USER(19 downto 12) <= OutputData;
	USER(11 downto 6)  <= (others=>'0');
	USER(5 downto 0)  <= GStateL;
	CLK <= CLK0;
-- ****************************************



	SD_CLK <= CLK0;
	logicH <= '1';
	logicL <= '0';
	SD_CS     <= '1';
	SD_RAS    <= '1';
	SD_CAS    <= '1';
	SD_WEN    <= '1';
	USER(36)  <= '0';
	USB_RD <= USB_RD_node;
	USB_WR <= USB_WR_node;
	GStateL <= conv_std_logic_vector(GState,5);

    SYSROM : RAMB4_S8
    port map (
        ADDR=>BRAM_ADDR(8 downto 0),
        CLK =>CLK,
        DI  =>BRAM_DI,
		EN  =>logicH,
		RST =>logicL,
		WE  =>BRAM_WE,
		DO  =>BRAM_DO
	);
	BRAM_ADDR <= "000" & conv_std_logic_vector(MesAddr,9);

	H2Aout <= x"30" when(H2Ain =  0) else
	          x"31" when(H2Ain =  1) else
	          x"32" when(H2Ain =  2) else
	          x"33" when(H2Ain =  3) else
	          x"34" when(H2Ain =  4) else
	          x"35" when(H2Ain =  5) else
	          x"36" when(H2Ain =  6) else
	          x"37" when(H2Ain =  7) else
	          x"38" when(H2Ain =  8) else
	          x"39" when(H2Ain =  9) else
	          x"41" when(H2Ain = 10) else
	          x"42" when(H2Ain = 11) else
	          x"43" when(H2Ain = 12) else
	          x"44" when(H2Ain = 13) else
	          x"45" when(H2Ain = 14) else
	          x"46" when(H2Ain = 15) else
	          x"30";

	A2Hout <= x"0"  when(A2Hin = x"30") else
	          x"1"  when(A2Hin = x"31") else
	          x"2"  when(A2Hin = x"32") else
	          x"3"  when(A2Hin = x"33") else
	          x"4"  when(A2Hin = x"34") else
	          x"5"  when(A2Hin = x"35") else
	          x"6"  when(A2Hin = x"36") else
	          x"7"  when(A2Hin = x"37") else
	          x"8"  when(A2Hin = x"38") else
	          x"9"  when(A2Hin = x"39") else
	          x"A"  when(A2Hin = x"41") else
	          x"B"  when(A2Hin = x"42") else
	          x"C"  when(A2Hin = x"43") else
	          x"D"  when(A2Hin = x"44") else
	          x"E"  when(A2Hin = x"45") else
	          x"F"  when(A2Hin = x"46") else
	          x"A"  when(A2Hin = x"61") else
	          x"B"  when(A2Hin = x"62") else
	          x"C"  when(A2Hin = x"63") else
	          x"D"  when(A2Hin = x"64") else
	          x"E"  when(A2Hin = x"65") else
	          x"F"  when(A2Hin = x"66") else
	          x"0";
	A2Herr <= '0'   when(A2Hin >= x"30" and A2Hin <= x"39") else
	          '0'   when(A2Hin >= x"41" and A2Hin <= x"46") else
	          '0'   when(A2Hin >= x"61" and A2Hin <= x"66") else
	          '1';

	process(CLK) begin
		if (CLK'event and CLK = '1') then
			case GState is
				when 0 =>
					USB_RX_Ready <= '1';
					USB_TX_Ready <= '0';
					MesAddr <= Mes_version;
					NextGState <= 1; -- return addr(state)
					GState <= 28;    -- call sub routine
				when 1 =>
					USB_RX_Ready <= '1';
					USB_TX_Ready <= '0';
					cline <= 0;
					clmax <= 0;
					MesAddr <= Mes_prompt;
					NextGState <= 2; -- return addr(state)
					GState <= 28;    -- call sub routine
				when 2 => -- idle state
					if(USB_Received = '1') then
						USB_Tx_DATA     <= USB_Rx_DATA;
						inputstr(cline) <= USB_Rx_DATA;
						if(cline < 9) then
							cline <= cline + 1;
						end if;
						GState <= 3;
					end if;
				when 3 =>
					if(USB_Tx_DATA  = x"0d") then
						GState <= 5;
						clmax  <= cline-1;
						cline  <= 0;
					else
						USB_TX_Ready <= '1';
						GState <= 4;
					end if;
				when 4 => -- echo back
					if(USB_Transmitted = '1') then
						USB_TX_Ready <= '0';
						GState <= 2;
					end if;
				when 5 => -- CR pushed
					if(cline = clmax) then
						GState <= 1; -- print prompt
					else
						if((inputstr(cline) = x"56") or (inputstr(cline) = x"76")) then
							-- print version
							MesAddr <= Mes_version;
							NextGState <= 1;
							GState <= 28;
						elsif((inputstr(cline) = x"69") or (inputstr(cline) = x"49")) then
							-- I/O input operation
							GState <= 21;
						elsif((inputstr(cline) = x"6f") or (inputstr(cline) = x"4f")) then
							-- I/O output operation
							cline <= cline + 1;
							GState <= 18;
						elsif((inputstr(cline) = x"6d") or (inputstr(cline) = x"4d")) then
							-- modify memory
							cline <= cline + 1;
							GState <= 32;
						elsif((inputstr(cline) = x"68") or (inputstr(cline) = x"48")) then
							-- show help
							MesAddr <= Mes_help;
							NextGState <= 1;
							GState <= 28;
						elsif((inputstr(cline) = x"64") or (inputstr(cline) = x"44")) then
							--dump
							dumpx <= (others=>'0');
							dumpy <= (others=>'0');
							GState <= 6;
						else
							--syntax error
							MesAddr <= Mes_error;
							GState <= 28;
							NextGState <= 1;
						end if;
					end if;

				when 6 =>
					USB_TX_Data <= x"0d";
					NextGState <= 7;
					GState <= 26; -- call putchar()
					H2Ain  <= "000" & dumpy(4);
				when 7 =>
					USB_TX_Data <= x"0a";
					NextGState <= 8;
					GState <= 26; -- call putchar()
					H2Ain  <= "000" & dumpy(4);
				when 8 =>
					USB_TX_Data <= H2Aout;
					NextGState <= 9;
					GState <= 26; -- call putchar()
					H2Ain  <= dumpy(3 downto 0);
				when 9 =>
					USB_TX_Data <= H2Aout;
					NextGState <= 10;
					GState <= 26; -- call putchar()
				when 10 =>
					USB_TX_Data <= x"30";
					NextGState <= 11;
					GState <= 26; -- call putchar()
					MesAddr <= conv_integer(dumpy & dumpx);
				when 11 =>
					-- memory dump start
					USB_TX_Data <= x"20";
					NextGState <= 12;
					GState <= 26; -- call putchar()
				when 12 =>
					H2Ain <= BRAM_DO(7 downto 4);
					NextGState <= 13;
					GState <= 26; -- call putchar()
				when 13 =>
					USB_TX_Data <= H2Aout;
					H2Ain <= BRAM_DO(3 downto 0);
					NextGState <= 14;
					GState <= 26; -- call putchar()
				when 14 =>
					USB_TX_Data <= H2Aout;
					NextGState <= 15;
					GState <= 26; -- call putchar()
				when 15 =>
					if(dumpx = 15) then
						dumpx <= (others=>'0');
						GState <= 17;
					else
						dumpx <= dumpx + 1;
						GState <= 16;
					end if;
				when 16 =>
					MesAddr <= conv_integer(dumpy & dumpx);
					GState <= 11;
				when 17 =>
					dumpy <= dumpy + 1;
					if(dumpy = 31) then
						GState     <= 1;
					else
						GState     <= 6;
					end if;
				when 18 =>
					-- data output start
					A2Hin <= inputstr(cline); -- get first charactor
					cline <= cline + 1;
					GState <= 19;
				when 19 =>
					if(A2Herr = '1') then
						-- syntax error
						MesAddr <= Mes_error;
						GState <= 28;
						NextGState <= 1;
					elsif(inputstr(cline) = x"0d") then
						-- next char is CR
						OutputData(3 downto 0) <= A2Hout;
						OutputData(7 downto 4) <= (others=>'0');
						MesAddr <= Mes_output;
						NextGState <= 1;
						GState <= 28;
					else
						A2Hin <= inputstr(cline);
						OutputData(3 downto 0) <= A2Hout;
						GState <= 20;
					end if;
				when 20 =>
					if(A2Herr = '1') then
						-- syntax error
						MesAddr <= Mes_error;
						GState <= 28;
						NextGState <= 1;
					else
						OutputData(7 downto 4) <= OutputData(3 downto 0);
						OutputData(3 downto 0) <= A2Hout;
						MesAddr <= Mes_output;
						GState <= 28;
						NextGState <= 1;
					end if;

				when 21 =>
					-- data input start
					MesAddr <= Mes_input;
					NextGState <= 22;
					GState <= 28; -- call putstr()
				when 22 =>
					H2Ain <= InputData(7 downto 4);
					GState <= 23;
				when 23 =>
					H2Ain <= InputData(3 downto 0);
					USB_TX_Data <= H2Aout;
					NextGState <= 24;
					GState <= 26; -- call putchar()
				when 24 =>
					USB_TX_Data <= H2Aout;
					NextGState <= 1;
					GState <= 26; -- call putchar()

				when 26 =>
					-- sub putchar()
					USB_TX_Ready <= '1';
					GState <= 27;
				when 27 =>
					if(USB_Transmitted = '1') then
						USB_TX_Ready <= '0';
						GState <= NextGState;
					end if;
				when 28 =>
					-- sub putstring()
					GState <= 29;
				when 29 =>
					if(BRAM_DO /= 0) then
						USB_TX_DATA <= BRAM_DO;
						USB_TX_Ready <= '1';
						GState <= 30;
						MesAddr <= MesAddr + 1;
					else
						GState <= NextGState;
					end if;
				when 30 =>
					if(USB_Transmitted = '1') then
						USB_TX_Ready <= '0';
						GState <= 28;
					end if;
				when 32 =>
					-- memory modify
					A2Hin <= inputstr(cline); -- get first charactor
					cline <= cline + 1;
					GState <= 33;
				when 33 =>
					A2Hin <= inputstr(cline); -- get second charactor
					cline <= cline + 1;
					if(A2Herr = '1') then
						-- syntax error
						MesAddr <= Mes_error;
						GState <= 28;
						NextGState <= 1;
					else
						TempAddr(8) <= A2Hout(0);
						GState <= 34;
					end if;
				when 34 =>
					A2Hin <= inputstr(cline); -- get third charactor
					cline <= cline + 1;
					if(A2Herr = '1') then
						-- syntax error
						MesAddr <= Mes_error;
						GState <= 28;
						NextGState <= 1;
					else
						TempAddr(7 downto 4) <= A2Hout;
						GState <= 35;
					end if;
				when 35 =>
					A2Hin <= inputstr(cline); -- get 4'th charactor
					cline <= cline + 1;
					if(A2Herr = '1') then
						-- syntax error
						MesAddr <= Mes_error;
						GState <= 28;
						NextGState <= 1;
					else
						TempAddr(3 downto 0) <= A2Hout;
						GState <= 36;
					end if;
				when 36 =>
					A2Hin <= inputstr(cline); -- get 5'th charactor
					cline <= cline + 1;
					if(A2Herr = '1') then
						-- syntax error
						MesAddr <= Mes_error;
						GState <= 28;
						NextGState <= 1;
					else
						BRAM_DI(7 downto 4) <= A2Hout;
						GState <= 37;
					end if;
				when 37 =>
					A2Hin <= inputstr(cline); -- get 6'th charactor
					cline <= cline + 1;
					if(A2Herr = '1') then
						-- syntax error
						MesAddr <= Mes_error;
						GState <= 28;
						NextGState <= 1;
					else
						BRAM_DI(3 downto 0) <= A2Hout;
						GState <= 38;
					end if;
				when 38 =>
					MesAddr <= conv_integer(TempAddr);
					GState <= 39;
				when 39 =>
					BRAM_WE <= '1';
					GState <= 40;
				when 40 =>
					BRAM_WE <= '0';
					GState <= 1;
				when others =>
					GState <= 0;
			end case;
		end if;
	end process;

	process(CLK) begin
		if (CLK'event and CLK = '1') then
			USB_RXF_node <= USB_RXF;
			USB_TXE_node <= USB_TXE;
		end if;
	end process;

	USB_INT : process(CLK) begin
		if (CLK'event and CLK = '1') then
			case USB_STATE is
				when 0 =>
					USB_D  <= (others=>'Z');
					USB_Received <= '0';
					USB_Transmitted <= '0';
					if((USB_RXF_node = '0') and (USB_RX_Ready = '1')) then
						USB_RD_node <= '0'; -- at state 1
						USB_STATE <= 1;
					elsif((USB_TXE_node = '0') and (USB_TX_Ready = '1')) then
						USB_STATE <= 8;
					else
						USB_RD_node <= '1';
						USB_WR_node <= '0';
					end if;
				-- USB read sequence
				when 1 =>
					USB_STATE <= 2;
				when 2 =>
					USB_STATE <= 3;
				when 3 =>
					USB_Rx_Data  <= USB_D; -- at state 4
					USB_Received <= '1';
					USB_STATE <= 4;
				when 4 =>
					USB_RD_node <= '1'; -- at state 5
					USB_Received <= '0';
					USB_STATE <= 5;
				when 5 =>
					USB_STATE <= 6;
				when 6 =>
					USB_STATE <= 7;
				when 7 =>
					USB_RD_node <= '1';
					USB_STATE <= 0;
				-- USB write sequence
				when 8 =>
					USB_WR_node <= '1'; -- at state 9
					USB_D  <= USB_Tx_DATA;-- at state 9
					USB_STATE <= 9;
				when 9 =>
					USB_STATE <= 10;
				when 10 =>
					USB_STATE <= 11;
				when 11 =>
					USB_STATE <= 12;
				when 12 =>
					USB_WR_node <= '0'; -- at state 13
					USB_Transmitted <= '1';
					USB_STATE <= 13;
				when 13 =>
					USB_D  <= (others=>'Z');-- at state 14
					USB_Transmitted <= '0';
					USB_STATE <= 14;
				when 14 =>
					USB_STATE <= 15;
				when 15 =>
					USB_STATE <= 0;
				when others =>
					USB_STATE <= 0;
			end case;
		end if;
	end process;
end Behavioral;