//generate 10 keys, 10 at a time, 4 rounds in the state machine 
module key_gen40(clk,rst,signal_done,signal_next, 
           match, 
           plain_txt, 
           k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10, 
           k11,k12,k13,k14,k15,k16,k17,k18,k19, 
           k20,k21,k22,k23,k24,k25,k26,k27,k28,k29, 
           k30,k31,k32,k33,k34,k35,k36,k37,k38,k39); 


   /**add control for ledg progress**/ 
   input wire rst,clk; 

   wire [6:0] b1[9:0]; 
   wire [6:0] b2[9:0]; 
   wire [6:0] b3[9:0]; 
   wire [6:0] b4[9:0]; 
   wire [6:0] b5[9:0]; 
   wire [6:0] b6[9:0]; 
   wire [6:0] b7[9:0]; 

   wire      c1,c2,c3,c4,c5; 

   input wire      signal_done; 
   output reg      signal_next; 
   wire      signal_match; 

   input wire [39:0] match;     //  match vector from the DES units


   output reg [55:0]  plain_txt;    //  store the key when brute-force attack has found it
   reg [63:0]           ascii[9:0][3:0]; //first dimension is the 10 parallel keys (left),right 
   //  dimension is the for the 5 founds of the state machine


   reg [63:0]           ascii_next[9:0][3:0]; 


   output wire [63:0] k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10, 
    	      k11,k12,k13,k14,k15,k16,k17,k18,k19, 
    	      k20,k21,k22,k23,k24,k25,k26,k27,k28,k29, 
    	      k30,k31,k32,k33,k34,k35,k36,k37,k38,k39; //  generated keys

   assign k0 = ascii[0][0];     //  10 keys from round 1
   assign k1 = ascii[1][0]; 
   assign k2 = ascii[2][0]; 
   assign k3 = ascii[3][0]; 
   assign k4 = ascii[4][0]; 
   assign k5 = ascii[5][0]; 
   assign k6 = ascii[6][0]; 
   assign k7 = ascii[7][0]; 
   assign k8 = ascii[8][0]; 
   assign k9 = ascii[9][0]; 

   assign k10 = ascii[0][1];    //  10 keys from round 2
   assign k11 = ascii[1][1]; 
   assign k12 = ascii[2][1]; 
   assign k13 = ascii[3][1]; 
   assign k14 = ascii[4][1]; 
   assign k15 = ascii[5][1]; 
   assign k16 = ascii[6][1]; 
   assign k17 = ascii[7][1]; 
   assign k18 = ascii[8][1]; 
   assign k19 = ascii[9][1]; 

   assign k20 = ascii[0][2];    //  10 keys from round 3 etc...
   assign k21 = ascii[1][2]; 
   assign k22 = ascii[2][2]; 
   assign k23 = ascii[3][2]; 
   assign k24 = ascii[4][2]; 
   assign k25 = ascii[5][2]; 
   assign k26 = ascii[6][2]; 
   assign k27 = ascii[7][2]; 
   assign k28 = ascii[8][2]; 
   assign k29 = ascii[9][2]; 

   assign k30 = ascii[0][3]; 
   assign k31 = ascii[1][3]; 
   assign k32 = ascii[2][3]; 
   assign k33 = ascii[3][3]; 
   assign k34 = ascii[4][3]; 
   assign k35 = ascii[5][3]; 
   assign k36 = ascii[6][3]; 
   assign k37 = ascii[7][3]; 
   assign k38 = ascii[8][3]; 
   assign k39 = ascii[9][3]; 

   reg [7:0]          state; 

   //8bits supports 0-255 or 256 parallelizations 
   reg [7:0]          cnt; 

   wire [55:0]          nk[9:0];      //  new key from the LUT and key generating counters

   reg     	     c_clk;	// signal to increment the 0-69 counters 

   reg [7:0]          i;	// index to keep track of which key we're generating (n keys) 
   reg [7:0]          unit; //counter; used to find which DES unit found the key 


   count count0(b1[0],b2[0],b3[0],b4[0],b5[0],b6[0],b7[0],c_clk,rst,7'd0); 
   count count1(b1[1],b2[1],b3[1],b4[1],b5[1],b6[1],b7[1],c_clk,rst,7'd1); 
   count count2(b1[2],b2[2],b3[2],b4[2],b5[2],b6[2],b7[2],c_clk,rst,7'd2); 
   count count3(b1[3],b2[3],b3[3],b4[3],b5[3],b6[3],b7[3],c_clk,rst,7'd3); 
   count count4(b1[4],b2[4],b3[4],b4[4],b5[4],b6[4],b7[4],c_clk,rst,7'd4); 
   count count5(b1[5],b2[5],b3[5],b4[5],b5[5],b6[5],b7[5],c_clk,rst,7'd5); 
   count count6(b1[6],b2[6],b3[6],b4[6],b5[6],b6[6],b7[6],c_clk,rst,7'd6); 
   count count7(b1[7],b2[7],b3[7],b4[7],b5[7],b6[7],b7[7],c_clk,rst,7'd7); 
   count count8(b1[8],b2[8],b3[8],b4[8],b5[8],b6[8],b7[8],c_clk,rst,7'd8); 
   count count9(b1[9],b2[9],b3[9],b4[9],b5[9],b6[9],b7[9],c_clk,rst,7'd9); 

   char_space_lut lut0(b1[0],b2[0],b3[0],b4[0],b5[0],b6[0],b7[0],nk[0]); 
   char_space_lut lut1(b1[1],b2[1],b3[1],b4[1],b5[1],b6[1],b7[1],nk[1]); 
   char_space_lut lut2(b1[2],b2[2],b3[2],b4[2],b5[2],b6[2],b7[2],nk[2]); 
   char_space_lut lut3(b1[3],b2[3],b3[3],b4[3],b5[3],b6[3],b7[3],nk[3]); 
   char_space_lut lut4(b1[4],b2[4],b3[4],b4[4],b5[4],b6[4],b7[4],nk[4]); 
   char_space_lut lut5(b1[5],b2[5],b3[5],b4[5],b5[5],b6[5],b7[5],nk[5]); 
   char_space_lut lut6(b1[6],b2[6],b3[6],b4[6],b5[6],b6[6],b7[6],nk[6]); 
   char_space_lut lut7(b1[7],b2[7],b3[7],b4[7],b5[7],b6[7],b7[7],nk[7]); 
   char_space_lut lut8(b1[8],b2[8],b3[8],b4[8],b5[8],b6[8],b7[8],nk[8]); 
   char_space_lut lut9(b1[9],b2[9],b3[9],b4[9],b5[9],b6[9],b7[9],nk[9]); 


   assign signal_match = |match; 
   wire [6:0]          l_index, r_index; 
   assign r_index = (unit - unit%10)/10; 
   assign l_index = unit%10; 

   always@(posedge clk or posedge rst)//add or reset 
     begin 
    if(rst) 
      begin 
         plain_txt = 56'b0; 
         signal_next = 1'b0; 
         c_clk = 1'b0; 
         state = 8'd0; 
         i=8'd1; 
         //upon reset, the first key is already available. 

         ascii_next[0][0]={nk[0][55:49],1'b0, //  pad with dummy parity bit
    		       nk[0][48:42],1'b0, 
    		       nk[0][41:35],1'b0, 
    		       nk[0][34:28],1'b0, 
    		       nk[0][27:21],1'b0, 
    		       nk[0][20:14],1'b0, 
    		       nk[0][13:7],1'b0, 
    		       nk[0][6:0],1'b0}; 
         ascii_next[1][0]={nk[1][55:49],1'b0, //  pad with dummy parity bit
    		       nk[1][48:42],1'b0, 
    		       nk[1][41:35],1'b0, 
    		       nk[1][34:28],1'b0, 
    		       nk[1][27:21],1'b0, 
    		       nk[1][20:14],1'b0, 
    		       nk[1][13:7],1'b0, 
    		       nk[1][6:0],1'b0}; 
         ascii_next[2][0]={nk[2][55:49],1'b0, //  pad with dummy parity bit
    		       nk[2][48:42],1'b0, 
    		       nk[2][41:35],1'b0, 
    		       nk[2][34:28],1'b0, 
    		       nk[2][27:21],1'b0, 
    		       nk[2][20:14],1'b0, 
    		       nk[2][13:7],1'b0, 
    		       nk[2][6:0],1'b0}; 
         ascii_next[3][0]={nk[3][55:49],1'b0, //  pad with dummy parity bit
    		       nk[3][48:42],1'b0, 
    		       nk[3][41:35],1'b0, 
    		       nk[3][34:28],1'b0, 
    		       nk[3][27:21],1'b0, 
    		       nk[3][20:14],1'b0, 
    		       nk[3][13:7],1'b0, 
    		       nk[3][6:0],1'b0}; 
         ascii_next[4][0]={nk[4][55:49],1'b0, //  pad with dummy parity bit
    		       nk[4][48:42],1'b0, 
    		       nk[4][41:35],1'b0, 
    		       nk[4][34:28],1'b0, 
    		       nk[4][27:21],1'b0, 
    		       nk[4][20:14],1'b0, 
    		       nk[4][13:7],1'b0, 
    		       nk[4][6:0],1'b0}; 
         ascii_next[5][0]={nk[5][55:49],1'b0, //  pad with dummy parity bit
    		       nk[5][48:42],1'b0, 
    		       nk[5][41:35],1'b0, 
    		       nk[5][34:28],1'b0, 
    		       nk[5][27:21],1'b0, 
    		       nk[5][20:14],1'b0, 
    		       nk[5][13:7],1'b0, 
    		       nk[5][6:0],1'b0}; 
         ascii_next[6][0]={nk[6][55:49],1'b0, //  pad with dummy parity bit
    		       nk[6][48:42],1'b0, 
    		       nk[6][41:35],1'b0, 
    		       nk[6][34:28],1'b0, 
    		       nk[6][27:21],1'b0, 
    		       nk[6][20:14],1'b0, 
    		       nk[6][13:7],1'b0, 
    		       nk[6][6:0],1'b0}; 
         ascii_next[7][0]={nk[7][55:49],1'b0, //  pad with dummy parity bit
    		       nk[7][48:42],1'b0, 
    		       nk[7][41:35],1'b0, 
    		       nk[7][34:28],1'b0, 
    		       nk[7][27:21],1'b0, 
    		       nk[7][20:14],1'b0, 
    		       nk[7][13:7],1'b0, 
    		       nk[7][6:0],1'b0}; 
         ascii_next[8][0]={nk[8][55:49],1'b0, //  pad with dummy parity bit
    		       nk[8][48:42],1'b0, 
    		       nk[8][41:35],1'b0, 
    		       nk[8][34:28],1'b0, 
    		       nk[8][27:21],1'b0, 
    		       nk[8][20:14],1'b0, 
    		       nk[8][13:7],1'b0, 
    		       nk[8][6:0],1'b0}; 
         ascii_next[9][0]={nk[9][55:49],1'b0, //  pad with dummy parity bit
    		       nk[9][48:42],1'b0, 
    		       nk[9][41:35],1'b0, 
    		       nk[9][34:28],1'b0, 
    		       nk[9][27:21],1'b0, 
    		       nk[9][20:14],1'b0, 
    		       nk[9][13:7],1'b0, 
    		       nk[9][6:0],1'b0}; 


      end 
    else 
      begin 
         case(state) 
           	 
           0: 
    	 begin 
    	    c_clk=1'b1; //  create posedge to advance the counters
    	    state=8'd1; 
    	 end 

           1: 
    	 begin 
    	    ascii_next[0][i]={nk[0][55:49],1'b0, //  pad with dummy parity bit
    			      nk[0][48:42],1'b0, 
    			      nk[0][41:35],1'b0, 
    			      nk[0][34:28],1'b0, 
    			      nk[0][27:21],1'b0, 
    			      nk[0][20:14],1'b0, 
    			      nk[0][13:7],1'b0, 
    			      nk[0][6:0],1'b0}; 
    	    ascii_next[1][i]={nk[1][55:49],1'b0, //  pad with dummy parity bit
    			      nk[1][48:42],1'b0, 
    			      nk[1][41:35],1'b0, 
    			      nk[1][34:28],1'b0, 
    			      nk[1][27:21],1'b0, 
    			      nk[1][20:14],1'b0, 
    			      nk[1][13:7],1'b0, 
    			      nk[1][6:0],1'b0}; 
    	    ascii_next[2][i]={nk[2][55:49],1'b0, //  pad with dummy parity bit
    			      nk[2][48:42],1'b0, 
    			      nk[2][41:35],1'b0, 
    			      nk[2][34:28],1'b0, 
    			      nk[2][27:21],1'b0, 
    			      nk[2][20:14],1'b0, 
    			      nk[2][13:7],1'b0, 
    			      nk[2][6:0],1'b0}; 
    	    ascii_next[3][i]={nk[3][55:49],1'b0, //  pad with dummy parity bit
    			      nk[3][48:42],1'b0, 
    			      nk[3][41:35],1'b0, 
    			      nk[3][34:28],1'b0, 
    			      nk[3][27:21],1'b0, 
    			      nk[3][20:14],1'b0, 
    			      nk[3][13:7],1'b0, 
    			      nk[3][6:0],1'b0}; 
    	    ascii_next[4][i]={nk[4][55:49],1'b0, //  pad with dummy parity bit
    			      nk[4][48:42],1'b0, 
    			      nk[4][41:35],1'b0, 
    			      nk[4][34:28],1'b0, 
    			      nk[4][27:21],1'b0, 
    			      nk[4][20:14],1'b0, 
    			      nk[4][13:7],1'b0, 
    			      nk[4][6:0],1'b0}; 
    	    ascii_next[5][i]={nk[5][55:49],1'b0, //  pad with dummy parity bit
    			      nk[5][48:42],1'b0, 
    			      nk[5][41:35],1'b0, 
    			      nk[5][34:28],1'b0, 
    			      nk[5][27:21],1'b0, 
    			      nk[5][20:14],1'b0, 
    			      nk[5][13:7],1'b0, 
    			      nk[5][6:0],1'b0}; 
    	    ascii_next[6][i]={nk[6][55:49],1'b0, //  pad with dummy parity bit
    			      nk[6][48:42],1'b0, 
    			      nk[6][41:35],1'b0, 
    			      nk[6][34:28],1'b0, 
    			      nk[6][27:21],1'b0, 
    			      nk[6][20:14],1'b0, 
    			      nk[6][13:7],1'b0, 
    			      nk[6][6:0],1'b0}; 
    	    ascii_next[7][i]={nk[7][55:49],1'b0, //  pad with dummy parity bit
    			      nk[7][48:42],1'b0, 
    			      nk[7][41:35],1'b0, 
    			      nk[7][34:28],1'b0, 
    			      nk[7][27:21],1'b0, 
    			      nk[7][20:14],1'b0, 
    			      nk[7][13:7],1'b0, 
    			      nk[7][6:0],1'b0}; 
    	    ascii_next[8][i]={nk[8][55:49],1'b0, //  pad with dummy parity bit
    			      nk[8][48:42],1'b0, 
    			      nk[8][41:35],1'b0, 
    			      nk[8][34:28],1'b0, 
    			      nk[8][27:21],1'b0, 
    			      nk[8][20:14],1'b0, 
    			      nk[8][13:7],1'b0, 
    			      nk[8][6:0],1'b0}; 
    	    ascii_next[9][i]={nk[9][55:49],1'b0, //  pad with dummy parity bit
    			      nk[9][48:42],1'b0, 
    			      nk[9][41:35],1'b0, 
    			      nk[9][34:28],1'b0, 
    			      nk[9][27:21],1'b0, 
    			      nk[9][20:14],1'b0, 
    			      nk[9][13:7],1'b0, 
    			      nk[9][6:0],1'b0}; 
    	 

    	    c_clk=1'b0; //  create negedge
    	    i=i+8'd1; 

    	    if(i=='d4)	// 4 rounds 
    	      begin 
    		 state=8'd2; //  done generating key for all the n DES units
    	      end 
    	    else 
    	      begin 
    		 state=8'd0; //  generate next key
    	      end 
    	 
    	 end //  case: 1

           2:		// signal_done? 
    	 begin 
    	    if(signal_done) 
    	      begin 
    		 state=8'd3; 
    	      end 
    	 end //  case: 0

           3: 
    	 begin 
    	    if(signal_match) //  or all the bits of match
    	      begin 
    		 state=8'd6; //  a unit found the key
    		 unit=8'd0; //  reset the counter for state6
    		 
    	      end 
    	    else 
    	      begin 
    		 ascii[0][0]=ascii_next[0][0]; //  swap in the new keys
    		 ascii[1][0]=ascii_next[1][0]; 
    		 ascii[2][0]=ascii_next[2][0]; 
    		 ascii[3][0]=ascii_next[3][0]; 
    		 ascii[4][0]=ascii_next[4][0]; 
    		 ascii[5][0]=ascii_next[5][0]; 
    		 ascii[6][0]=ascii_next[6][0]; 
    		 ascii[7][0]=ascii_next[7][0]; 
    		 ascii[8][0]=ascii_next[8][0]; 
    		 ascii[9][0]=ascii_next[9][0]; 
    		 
    		 ascii[0][1]=ascii_next[0][1]; 
    		 ascii[1][1]=ascii_next[1][1]; 
    		 ascii[2][1]=ascii_next[2][1]; 
    		 ascii[3][1]=ascii_next[3][1]; 
    		 ascii[4][1]=ascii_next[4][1]; 
    		 ascii[5][1]=ascii_next[5][1]; 
    		 ascii[6][1]=ascii_next[6][1]; 
    		 ascii[7][1]=ascii_next[7][1]; 
    		 ascii[8][1]=ascii_next[8][1]; 
    		 ascii[9][1]=ascii_next[9][1]; 
    		 
    		 ascii[0][2]=ascii_next[0][2]; 
    		 ascii[1][2]=ascii_next[1][2]; 
    		 ascii[2][2]=ascii_next[2][2]; 
    		 ascii[3][2]=ascii_next[3][2]; 
    		 ascii[4][2]=ascii_next[4][2]; 
    		 ascii[5][2]=ascii_next[5][2]; 
    		 ascii[6][2]=ascii_next[6][2]; 
    		 ascii[7][2]=ascii_next[7][2]; 
    		 ascii[8][2]=ascii_next[8][2]; 
    		 ascii[9][2]=ascii_next[9][2]; 
    		 
    		 ascii[0][3]=ascii_next[0][3]; 
    		 ascii[1][3]=ascii_next[1][3]; 
    		 ascii[2][3]=ascii_next[2][3]; 
    		 ascii[3][3]=ascii_next[3][3]; 
    		 ascii[4][3]=ascii_next[4][3]; 
    		 ascii[5][3]=ascii_next[5][3]; 
    		 ascii[6][3]=ascii_next[6][3]; 
    		 ascii[7][3]=ascii_next[7][3]; 
    		 ascii[8][3]=ascii_next[8][3]; 
    		 ascii[9][3]=ascii_next[9][3]; 
    		 
    		 state=8'd4; //  start next round of computations
    	      end 
    	 end 

           4: 
    	 begin 
    	    signal_next=1'b1; //  posedge signal to start DES calculations
    	    state=8'd5; 
    	 
    	 end 
           5: 
    	 begin 
    	    signal_next=1'b0; //  negedge deactivate
    	    i=8'd0;	      //  reset the counter for key generation
    	    state=8'd0;	      //  getnerate the next set of keys
    	 
    	 end 

           6:		// figure out which unit found the key 
             begin 
    	    if(match[unit]==1'b0) 
    	      begin 
    		 unit = unit + 8'd1; 
    	      end 
    	    else 
    	      begin 
    		 //strip parity bits to obtain ascii values 
    		 plain_txt = {ascii[l_index][r_index][63:57], 
    			      ascii[l_index][r_index][55:49], 
    			      ascii[l_index][r_index][47:41], 
    			      ascii[l_index][r_index][39:33], 
    			      ascii[l_index][r_index][31:25], 
    			      ascii[l_index][r_index][23:17], 
    			      ascii[l_index][r_index][15:9], 
    			      ascii[l_index][r_index][7:1]}; //  store the password that generated the correct hash
    		 state = 8'd7; 
    	      end 
    	 end 
           7:		// trap state; 
    	 begin 
    	 
    	 end 
         endcase //  case (state)

      end 
     end 
endmodule //  key_gen