module    controller (iCLK,iRST_N_LCD,LCD_DATA,LCD_RW,LCD_EN,LCD_RS,key,sw0,hash,plain_text,match,sys_reset); 

   input sw0,match; 
   output reg sys_reset; 
   input [3:0] key; 
   output reg [63:0] hash; 
   input wire [55:0] plain_text; 
   wire [127:0]      hash_ascii; 

   hex_to_ascii u2(hash,hash_ascii); 
   reg     	     go; 

   always@(*) 
     begin 
    if(sw0 & ~key[0]) //reset: sw0 up and key0 pressed 
      begin 
         sys_reset=1'b1; //hold the LM cracker in reset 
         go=1'b0; 
      end 
    else if(~sw0 & ~key[0])//go: sw0 down and key0 pressed 
      begin 
         go=1'b1; 
         sys_reset=1'b0; //set the LM cracker loose 
      end
 
      else if(match)
 
      begin
 
    	go=1'b0;
 
    	end 
     end 



   //     Host Side
   input    		iCLK,iRST_N_LCD; 
   //     LCD Side
   output [7:0]     	LCD_DATA; 
   output    		LCD_RW,LCD_EN,LCD_RS; 
   //     Internal Wires/Registers
   reg [5:0]     		LUT_INDEX; 
   reg [8:0]     		LUT_DATA; 
   reg [5:0]     		mLCD_ST; 
   reg [17:0]     		mDLY; 
   reg     			mLCD_Start; 
   reg [7:0]     		mLCD_DATA; 
   reg     			mLCD_RS; 
   wire     		mLCD_Done; 

   parameter    LCD_INTIAL	=	0; 
   parameter    LCD_LINE1	=	5; 
   parameter    LCD_CH_LINE	=	LCD_LINE1+16; 
   parameter    LCD_LINE2	=	LCD_LINE1+16+1; 
   //parameter    LUT_SIZE	=	LCD_LINE1+32+1; 
   parameter    LUT_SIZE	=	LCD_LINE1+32+1+1; //insert one additional command 



   //first row cursor. pressing key3 moves left sw0 and k3 to move right 
   reg [3:0]     		pos; 
   always@(posedge ms_tick) 
     begin 
    if(~key[3] && ~go) 
      begin 
         if(sw0) 
           pos=pos+4'h1; 
         else 
           pos=pos-4'h1; 
      end 
     end 


   reg k1,k2,k3; 

   //timer registers 
   reg [31:0] timer; 
   reg [31:0] timer_ms; 

   always@(posedge iCLK) 
     begin 
    timer=timer+31'd1; 
    timer_ms=timer_ms+31'd1; 

    if(timer==32'hcdfe60) //27E6/2 
      begin 
         timer=32'd0; 
         sec_tick=~sec_tick; //switch every 500ms 

      end 

    if(timer_ms==32'h2932e0) //27E6 * .1 
      begin 
         timer_ms=32'd0; 
         ms_tick=~ms_tick; //switch every 100ms 
      end 
     end 


   //time elapsed timer since start of LM crack; count in ascii 
   reg [7:0] digit3,digit2,digit1,digit0,sec; //digit 2 is msb; counts from 0000-9999minutes. sec counts from 0-60 sec 
   always@(posedge sec_tick) //posedge sec_tick is every one second 
     begin 
    if(go) 
      begin 
         if(sec==8'd59) //not ascii 
           begin 
    	  sec=8'd0; 
    	  if(digit0==8'h39) //ascii 
    	    begin 
    	       digit0=8'h30; 
    	       if(digit1==8'h39) 
    		 begin 
    		    digit1=8'h30; 
    		    if(digit2==8'h39) 
    		      begin 
    			 digit2=8'h30; 
    			 if(digit3==8'h39) 
    			   begin 
    			      digit3=8'h30; 
    			   end 
    			 else 
    			   begin 
    			      digit3=digit3+8'h01; 
    			   end 
    		      end 
    		    else 
    		      begin 
    			 digit2=digit2+8'h01; 
    		      end 
    		 
    		 end 
    	       else 
    		 begin 
    		    digit1=digit1+8'h01; 
    		 end 
    	    end		 
    	  else 
    	    begin 
    	       digit0=digit0+8'h01; 
    	    end 
    	 
           end 
         else 
           begin 
    	  sec=sec+8'd1; 
           end 
      end 
    else if(~go && ~match) 
      begin 
         digit3=8'h30; 
         digit2=8'h30; 
         digit1=8'h30; 
         digit0=8'h30; 
         sec=8'd0; 
      end 


     end 


   reg sec_tick; //1 second period 
   reg ms_tick;// 200ms period 

   wire blink; 
   assign blink = sec_tick; 

   always@(posedge ms_tick) 
     begin 
    if(~key[2] && ~go) //go up 
      begin 
         case(pos) 
           0:hash[3:0]=hash[3:0]+4'd1; 
           1:hash[7:4]=hash[7:4]+4'd1; 
           2:hash[11:8]=hash[11:8]+4'd1; 
           3:hash[15:12]=hash[15:12]+4'd1; 
           4:hash[19:16]=hash[19:16]+4'd1; 
           5:hash[23:20]=hash[23:20]+4'd1; 
           6:hash[27:24]=hash[27:24]+4'd1; 
           7:hash[31:28]=hash[31:28]+4'd1; 
           8:hash[35:32]=hash[35:32]+4'd1; 
           9:hash[39:36]=hash[39:36]+4'd1; 
           10:hash[43:40]=hash[43:40]+4'd1; 
           11:hash[47:44]=hash[47:44]+4'd1; 
           12:hash[51:48]=hash[51:48]+4'd1; 
           13:hash[55:52]=hash[55:52]+4'd1; 
           14:hash[59:56]=hash[59:56]+4'd1; 
           15:hash[63:60]=hash[63:60]+4'd1; 
         endcase 
      end 
    else if(~key[1] && ~go) //go down 
      begin 
         case(pos) 
           0:hash[3:0]=hash[3:0]-4'd1; 
           1:hash[7:4]=hash[7:4]-4'd1; 
           2:hash[11:8]=hash[11:8]-4'd1; 
           3:hash[15:12]=hash[15:12]-4'd1; 
           4:hash[19:16]=hash[19:16]-4'd1; 
           5:hash[23:20]=hash[23:20]-4'd1; 
           6:hash[27:24]=hash[27:24]-4'd1; 
           7:hash[31:28]=hash[31:28]-4'd1; 
           8:hash[35:32]=hash[35:32]-4'd1; 
           9:hash[39:36]=hash[39:36]-4'd1; 
           10:hash[43:40]=hash[43:40]-4'd1; 
           11:hash[47:44]=hash[47:44]-4'd1; 
           12:hash[51:48]=hash[51:48]-4'd1; 
           13:hash[55:52]=hash[55:52]-4'd1; 
           14:hash[59:56]=hash[59:56]-4'd1; 
           15:hash[63:60]=hash[63:60]-4'd1; 
         endcase 
      end 



     end 


   always@(posedge iCLK or negedge iRST_N_LCD) 
     begin 
    if(!iRST_N_LCD) 
      begin 
         LUT_INDEX	<=	0; 
         mLCD_ST		<=	0; 
         mDLY		<=	0; 
         mLCD_Start	<=	0; 
         mLCD_DATA	<=	0; 
         mLCD_RS		<=	0; 
      end 
    else 
      begin 
         if(LUT_INDEXbegin 
    	  case(mLCD_ST) 
    	    0:	begin 
    	       mLCD_DATA	<=	LUT_DATA[7:0]; 
    	       mLCD_RS		<=	LUT_DATA[8]; 
    	       mLCD_Start	<=	1; 
    	       mLCD_ST		<=	1; 
    	    end 
    	    1:	begin 
    	       if(mLCD_Done) 
    		 begin 
    		    mLCD_Start	<=	0; 
    		    mLCD_ST		<=	2;					 
    		 end 
    	    end 
    	    2:	begin 
    	       if(mDLY<18'h3FFFE) 
    		 mDLY	<=	mDLY+1; 
    	       else 
    		 begin 
    		    mDLY	<=	0; 
    		    mLCD_ST	<=	3; 
    		 end 
    	    end 
    	    3:	begin 
    	       LUT_INDEX	<=	LUT_INDEX+1; 
    	       mLCD_ST	<=	0; 
    	    end 
    	  endcase 
           end 
         else		//modified to redraw LCD continuously 
           begin 
    	  LUT_INDEX	<=	LCD_LINE1; //loop 
    	  mLCD_ST	<=	0; 
           end 
      end 
     end 

   always 
     begin 
    case(LUT_INDEX) 
      //	Initial 
      LCD_INTIAL+0:	LUT_DATA	<=	9'h038; 
      LCD_INTIAL+1:	LUT_DATA	<=	9'h00C; //display on off cursor and blinking command 
      LCD_INTIAL+2:	LUT_DATA	<=	9'h001; //clear display command 
      LCD_INTIAL+3:	LUT_DATA	<=	9'h006; //entry mode set command 
      LCD_INTIAL+4:	LUT_DATA	<=	9'h080;	//set ddram address to 00000000 command 
      //	Line 1 
      LCD_LINE1+0:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd15)&&~go)?8'h20:hash_ascii[127:120])};	 
      LCD_LINE1+1:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd14)&&~go)?8'h20:hash_ascii[119:112])}; 
      LCD_LINE1+2:	LUT_DATA	<=	{1'b1,match?(|plain_text[55:48]?plain_text[55:48]:8'hff):((blink&&(pos==4'd13)&&~go)?8'h20:hash_ascii[111:104])}; 
      LCD_LINE1+3:	LUT_DATA	<=	{1'b1,match?(|plain_text[47:40]?plain_text[47:40]:8'hff):((blink&&(pos==4'd12)&&~go)?8'h20:hash_ascii[103:96])}; 
      LCD_LINE1+4:	LUT_DATA	<=	{1'b1,match?(|plain_text[39:32]?plain_text[39:32]:8'hff):((blink&&(pos==4'd11)&&~go)?8'h20:hash_ascii[95:88])}; 
      LCD_LINE1+5:	LUT_DATA	<=	{1'b1,match?(|plain_text[31:24]?plain_text[31:24]:8'hff):((blink&&(pos==4'd10)&&~go)?8'h20:hash_ascii[87:80])}; 
      LCD_LINE1+6:	LUT_DATA	<=	{1'b1,match?(|plain_text[23:16]?plain_text[23:16]:8'hff):((blink&&(pos==4'd9)&&~go)?8'h20:hash_ascii[79:72])}; 
      LCD_LINE1+7:	LUT_DATA	<=	{1'b1,match?(|plain_text[15:8]?plain_text[15:8]:8'hff):((blink&&(pos==4'd8)&&~go)?8'h20:hash_ascii[71:64])}; 
      LCD_LINE1+8:	LUT_DATA	<=	{1'b1,match?(|plain_text[7:0]?plain_text[7:0]:8'hff):((blink&&(pos==4'd7)&&~go)?8'h20:hash_ascii[63:56])}; 
      LCD_LINE1+9:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd6)&&~go)?8'h20:hash_ascii[55:48])}; 
      LCD_LINE1+10:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd5)&&~go)?8'h20:hash_ascii[47:40])}; 
      LCD_LINE1+11:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd4)&&~go)?8'h20:hash_ascii[39:32])}; 
      LCD_LINE1+12:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd3)&&~go)?8'h20:hash_ascii[31:24])}; 
      LCD_LINE1+13:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd2)&&~go)?8'h20:hash_ascii[23:16])}; 
      LCD_LINE1+14:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd1)&&~go)?8'h20:hash_ascii[15:8])}; 
      LCD_LINE1+15:	LUT_DATA	<=	{1'b1,match?8'hff:((blink&&(pos==4'd0)&&~go)?8'h20:hash_ascii[7:0])}; 
      //	Change Line 
      LCD_CH_LINE:	LUT_DATA	<=	9'h0C0; 
      //	Line 2 
      LCD_LINE2+0:	LUT_DATA	<=	{1'b1,digit3}; //timer digits 
      LCD_LINE2+1:	LUT_DATA	<=	{1'b1,digit2}; 
      LCD_LINE2+2:	LUT_DATA	<=	{1'b1,digit1}; 
      LCD_LINE2+3:	LUT_DATA	<=	{1'b1,digit0}; 
      LCD_LINE2+4:	LUT_DATA	<=	9'h16d;	//m 
      LCD_LINE2+5:	LUT_DATA	<=	9'h169;	//i 
      LCD_LINE2+6:	LUT_DATA	<=	9'h16e;	//n 
      LCD_LINE2+7:	LUT_DATA	<=	9'h12e;	//. 
      LCD_LINE2+8:	LUT_DATA	<=	{1'b1,~match?(go?((blink&&go)?8'h52:8'h20):8'h20):8'h20}; //R 
      LCD_LINE2+9:	LUT_DATA	<=	{1'b1,~match?(go?((blink&&go)?8'h55:8'h20):8'h73):8'h46}; //U S F 
      LCD_LINE2+10:	LUT_DATA	<=	{1'b1,~match?(go?((blink&&go)?8'h4e:8'h20):8'h65):8'h4f}; //N E O 
      LCD_LINE2+11:	LUT_DATA	<=	{1'b1,~match?(go?((blink&&go)?8'h4e:8'h20):8'h74):8'h55}; //N T U 
      LCD_LINE2+12:	LUT_DATA	<=	{1'b1,~match?(go?((blink&&go)?8'h49:8'h20):8'h75):8'h4e}; //I U N 
      LCD_LINE2+13:	LUT_DATA	<=	{1'b1,~match?(go?((blink&&go)?8'h4e:8'h20):8'h70):8'h44}; //N P D 
      LCD_LINE2+14:	LUT_DATA	<=	{1'b1,~match?(go?((blink&&go)?8'h47:8'h20):8'h20):8'h20}; //G 
      LCD_LINE2+15:	LUT_DATA	<=	9'h120; //space 
      //return home command //modified to refresh LCD continuously 
      LCD_LINE2+16:	LUT_DATA	<=	9'h002;  //38th index 
      default:		LUT_DATA	<=	9'h000; 
    endcase 
     end 


   LCD_Controller u0(.iDATA(mLCD_DATA), 
    	     .iRS(mLCD_RS), 
    	     .iStart(mLCD_Start), 
    	     .oDone(mLCD_Done), 
    	     .iCLK(iCLK), 
    	     .iRST_N(iRST_N_LCD), 
    	     .LCD_DATA(LCD_DATA), 
    	     .LCD_RW(LCD_RW), 
    	     .LCD_EN(LCD_EN), 
    	     .LCD_RS(LCD_RS)	); 

endmodule