dakies/OSS_Verilog huggingface dataset:
module encryption_TB;


/*INPUTS*/

reg [7:0] key_byte, state_byte;
reg clk,rst,enable;

/* OUTPUTS */
wire [7:0] state_out_byte;
wire load,ready;

/* instance */
AES_encryption AES_TB(key_byte, state_byte,clk,rst,enable,state_out_byte,load,ready);

/*Initializing inputs*/
initial 
begin 
 //initialize here 
	clk = 0;
	rst = 0;
  key_byte = 0;
  state_byte =0;
	enable = 0;
end 


/*Monitor values*/
initial 
begin 
  $display ("\t\ttime,\tkey_Byte,\tdata_Byte,\tload,\tready,\tdata_out_byte");
  $monitor ("%d,\t%b,\t%b,\t%b,\t%b,\t%b",$time,key_byte,state_byte,load,ready,state_out_byte);
end

//Generate clock 
always 
#1 clk = ~clk;

event reset_done;
/*Generating input values */
task reset();
  begin
  @(negedge clk);
    rst = 1;
	#5
  @(negedge clk);
		begin 
		rst = 0;
		->reset_done;
		end
	
	

end 
endtask


reg [127:0] full_key,full_state;
integer i;

always @(negedge clk)
begin 
	if ( enable && (i > 0) )
	begin 
		key_byte <= full_key[i-:8];
		state_byte <= full_state[i-:8];
		i = i-8;
	end 
end 


initial 
begin 
/*
		 // 16 cycle  key = 54 68 61 74 73 20 6D 79 20 4B 75 6E 67 20 46 75 
				// ;data = 54 77 6F 20 4F 6E 65 20 4E 69 6E 65 20 54 77 6F 
				
									 54 77 6F 20
									 4F 6E 65 20
									 4E 69 6E 65
									 20 54 77 6F 
*/
	full_key <= 128'h5468617473206D79204B756E67204675;
	full_state <= 128'h54776F204F6E65204E696E652054776F;

  i <= 127;
	#1 reset();
end

initial
begin 
  @(reset_done)
  begin
	#2;
		enable = 1;
		@(ready) 
			begin 
				#35;
				$stop;
			end 
  end
end 
endmodule
module subByte_inv
	(
	input wire [31:0] state,
	output wire  [31:0]state_out
	);



////////////////////////////////////////////////


/* cannot instantiate instances inisde initial block. */

genvar itr;
genvar jtr;
generate
		for (itr = 0 ; itr <= 31; itr = itr+8)
					s_box_inv sboxInv (state[itr +:8] , state_out[itr +:8]);
endgenerate


////////////////////////////////////////////////



endmodule
module InverseMixColumns
	#(parameter word_size =8 ,array_size =16)
	(
	input wire [word_size*array_size-1:0] state,
	input  clk,enable, rst,
	output reg  [word_size*array_size-1:0]state_out);

	integer i,j,ij,k;

  reg [word_size-1:0] state_2D [0:3] [0:3];
  reg [word_size-1:0] state_out_2D[0:3] [0:3];	
  reg [word_size-1:0] inv_trans_matrix[0:3] [0:3];	
  reg [14:0] temp_mul,temp_mod;
  
`include "FiniteMultiplication.v"
`include "mod.v"

		always@(posedge clk) 
begin
for ( i=0; i<=3; i=i+1)
	for ( j=0; j<=3; j=j+1)
		begin
		ij=15-(i*4+j);
		state_2D[j][i]=state[ij*word_size  +:  word_size];
		$display("state_2D[%d][%d]=%h,  state[%d]=%h",j,i, state_2D[j][i],ij, state[ij*word_size  +:  word_size]);
		end	





inv_trans_matrix[0][0]=8'd14;
inv_trans_matrix[0][1]=8'd11;
inv_trans_matrix[0][2]=8'd13;
inv_trans_matrix[0][3]=8'd09;
inv_trans_matrix[1][0]=8'd09;
inv_trans_matrix[1][1]=8'd14;
inv_trans_matrix[1][2]=8'd11;
inv_trans_matrix[1][3]=8'd13;
inv_trans_matrix[2][0]=8'd13;
inv_trans_matrix[2][1]=8'd09;
inv_trans_matrix[2][2]=8'd14;
inv_trans_matrix[2][3]=8'd11;
inv_trans_matrix[3][0]=8'd11;
inv_trans_matrix[3][1]=8'd13;
inv_trans_matrix[3][2]=8'd09;
inv_trans_matrix[3][3]=8'd14;
/////////////////////////////
if (rst)
begin
state_out<=128'd0;
temp_mul<=14'd0;
temp_mod<=14'd0;
end 
/////////////////////////////
else if (enable)

 begin 

 for(i=0;i <=3;i=i+1)
	for(j=0;j <=3;j=j+1)
	begin
		temp_mod=14'd0;
		for(k=0;k <=3;k=k+1)
		begin
			finite_multiplication( state_2D[k][j], inv_trans_matrix[i][k], temp_mul);
			temp_mod = temp_mod ^ temp_mul;
			Mod(temp_mod,state_out_2D[i][j]);
			end
			$display ("state_out_2D[%d][%d] = %h",i,j,state_out_2D[i][j]);
			end
			end 


//2D to 1D

for ( i=0; i<=3; i=i+1) 
	for ( j=0; j<=3; j=j+1)
		begin
		ij=15-(i*4+j);
		state_out[ij*word_size  +:  word_size]=state_out_2D[j][i];
		end	
				$display ("state_out = %h",state_out);

end 
endmodule
module rcon(
input [3:0] r,
output reg [31:0] rcon // output reg [3:0]  rcon [7:0] // can't do that ._. 
);

always @(r)
 case(r)
    4'h1: rcon=32'h01000000;
    4'h2: rcon=32'h02000000;
    4'h3: rcon=32'h04000000;
    4'h4: rcon=32'h08000000;
    4'h5: rcon=32'h10000000;
    4'h6: rcon=32'h20000000;
    4'h7: rcon=32'h40000000;
    4'h8: rcon=32'h80000000;
    4'h9: rcon=32'h1b000000;
    4'ha: rcon=32'h36000000;
    default: rcon=32'h00000000;
  endcase
endmodule
module Shift_Rows 
 #(parameter word_size =8 ,array_size =16)(
  input en,clk,rst,
  input  wire  [0:word_size*array_size-1] Data,
	output reg  [0:word_size*array_size-1] Shifted_Data,
	output reg done );
  
  reg [word_size-1:0] data [0:3] [0:3];
  reg [word_size-1:0] shifted_data[0:3] [0:3];
 
 integer i,j,ij;	 
  
always @(posedge clk)
  begin
    if (rst)
		begin
      //for ( i=0; i<=word_size*array_size-1; i=i+1)
	       Shifted_Data = 128'b0;
				 done = 0;
		end
  else if (en) begin
    for ( i=0; i<=3; i=i+1)
	   for ( j=0; j<=3; j=j+1)
	      begin 
	        ij =((4*i)+j);
		      data[j][i]=Data[ij*word_size  +:  word_size];
		    end	
		    
		 for ( i=0; i<=3; i=i+1)
	    for ( j=0; j<=3; j=j+1)
	     begin
	      if (i ==0)
	         shifted_data[i][j] = data[i][j];
	      else if (i ==1)
	        begin
	         shifted_data[1][0] = data[1][1];
           shifted_data[1][1] = data[1][2];
           shifted_data[1][2] = data[1][3];
           shifted_data[1][3] = data[1][0];
          end
         else if (i ==2)
           begin
	          shifted_data[2][0] = data[2][2];
	          shifted_data[2][1] = data[2][3];
            shifted_data[2][2] = data[2][0];
            shifted_data[2][3] = data[2][1];
           end
          else if (i ==3) 
           begin
		        shifted_data[3][0] = data[3][3];
            shifted_data[3][1] = data[3][0];
            shifted_data[3][2] = data[3][1];
            shifted_data[3][3] = data[3][2];
           end
        end 
 
						for ( i=0; i<=3; i=i+1)
							for ( j=0; j<=3; j=j+1)
								begin 
									ij =((4*i)+j);
									Shifted_Data[ij*word_size  +:  word_size]=shifted_data[j][i];
								end
					done = 1;
		    end	
	 			else done <= 0;
end
		   
  
endmodule
module key_expansion( 
  input  [127:0] key_0 ,
	input clk,
	input reset,
  output  reg [127:0] key_Out);
  
	reg [31:0] stp1 ;
  wire [31:0] stp2 ;
  wire [31:0]Rcon ;
	reg [3:0] m; 
	reg [127:0] k [10:0];

 	 rcon uut1 (.r(m),.rcon(Rcon));
   subByte uut2 (.state(stp1) , .state_out(stp2));
	 
	 always @(negedge clk)
	 begin 
		if( reset == 1 )
		begin 
			m <= 0;
		end
		else 
		begin 		
	 $display("key %d : %h, %h",m,k[m],{ k[m][25:0] , k[m][31:24] });
 	  stp1 	<= { k[m][25:0] , k[m][31:24] }; 
		 key_Out <=	k[m];
	   m <= m + 1;        // m= 0 1 2 3 4 5 6 7 8 9
	   end 
		 end 

always @(posedge clk) 
 begin
	if ( reset == 1 )
	begin 
		k[0] <= key_0;
		k[1] <= 128'b0;
		k[2] <= 128'b0;
		k[3] <= 128'b0;
		k[4] <= 128'b0;
		k[5] <= 128'b0;
		k[6] <= 128'b0;
		k[7] <= 128'b0;
		k[8] <= 128'b0;
		k[9] <= 128'b0;
		k[10] <= 128'b0;
	end 
	else 
	begin 
		k[m][127:96] = k[m-1][127:96] ^ stp2 ^ Rcon; 	
		k[m][95:64] = k[m-1][95:64] ^ k[m][127:96];
		k[m] [63:32] = k[m-1][63:32] ^ k[m][95:64];
		k[m][31:0] = k[m-1][31:0] ^ k[m][63:32];
		
	end 
end
 endmodule
module encryption_TB;


/*INPUTS*/

reg [7:0] key_byte, state_byte;
reg clk,rst,enable;

/* OUTPUTS */
wire [7:0] state_out_byte;
wire load,ready;

/* instance */
AES_encryption AES_TB(key_byte, state_byte,clk,rst,enable,state_out_byte,load,ready);

reg startSend;

/*Initializing inputs*/
initial 
begin 
 //initialize here 
	clk = 0;
	rst = 0;
  key_byte = 0;
  state_byte =0;
	enable = 0;
	startSend=0;
end 


/*Monitor values*/
initial 
begin 
  $display ("\t\ttime,\tkey_Byte,\tdata_Byte,\tload,\tready,\tdata_out_byte");
  $monitor ("%d,\t%b,\t%b,\t%b,\t%b,\t%b",$time,key_byte,state_byte,load,ready,state_out_byte);
end

//Generate clock 
always 
#1 clk = ~clk;

event reset_done;
/*Generating input values */
task reset();
  begin
  @(negedge clk);
    rst = 1;
	#5
  @(negedge clk);
		begin 
		rst = 0;
		->reset_done;
		end
	
	

end 
endtask


reg [127:0] full_key,full_state;
integer i;

always @(negedge clk)
begin 
	if ( startSend && (i > 0) )
	begin 
		key_byte <= full_key[i-:8];
		state_byte <= full_state[i-:8];
		i = i-8;
	end 
end 


initial 
begin 
/*
		 // 16 cycle  key = 54 68 61 74 73 20 6D 79 20 4B 75 6E 67 20 46 75 
				// ;data = 54 77 6F 20 4F 6E 65 20 4E 69 6E 65 20 54 77 6F 
				
									 54 77 6F 20
									 4F 6E 65 20
									 4E 69 6E 65
									 20 54 77 6F 
*/
	full_key <= 128'h5468617473206D79204B756E67204675;
	full_state <= 128'h54776F204F6E65204E696E652054776F;

  i <= 127;
	#1 reset();
end

initial
begin 
  @(reset_done)
  begin
	#2;
		enable = 1;
	#2; /*wait one cycle because datsa is recieved in the design after one cycle of the enable signal is set*/
		startSend = 1;
		@(ready) 
			begin 
				#35;
				$stop;
			end 
  end
end 
endmodule
module Shift_Rows (
  input en,clk,rst,
  input  wire  [0:127] Data,
	output reg  [0:127] Shifted_Data,
	output reg done );
	

always @(posedge clk)
  begin
    if (rst)
		begin
	       Shifted_Data = 128'b0;
				 done = 0;
		end
  else if (en) begin
				/*      
				1010100011101110110111100100000010011110110111001100101001000000100111001101001011011100110010100100000010101000111011101101111

							 0    8    16     24 
							 32		40   48     56
							 64   72   80     88
							 96   104  112    120

							 0    40    80     120
							 32		72    112    24 
							 64   104   16     56
							 96   8    48    88
*/

		/* in the DATA .. the arranging is columns filled 1st  ._. */
		/* column 0 no change */
		Shifted_Data[0+:8] <= Data[0+:8];
		Shifted_Data[32+:8] <= Data[32+:8];
		Shifted_Data[64+:8] <= Data[64+:8];
		Shifted_Data[96+:8] <= Data[96+:8];

		/*2nd column , column 1 , 1 shift down */
		Shifted_Data [8+:8] <= Data[40+:8];
		Shifted_Data [40+:8] <= Data[72+:8];
		Shifted_Data [72+:8] <= Data[104+:8];
		Shifted_Data [104+:8] <= Data[8+:8];
		
		/*3rd column , column 2 , 2 shifts down */
		Shifted_Data [16+:8] <= Data[80+:8];
		Shifted_Data [48+:8] <= Data[112+:8];
		Shifted_Data [80+:8] <= Data[16+:8];
		Shifted_Data [112+:8] <= Data[48+:8];


		/*4th column , column 3 , 3 shifts down */
		Shifted_Data [24+:8] <= Data[120+:8];
		Shifted_Data [56+:8] <= Data[24+:8];
		Shifted_Data [88+:8] <= Data[56+:8];
		Shifted_Data [120+:8] <= Data[88+:8];

		/*
		//	row 0 no change 
		Shifted_Data[0+:32] <= Data[0+:32];
		//	2nd row , row 1 , 1 shift left 
		Shifted_Data [32+:24] <= Data[40+:24];
		Shifted_Data [56+:8] <= Data[32+:8];
		//3rd row , row 2 , 2 shifts left 
		Shifted_Data [64+:16] <= Data[80+:16];
		Shifted_Data [80+:16] <= Data[64+:16];
		//*4th row , row 3 , 3 shifts left 
		Shifted_Data [96+:8] <= Data[120+:8];
		Shifted_Data [104+:24] <= Data[96+:24];
	*/
		done = 1;
	end		
	else done <= 0;
end
endmodule
module MixColumns(
	input wire [127:0] state,
	input  clk,enable, rst,
	output reg  [127:0]state_out,
	output reg done);

function reg [7:0] MultiplyByTwo;
	input [7:0] x;
	begin 
			/* multiplication by 2 is shifting on bit to the left, and if the original 8 bits had a 1 @ MSB, xor the result with 0001 1011*/
			if(x[7] == 1) MultiplyByTwo = ((x << 1) ^ 8'h1b);
			else MultiplyByTwo = x << 1; 
	end 	
endfunction

function reg [7:0] MultiplyByThree;
	input [7:0] x;
	begin 
			/* multiplication by 3 ,= 01 ^ 10 = (NUM * 01) XOR (NUM * 10) = (NUM) XOR (NUM Muliplication by 2) */
			MultiplyByThree = MultiplyByTwo(x) ^ x;
	end 
endfunction
 
integer i; 
	always@(posedge clk) 
begin
	if (rst)
	begin
		state_out<=128'd0;
		i<= 0;
		done <= 0;
	end 
	else if (enable)
	begin 
			for(i=0;i<=3;i=i+1)
			begin 
			 /* 
			 * Mix columns is a matrices muliplication: polynomial matrix state matrix .
			 * for example 
			 *	2	3	1 1     63 09 cd ba
			 *	1	2	3 1     53 60 70 ca
			 *	1	1	2 3     e0 e1 b7 d0
			 * 	3	1	1 2     8c 04 51 e7
			 * But the state bits as input comes serially in a reg [127:0] : 63 53 e0 8c 09 60 e1 04 cd 70 b7 51 ba ca d0 e7  
			 * so instead of multiplying row * column we multiply row * row  and putting the bits in the output state in a column per iteration
			 * 
			 */
			 
				state_out[i*32+:8]  <= MultiplyByTwo(state[(i*32)+:8])^(state[(i*32 + 8)+:8])^(state[(i*32 + 16)+:8])^MultiplyByThree(state[(i*32 + 24)+:8]);
				state_out[(i*32 + 8)+:8] <= MultiplyByThree(state[(i*32)+:8])^MultiplyByTwo(state[(i*32 + 8)+:8])^(state[(i*32 + 16)+:8])^(state[(i*32 + 24)+:8]);
				state_out[(i*32 + 16)+:8] <= (state[(i*32)+:8])^MultiplyByThree(state[(i*32 + 8)+:8])^MultiplyByTwo(state[(i*32 + 16)+:8])^(state[(i*32 + 24)+:8]);
				state_out[(i*32 + 24)+:8]  <= (state[(i*32)+:8])^(state[(i*32 + 8)+:8])^MultiplyByThree(state[(i*32 + 16)+:8])^MultiplyByTwo(state[(i*32 + 24)+:8]);
			end 
			
			done <= 1;
			end else done <= 0;
end
endmodule
module AddRoundKey(
	input wire [127:0] key ,
	input wire [127:0] state,
	input  clk,enable, rst,
	output reg  [127:0]state_out,
	output reg done);

	integer i;

always@(posedge clk)
 begin
 if (rst) begin
 state_out=128'd0;
 done <= 0;
 i <= 0;
 end 
 else if (enable) begin 
	for ( i=0; i<=15; i=i+1)
		state_out[i*8  +:  8] <= key[i*8  +:  8] ^ state[i*8  +:  8];

	done = 1;
	end 
	else done <= 0;

end
endmodule
module switch_led  // sources/rtl/switch_led.v(15)
  (
  switch,
  led
  );

  input [15:0] switch;  // sources/rtl/switch_led.v(17)
  output [15:0] led;  // sources/rtl/switch_led.v(18)


  buf u0 (led[3], switch[3]);  // sources/rtl/switch_led.v(21)
  buf u1 (led[2], switch[2]);  // sources/rtl/switch_led.v(21)
  buf u10 (led[10], switch[10]);  // sources/rtl/switch_led.v(21)
  buf u11 (led[11], switch[11]);  // sources/rtl/switch_led.v(21)
  buf u12 (led[12], switch[12]);  // sources/rtl/switch_led.v(21)
  buf u13 (led[13], switch[13]);  // sources/rtl/switch_led.v(21)
  buf u14 (led[14], switch[14]);  // sources/rtl/switch_led.v(21)
  buf u15 (led[15], switch[15]);  // sources/rtl/switch_led.v(21)
  buf u2 (led[1], switch[1]);  // sources/rtl/switch_led.v(21)
  buf u3 (led[0], switch[0]);  // sources/rtl/switch_led.v(21)
  buf u4 (led[4], switch[4]);  // sources/rtl/switch_led.v(21)
  buf u5 (led[5], switch[5]);  // sources/rtl/switch_led.v(21)
  buf u6 (led[6], switch[6]);  // sources/rtl/switch_led.v(21)
  buf u7 (led[7], switch[7]);  // sources/rtl/switch_led.v(21)
  buf u8 (led[8], switch[8]);  // sources/rtl/switch_led.v(21)
  buf u9 (led[9], switch[9]);  // sources/rtl/switch_led.v(21)

endmodule
module switch_led  // sources/rtl/switch_led.v(15)
  (
  switch,
  led
  );

  input [15:0] switch;  // sources/rtl/switch_led.v(17)
  output [15:0] led;  // sources/rtl/switch_led.v(18)


  assign led[15] = switch[15];
  assign led[14] = switch[14];
  assign led[13] = switch[13];
  assign led[12] = switch[12];
  assign led[11] = switch[11];
  assign led[10] = switch[10];
  assign led[9] = switch[9];
  assign led[8] = switch[8];
  assign led[7] = switch[7];
  assign led[6] = switch[6];
  assign led[5] = switch[5];
  assign led[4] = switch[4];
  assign led[3] = switch[3];
  assign led[2] = switch[2];
  assign led[1] = switch[1];
  assign led[0] = switch[0];

endmodule
module Double_RAM_uut  // al_ip/Double_RAM_uut.v(14)
  (
  addra,
  addrb,
  ceb,
  clka,
  clkb,
  dia,
  dob
  );

  input [7:0] addra;  // al_ip/Double_RAM_uut.v(23)
  input [7:0] addrb;  // al_ip/Double_RAM_uut.v(24)
  input ceb;  // al_ip/Double_RAM_uut.v(25)
  input clka;  // al_ip/Double_RAM_uut.v(26)
  input clkb;  // al_ip/Double_RAM_uut.v(27)
  input [7:0] dia;  // al_ip/Double_RAM_uut.v(22)
  output [7:0] dob;  // al_ip/Double_RAM_uut.v(19)


  EG_PHY_CONFIG #(
    .DONE_PERSISTN("ENABLE"),
    .INIT_PERSISTN("ENABLE"),
    .JTAG_PERSISTN("DISABLE"),
    .PROGRAMN_PERSISTN("DISABLE"))
    config_inst ();
  // address_offset=0;data_offset=0;depth=256;width=8;num_section=1;width_per_section=8;section_size=8;working_depth=1024;working_width=9;address_step=1;bytes_in_per_section=1;
  EG_PHY_BRAM #(
    .CEAMUX("1"),
    .CSA0("1"),
    .CSA1("1"),
    .CSA2("1"),
    .CSB0("1"),
    .CSB1("1"),
    .CSB2("1"),
    .DATA_WIDTH_A("9"),
    .DATA_WIDTH_B("9"),
    .MODE("DP8K"),
    .OCEAMUX("0"),
    .OCEBMUX("0"),
    .REGMODE_A("NOREG"),
    .REGMODE_B("NOREG"),
    .RESETMODE("SYNC"),
    .RSTAMUX("0"),
    .RSTBMUX("0"),
    .WEAMUX("1"),
    .WEBMUX("0"),
    .WRITEMODE_A("NORMAL"),
    .WRITEMODE_B("NORMAL"))
    inst_256x8_sub_000000_000 (
    .addra({2'b00,addra,3'b111}),
    .addrb({2'b00,addrb,3'b111}),
    .ceb(ceb),
    .clka(clka),
    .clkb(clkb),
    .dia({open_n54,dia}),
    .dob({open_n79,dob}));

endmodule
module pll_test  // al_ip/pll_test.v(24)
  (
  refclk,
  reset,
  clk0_out,
  clk1_out,
  clk2_out,
  extlock
  );

  input refclk;  // al_ip/pll_test.v(31)
  input reset;  // al_ip/pll_test.v(32)
  output clk0_out;  // al_ip/pll_test.v(34)
  output clk1_out;  // al_ip/pll_test.v(35)
  output clk2_out;  // al_ip/pll_test.v(36)
  output extlock;  // al_ip/pll_test.v(33)

  wire clk0_buf;  // al_ip/pll_test.v(38)

  EG_PHY_GCLK bufg_feedback (
    .clki(clk0_buf),
    .clko(clk0_out));  // al_ip/pll_test.v(40)
  EG_PHY_CONFIG #(
    .DONE_PERSISTN("ENABLE"),
    .INIT_PERSISTN("ENABLE"),
    .JTAG_PERSISTN("DISABLE"),
    .PROGRAMN_PERSISTN("DISABLE"))
    config_inst ();
  EG_PHY_PLL #(
    .CLKC0_CPHASE(39),
    .CLKC0_DIV(40),
    .CLKC0_DIV2_ENABLE("DISABLE"),
    .CLKC0_ENABLE("ENABLE"),
    .CLKC0_FPHASE(0),
    .CLKC1_CPHASE(19),
    .CLKC1_DIV(20),
    .CLKC1_DIV2_ENABLE("DISABLE"),
    .CLKC1_ENABLE("ENABLE"),
    .CLKC1_FPHASE(0),
    .CLKC2_CPHASE(9),
    .CLKC2_DIV(10),
    .CLKC2_DIV2_ENABLE("DISABLE"),
    .CLKC2_ENABLE("ENABLE"),
    .CLKC2_FPHASE(0),
    .CLKC3_CPHASE(1),
    .CLKC3_DIV(1),
    .CLKC3_DIV2_ENABLE("DISABLE"),
    .CLKC3_ENABLE("DISABLE"),
    .CLKC3_FPHASE(0),
    .CLKC4_CPHASE(1),
    .CLKC4_DIV(1),
    .CLKC4_DIV2_ENABLE("DISABLE"),
    .CLKC4_ENABLE("DISABLE"),
    .CLKC4_FPHASE(0),
    .DERIVE_PLL_CLOCKS("DISABLE"),
    .DPHASE_SOURCE("DISABLE"),
    .DYNCFG("DISABLE"),
    .FBCLK_DIV(1),
    .FEEDBK_MODE("NORMAL"),
    .FEEDBK_PATH("CLKC0_EXT"),
    .FIN("25.000"),
    .FREQ_LOCK_ACCURACY(2),
    .GEN_BASIC_CLOCK("DISABLE"),
    .GMC_GAIN(6),
    .GMC_TEST(14),
    .ICP_CURRENT(3),
    .IF_ESCLKSTSW("DISABLE"),
    .INTFB_WAKE("DISABLE"),
    .KVCO(6),
    .LPF_CAPACITOR(3),
    .LPF_RESISTOR(2),
    .NORESET("DISABLE"),
    .ODIV_MUXC0("DIV"),
    .ODIV_MUXC1("DIV"),
    .ODIV_MUXC2("DIV"),
    .ODIV_MUXC3("DIV"),
    .ODIV_MUXC4("DIV"),
    .PLLC2RST_ENA("DISABLE"),
    .PLLC34RST_ENA("DISABLE"),
    .PLLMRST_ENA("DISABLE"),
    .PLLRST_ENA("ENABLE"),
    .PLL_LOCK_MODE(0),
    .PREDIV_MUXC0("VCO"),
    .PREDIV_MUXC1("VCO"),
    .PREDIV_MUXC2("VCO"),
    .PREDIV_MUXC3("VCO"),
    .PREDIV_MUXC4("VCO"),
    .REFCLK_DIV(1),
    .REFCLK_SEL("INTERNAL"),
    .STDBY_ENABLE("DISABLE"),
    .STDBY_VCO_ENA("DISABLE"),
    .SYNC_ENABLE("DISABLE"),
    .VCO_NORESET("DISABLE"))
    pll_inst (
    .daddr(6'b000000),
    .dclk(1'b0),
    .dcs(1'b0),
    .di(8'b00000000),
    .dwe(1'b0),
    .fbclk(clk0_out),
    .psclk(1'b0),
    .psclksel(3'b000),
    .psdown(1'b0),
    .psstep(1'b0),
    .refclk(refclk),
    .reset(reset),
    .stdby(1'b0),
    .clkc({open_n47,open_n48,clk2_out,clk1_out,clk0_buf}),
    .extlock(extlock));  // al_ip/pll_test.v(71)

endmodule
module uart_top_tb();

reg ext_clk_25m;
reg ext_rst_n;
reg uart_rx;
wire uart_tx;

//Clock process
parameter PERIOD = 10;

//glbl Instantiate
glbl glbl();

//Unit Instantiate
uart_top uut(
	.ext_clk_25m(ext_clk_25m),
	.ext_rst_n(ext_rst_n),
	.uart_rx(uart_rx),
	.uart_tx(uart_tx));

//Stimulus process
initial begin
//To be inserted
	ext_clk_25m = 0;
	ext_rst_n = 1;
	
	#500;
	uart_rx = 1;
	#104;
	
	uart_rx = 0;
	#104;
	uart_rx = 0;
	#104;
	uart_rx = 0;
	#104;
	uart_rx = 0;
	#104;
	uart_rx = 0;
	#104;
	uart_rx = 1;
	#104;
	uart_rx = 0;
	#104;
	uart_rx = 1;
	#104;
	
	uart_rx = 0;
	
		
		
	
end

always #20 ext_clk_25m <= ~ext_clk_25m;

endmodule
module uart_top
#(
    parameter BPS_SET      =   96,  //²¨ÌØÂÊ9600
    parameter CLK_PERIORD  =   40   //Ê±ÖÓÖÜÆÚ40ns(25MHz)
)
(
	input 	wire	ext_clk_25m,	//Íâ²¿ÊäÈë25MHzÊ±ÖÓÐÅºÅ
	input 	wire	ext_rst_n,		//Íâ²¿ÊäÈë¸´Î»ÐÅºÅ£¬µÍµçÆ½ÓÐÐ§
	input 	wire	uart_rx,		//UART½ÓÊÕÊý¾ÝÐÅºÅ
	output 	wire	uart_tx,		//UART·¢ËÍÊý¾ÝÐÅºÅ
	output 	wire	led
);													

//-------------------------------------
wire	clk_25m;	//PLLÊä³ö25MHzÊ±ÖÓ
wire	clk_50m;	//PLLÊä³ö50MHzÊ±ÖÓ
wire	clk_100m;	//PLLÊä³ö100MHzÊ±ÖÓ
wire	sys_rst_n;	//PLLÊä³öµÄlockedÐÅºÅ£¬×÷ÎªFPGAÄÚ²¿µÄ¸´Î»ÐÅºÅ£¬µÍµçÆ½¸´Î»£¬¸ßµçÆ½Õý³£¹¤×÷

//-------------------------------------
wire bps_start1,bps_start2;	//½ÓÊÕµ½Êý¾Ýºó£¬²¨ÌØÂÊÊ±ÖÓÆô¶¯ÐÅºÅÖÃÎ»
wire clk_bps1,clk_bps2;     //clk_bps_r¸ßµçÆ½Îª½ÓÊÕÊý¾ÝÎ»µÄÖÐ¼ä²ÉÑùµã,Í¬Ê±Ò²×÷Îª·¢ËÍÊý¾ÝµÄÊý¾Ý¸Ä±äµã 
wire [7:0] rx_data;         //½ÓÊÕÊý¾Ý¼Ä´æÆ÷£¬±£´æÖ±ÖÁÏÂÒ»¸öÊý¾ÝÀ´µ½
wire rx_int;                //½ÓÊÕÊý¾ÝÖÐ¶ÏÐÅºÅ,½ÓÊÕµ½Êý¾ÝÆÚ¼äÊ¼ÖÕÎª¸ßµçÆ½
//-------------------------------------
//Double RAM 
wire 			ram_rw_ce;  //RAM¶ÁÐ´Ê¹ÄÜ£¬0-->Ð´£¬1--¶Á
wire	[7:0]	ram_output;

//-------------------------------------
//PLLÀý»¯	
pll_test u_pll_test
(
	.refclk		    (ext_clk_25m	),
	.reset		    (~ext_rst_n		),
	.extlock	    (sys_rst_n		),
	.clk0_out	    (clk_25m		),
	.clk1_out	    (clk_50m		),
	.clk2_out	    (clk_100m		)
);
		
//-------------------------------------
//UART½ÓÊÕ
//-------------------------------------
	//UART½ÓÊÕÐÅºÅ²¨ÌØÂÊÉèÖÃ
speed_setting
#(
	.BPS_SET	    (BPS_SET	    ),
	.CLK_PERIORD	(CLK_PERIORD    )
)
speed_rx

(	
    .clk            (clk_25m        ),	//²¨ÌØÂÊÑ¡ÔñÄ£¿é
    .rst_n          (sys_rst_n      ),
    .bps_start      (bps_start1     ),
    .clk_bps        (clk_bps1       )
);

	//UART½ÓÊÕÊý¾Ý´¦Àí
my_uart_rx	my_uart_rx
(		
	.clk            (clk_25m        ),	//½ÓÊÕÊý¾ÝÄ£¿é
	.rst_n          (sys_rst_n      ),
	.uart_rx        (uart_rx        ),
	.rx_data        (rx_data        ),
	.rx_int         (rx_int         ),
	.clk_bps        (clk_bps1       ),
	.bps_start      (bps_start1     )
);
		
//-------------------------------------
//RAM¶ÁÐ´Ê±Ðò¿ØÖÆÄ£¿é
//-------------------------------------
ram_rw_control u_ram_rw_control
(
	.clk_25m        (clk_25m        ),		
	.sys_rst_n   	(sys_rst_n      ),
	.rx_int			(rx_int         ),
	.rx_data       	(rx_data        ),
	.ram_rw_ce     	(ram_rw_ce      ),
	.ram_output    	(ram_output     ),
	.led		    (led            )	
);
//-------------------------------------
//UART·¢ËÍ
//-------------------------------------
	//UART·¢ËÍÐÅºÅ²¨ÌØÂÊÉèÖÃ													
speed_setting
#(
	.BPS_SET	    (BPS_SET	    ),
	.CLK_PERIORD	(CLK_PERIORD	)
)
speed_tx
(	
	.clk            (clk_25m        ),	//²¨ÌØÂÊÑ¡ÔñÄ£¿é
	.rst_n          (sys_rst_n      ),
	.bps_start      (bps_start2     ),
	.clk_bps        (clk_bps2       )
);
						
	//UART·¢ËÍÊý¾Ý´¦Àí
my_uart_tx	my_uart_tx
(		
	.clk            (clk_25m        ),	//·¢ËÍÊý¾ÝÄ£¿é
	.rst_n          (sys_rst_n      ),
	.rx_data        (ram_output     ),
	.rx_int         (ram_rw_ce      ),
	.uart_tx        (uart_tx        ),
	.clk_bps        (clk_bps2       ),
	.bps_start      (bps_start2     )
);


endmodule
module speed_setting
#(
    parameter BPS_SET      =   96,  //²¨ÌØÂÊ
    parameter CLK_PERIORD  =   40   //Ê±ÖÓÖÜÆÚ40ns(25MHz)
)
(
	input	clk,		//25MHzÖ÷Ê±ÖÓ
	input	rst_n,		//µÍµçÆ½¸´Î»ÐÅºÅ
	input	bps_start,	//½ÓÊÕµ½Êý¾Ýºó£¬²¨ÌØÂÊÊ±ÖÓÆô¶¯ÐÅºÅÖÃÎ»
	output	clk_bps		//clk_bpsµÄ¸ßµçÆ½Îª½ÓÊÕ»òÕß·¢ËÍÊý¾ÝÎ»µÄÖÐ¼ä²ÉÑùµã
);

`define BPS_PARA	(10_000_000/CLK_PERIORD/BPS_SET)	//10_000_000/`CLK_PERIORD/96;
`define BPS_PARA_2	(`BPS_PARA/2)						//BPS_PARA/2;	

reg	[12:0] cnt;		    //·ÖÆµ¼ÆÊý
reg clk_bps_r;	        //²¨ÌØÂÊÊ±ÖÓ¼Ä´æÆ÷
reg	[2:0] uart_ctrl;	//uart²¨ÌØÂÊÑ¡Ôñ¼Ä´æÆ÷

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        cnt <= 13'd0;
	else if((cnt == `BPS_PARA) || !bps_start)
        cnt <= 13'd0;	    //²¨ÌØÂÊ¼ÆÊýÇåÁã
	else
        cnt <= cnt + 1'b1;  //²¨ÌØÂÊÊ±ÖÓ¼ÆÊýÆô¶¯
end

always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
        clk_bps_r <= 1'b0;
	else if(cnt == `BPS_PARA_2)
        clk_bps_r <= 1'b1;			//clk_bps_r¸ßµçÆ½Îª½ÓÊÕÊý¾ÝÎ»µÄÖÐ¼ä²ÉÑùµã,Í¬Ê±Ò²×÷Îª·¢ËÍÊý¾ÝµÄÊý¾Ý¸Ä±äµã
	else
        clk_bps_r <= 1'b0;
end

assign clk_bps = clk_bps_r;

endmodule
module ram_rw_control
(
	input 	wire			clk_25m,		//Íâ²¿ÊäÈë25MHzÊ±ÖÓÐÅºÅ
	input 	wire			sys_rst_n,		//Íâ²¿ÊäÈë¸´Î»ÐÅºÅ£¬µÍµçÆ½ÓÐÐ§
	input 	wire			rx_int,		
	input	wire	[7:0]	rx_data,
	output	wire			ram_rw_ce,
	output 	wire	[7:0]	ram_output,
	output	wire			led			
);

//-------------------------------------
//½ÓÊÕÊý¾ÝÍê±Ï±êÖ¾Î»
reg		rx_int0,rx_int1,rx_int2;			//rx_intÐÅºÅ¼Ä´æÆ÷£¬²¶×½ÑØÂË²¨ÓÃ
wire	neg_rx_int;							//rx_intÏÂ½µÑØ±êÖ¾Î»
//-------------------------------------
//Double RAM 
reg 	[7:0]	ram_input;
reg 	[7:0]	ram_wr_addr, ram_re_addr;
reg 			ram_rw_ce_r;  				//RAM¶ÁÐ´Ê¹ÄÜ£¬0-->Ð´£¬1--¶Á
reg 			LED_FLAG;

//-------------------------------------
//½ÓÊÕÊý¾ÝÍê±Ï±êÖ¾Î»
//-------------------------------------
always @ (posedge clk_25m or negedge sys_rst_n)
begin 
	if(!sys_rst_n) 
	begin
		rx_int0 <= 1'b0;
		rx_int1 <= 1'b0;
		rx_int2 <= 1'b0;
	end
	else 
	begin
		rx_int0 <= rx_int;
		rx_int1 <= rx_int0;
		rx_int2 <= rx_int1;
	end
end

assign neg_rx_int =  ~rx_int1 & rx_int2;    //½ÓÊÕµ½Êý¾ÝÆÚ¼ärx_intÊ¼ÖÕÎª¸ßµçÆ½,ËüµÄÏÂ½µÑØ±íÊ¾Êý¾Ý½ÓÊÕÍê±Ï¡£ÕâÀï²¶×½µ½ÏÂÉýÑØºó£¬neg_rx_intÀ­¸ß±£³ÖÒ»¸öÖ÷Ê±ÖÓÖÜÆÚ

//-------------------------------------
//RAM¶ÁÐ´Ê±Ðò¿ØÖÆ
//-------------------------------------
// Port a
always @(posedge clk_25m or negedge sys_rst_n)
begin
	if(!sys_rst_n)
	begin
		ram_wr_addr <= 0;
		ram_input   <= 0;
		LED_FLAG    <= 1;
	end
	else if(ram_wr_addr<255) 
	begin  									//ÔÚRAMÖÐÐ´ÈëÓëÆäµØÖ·¶ÔÓ¦µÄ256¸ö8bitµÝÔöÊý¾Ý
		ram_wr_addr <= ram_wr_addr + 1'b1;
		ram_input   <= ram_input + 1;
	end
	else 
	begin
		ram_wr_addr <= ram_wr_addr;
		ram_input   <= ram_input;
		LED_FLAG    <= 0;
	end
end

// Port b
always @(posedge clk_25m or negedge sys_rst_n)
begin
	if(!sys_rst_n)
	begin
		ram_re_addr <= 0;
		ram_rw_ce_r <= 1'b0;
	end
	else if(neg_rx_int) 
	begin 
	    ram_re_addr <= rx_data;  
		ram_rw_ce_r <= 1'b1;
	end
	else 
	begin
	    ram_re_addr <= 0;
		ram_rw_ce_r <= 1'b0;
	end
end

//-------------------------------------
//Àý»¯Ë«¿ÚRAMºË
//-------------------------------------
 Double_RAM_uut uut_Double_RAM
 ( 

	.dob    (ram_output ),
	.dia    (ram_input  ),
	.addra  (ram_wr_addr),
	.addrb  (ram_re_addr),
	.ceb    (ram_rw_ce  ),
	.clka   (clk_25m    ),
	.clkb   (clk_25m    )
);
	
assign led 		 = LED_FLAG; 
assign ram_rw_ce = ram_rw_ce_r; 
	
endmodule
module my_uart_tx
(
	input			clk,
	input			rst_n,
	input	[7:0]	rx_data,
	input			rx_int,
	output			uart_tx,
	input			clk_bps,
	output			bps_start
);

//---------------------------------------------------------
reg 	rx_int0,rx_int1,rx_int2;	//rx_intÐÅºÅ¼Ä´æÆ÷£¬²¶×½ÏÂ½µÑØÂË²¨ÓÃ
wire 	neg_rx_int;					//rx_intÏÂ½µÑØ±êÖ¾Î»

always @ (posedge clk or negedge rst_n) 
	if(!rst_n) 
    begin
		rx_int0 <= 1'b0;
		rx_int1 <= 1'b0;
		rx_int2 <= 1'b0;
	end
	else 
    begin
		rx_int0 <= rx_int;
		rx_int1 <= rx_int0;
		rx_int2 <= rx_int1;
	end

assign neg_rx_int =  ~rx_int1 & rx_int2;	//²¶×½µ½ÏÂ½µÑØºó£¬neg_rx_intÀ­¸ß±£³ÖÒ»¸öÖ÷Ê±ÖÓÖÜÆÚ

//---------------------------------------------------------
reg	[7:0] 	tx_data;		//´ý·¢ËÍÊý¾ÝµÄ¼Ä´æÆ÷
reg 		bps_start_r;
reg 		tx_en;			//·¢ËÍÊý¾ÝÊ¹ÄÜÐÅºÅ£¬¸ßÓÐÐ§
reg	[3:0] 	num;

always @ (posedge clk or negedge rst_n) 
	if(!rst_n) 
    begin
		bps_start_r <= 1'bz;
		tx_en 		<= 1'b0;
		tx_data 	<= 8'd0;
	end
	else if(neg_rx_int) 
    begin		                    //½ÓÊÕÊý¾ÝÍê±Ï£¬×¼±¸°Ñ½ÓÊÕµ½µÄÊý¾Ý·¢»ØÈ¥
		bps_start_r <= 1'b1;
		tx_data 	<= rx_data;		//°Ñ½ÓÊÕµ½µÄÊý¾Ý´æÈë·¢ËÍÊý¾Ý¼Ä´æÆ÷
		tx_en 		<= 1'b1;		//½øÈë·¢ËÍÊý¾Ý×´Ì¬ÖÐ
	end
	else if(num == 4'd10) 
    begin		                    //Êý¾Ý·¢ËÍÍê³É£¬¸´Î»
		bps_start_r <= 1'b0;
		tx_en		<= 1'b0;
	end

assign bps_start = bps_start_r;

//---------------------------------------------------------
reg uart_tx_r;

always @ (posedge clk or negedge rst_n)
	if(!rst_n) 
    begin
		num 		<= 4'd0;
		uart_tx_r 	<= 1'b1;
	end
	else if(tx_en) 
    begin
		if(clk_bps)	
        begin
			num <= num+1'b1;
			case (num)
				4'd0: uart_tx_r <= 1'b0; 		//·¢ËÍÆðÊ¼Î»
				4'd1: uart_tx_r <= tx_data[0];	//·¢ËÍbit0
				4'd2: uart_tx_r <= tx_data[1];	//·¢ËÍbit1
				4'd3: uart_tx_r <= tx_data[2];	//·¢ËÍbit2
				4'd4: uart_tx_r <= tx_data[3];	//·¢ËÍbit3
				4'd5: uart_tx_r <= tx_data[4];	//·¢ËÍbit4
				4'd6: uart_tx_r <= tx_data[5];	//·¢ËÍbit5
				4'd7: uart_tx_r <= tx_data[6];	//·¢ËÍbit6
				4'd8: uart_tx_r <= tx_data[7];	//·¢ËÍbit7
				4'd9: uart_tx_r <= 1'b1;		//·¢ËÍ½áÊøÎ»
			 	default: uart_tx_r <= 1'b1;
			endcase
		end
		else if(num == 4'd10)
                num <= 4'd0;		//¸´Î»
	end

assign uart_tx = uart_tx_r;

endmodule
module my_uart_rx
(
	input			clk,		//25MHzÖ÷Ê±ÖÓ
	input			rst_n,		//µÍµçÆ½¸´Î»ÐÅºÅ
	input			uart_rx,	//½ÓÊÕÊý¾ÝÐÅºÅ
	output	[7:0]	rx_data,	//½ÓÊÕÊý¾Ý¼Ä´æÆ÷£¬±£´æÖ±ÖÁÏÂÒ»¸öÊý¾ÝÀ´µ½
	output			rx_int,		//½ÓÊÕÊý¾ÝÖÐ¶ÏÐÅºÅ,½ÓÊÕµ½Êý¾ÝÆÚ¼äÊ¼ÖÕÎª¸ßµçÆ½
	input			clk_bps,	//clk_bpsµÄ¸ßµçÆ½Îª½ÓÊÕ»òÕß·¢ËÍÊý¾ÝÎ»µÄÖÐ¼ä²ÉÑùµã
	output			bps_start	//½ÓÊÕµ½Êý¾Ýºó£¬²¨ÌØÂÊÊ±ÖÓÆô¶¯ÐÅºÅÖÃÎ»
);

//----------------------------------------------------------------
reg		uart_rx0,uart_rx1,uart_rx2,uart_rx3;	//½ÓÊÕÊý¾Ý¼Ä´æÆ÷£¬ÂË²¨ÓÃ
wire	neg_uart_rx;							

always @ (posedge clk or negedge rst_n)
begin 
	if(!rst_n) 
    begin
		uart_rx0 <= 1'b0;
		uart_rx1 <= 1'b0;
		uart_rx2 <= 1'b0;
		uart_rx3 <= 1'b0;
	end
	else 
    begin
		uart_rx0 <= uart_rx;
		uart_rx1 <= uart_rx0;
		uart_rx2 <= uart_rx1;
		uart_rx3 <= uart_rx2;
	end
end

assign neg_uart_rx = uart_rx3 & uart_rx2 & ~uart_rx1 & ~uart_rx0;	//½ÓÊÕµ½ÏÂ½µÑØºóneg_uart_rxÖÃ¸ßÒ»¸öÊ±ÖÓÖÜÆÚ

//----------------------------------------------------------------
reg 		bps_start_r;
reg	[3:0] 	num;	
reg 		rx_int;		//½ÓÊÕÊý¾ÝÖÐ¶ÏÐÅºÅ,½ÓÊÕµ½Êý¾ÝÆÚ¼äÊ¼ÖÕÎª¸ßµçÆ½

always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)  
    begin
		bps_start_r <= 1'bz;
		rx_int 		<= 1'b0;
	end
	else if(neg_uart_rx) 
    begin	                    //½ÓÊÕµ½´®¿Ú½ÓÊÕÏßuart_rxµÄÏÂ½µÑØ±êÖ¾ÐÅºÅ  
		bps_start_r <= 1'b1;	//Æô¶¯´®¿Ú×¼±¸Êý¾Ý½ÓÊÕ   
		rx_int 		<= 1'b1;	//½ÓÊÕÊý¾ÝÖÐ¶ÏÐÅºÅÊ¹ÄÜ
	end
	else if(num == 4'd9) 
    begin	                    //½ÓÊÕÍêÓÐÓÃÊý¾ÝÐÅÏ¢
		bps_start_r <= 1'b0;	//Êý¾Ý½ÓÊÕÍê±Ï£¬ÊÍ·Å²¨ÌØÂÊÆô¶¯ÐÅºÅ
		rx_int 		<= 1'b0;	//½ÓÊÕÊý¾ÝÖÐ¶ÏÐÅºÅ¹Ø±Õ
	end
end    

assign bps_start = bps_start_r;

//----------------------------------------------------------------
reg	[7:0]	rx_data_r;		//´®¿Ú½ÓÊÕÊý¾Ý¼Ä´æÆ÷
reg	[7:0]	rx_temp_data;	//µ±Ç°½ÓÊÕÊý¾Ý¼Ä´æÆ÷

always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n) 
    begin
		rx_temp_data 	<= 8'd0;
		num 			<= 4'd0;
		rx_data_r 		<= 8'd0;
	end
	else if(rx_int) 
    begin	                //½ÓÊÕÊý¾Ý´¦Àí
		if(clk_bps) 
        begin	            //¶ÁÈ¡²¢±£´æÊý¾Ý	
			num <= num+1'b1;
			case (num)
				4'd1: rx_temp_data[0] <= uart_rx;	//Ëø´æµÚ0bit
				4'd2: rx_temp_data[1] <= uart_rx;	//Ëø´æµÚ1bit
				4'd3: rx_temp_data[2] <= uart_rx;	//Ëø´æµÚ2bit
				4'd4: rx_temp_data[3] <= uart_rx;	//Ëø´æµÚ3bit
				4'd5: rx_temp_data[4] <= uart_rx;	//Ëø´æµÚ4bit
				4'd6: rx_temp_data[5] <= uart_rx;	//Ëø´æµÚ5bit
				4'd7: rx_temp_data[6] <= uart_rx;	//Ëø´æµÚ6bit
				4'd8: rx_temp_data[7] <= uart_rx;	//Ëø´æµÚ7bit
				default: ;
			endcase
		end
		else if(num == 4'd9) 
        begin		
			num			<= 4'd0;			//½ÓÊÕµ½STOPÎ»ºó½áÊø,numÇåÁã
			rx_data_r	<= rx_temp_data;	//°ÑÊý¾ÝËø´æµ½Êý¾Ý¼Ä´æÆ÷rx_dataÖÐ
		end
	end
end

assign rx_data = rx_data_r;	

endmodule
module pll  // al_ip/pll.v(22)
  (
  refclk,
  clk0_out
  );

  input refclk;  // al_ip/pll.v(25)
  output clk0_out;  // al_ip/pll.v(26)

  wire clk0_buf;  // al_ip/pll.v(28)

  EG_PHY_GCLK bufg_feedback (
    .clki(clk0_buf),
    .clko(clk0_out));  // al_ip/pll.v(30)
  EG_PHY_CONFIG #(
    .DONE_PERSISTN("ENABLE"),
    .INIT_PERSISTN("ENABLE"),
    .JTAG_PERSISTN("DISABLE"),
    .PROGRAMN_PERSISTN("DISABLE"))
    config_inst ();
  EG_PHY_PLL #(
    .CLKC0_CPHASE(39),
    .CLKC0_DIV(40),
    .CLKC0_DIV2_ENABLE("DISABLE"),
    .CLKC0_ENABLE("ENABLE"),
    .CLKC0_FPHASE(0),
    .CLKC1_CPHASE(1),
    .CLKC1_DIV(1),
    .CLKC1_DIV2_ENABLE("DISABLE"),
    .CLKC1_ENABLE("DISABLE"),
    .CLKC1_FPHASE(0),
    .CLKC2_CPHASE(1),
    .CLKC2_DIV(1),
    .CLKC2_DIV2_ENABLE("DISABLE"),
    .CLKC2_ENABLE("DISABLE"),
    .CLKC2_FPHASE(0),
    .CLKC3_CPHASE(1),
    .CLKC3_DIV(1),
    .CLKC3_DIV2_ENABLE("DISABLE"),
    .CLKC3_ENABLE("DISABLE"),
    .CLKC3_FPHASE(0),
    .CLKC4_CPHASE(1),
    .CLKC4_DIV(1),
    .CLKC4_DIV2_ENABLE("DISABLE"),
    .CLKC4_ENABLE("DISABLE"),
    .CLKC4_FPHASE(0),
    .DERIVE_PLL_CLOCKS("DISABLE"),
    .DPHASE_SOURCE("DISABLE"),
    .DYNCFG("DISABLE"),
    .FBCLK_DIV(17),
    .FEEDBK_MODE("NORMAL"),
    .FEEDBK_PATH("CLKC0_EXT"),
    .FIN("24.000"),
    .FREQ_LOCK_ACCURACY(2),
    .GEN_BASIC_CLOCK("DISABLE"),
    .GMC_GAIN(6),
    .GMC_TEST(14),
    .ICP_CURRENT(3),
    .IF_ESCLKSTSW("DISABLE"),
    .INTFB_WAKE("DISABLE"),
    .KVCO(6),
    .LPF_CAPACITOR(3),
    .LPF_RESISTOR(2),
    .NORESET("DISABLE"),
    .ODIV_MUXC0("DIV"),
    .ODIV_MUXC1("DIV"),
    .ODIV_MUXC2("DIV"),
    .ODIV_MUXC3("DIV"),
    .ODIV_MUXC4("DIV"),
    .PLLC2RST_ENA("DISABLE"),
    .PLLC34RST_ENA("DISABLE"),
    .PLLMRST_ENA("DISABLE"),
    .PLLRST_ENA("DISABLE"),
    .PLL_LOCK_MODE(0),
    .PREDIV_MUXC0("VCO"),
    .PREDIV_MUXC1("VCO"),
    .PREDIV_MUXC2("VCO"),
    .PREDIV_MUXC3("VCO"),
    .PREDIV_MUXC4("VCO"),
    .REFCLK_DIV(16),
    .REFCLK_SEL("INTERNAL"),
    .STDBY_ENABLE("DISABLE"),
    .STDBY_VCO_ENA("DISABLE"),
    .SYNC_ENABLE("DISABLE"),
    .VCO_NORESET("DISABLE"))
    pll_inst (
    .daddr(6'b000000),
    .dclk(1'b0),
    .dcs(1'b0),
    .di(8'b00000000),
    .dwe(1'b0),
    .fbclk(clk0_out),
    .psclk(1'b0),
    .psclksel(3'b000),
    .psdown(1'b0),
    .psstep(1'b0),
    .refclk(refclk),
    .reset(1'b0),
    .stdby(1'b0),
    .clkc({open_n47,open_n48,open_n49,open_n50,clk0_buf}));  // al_ip/pll.v(53)

endmodule
module uart
#(
	parameter BAUDRATE = 115200,
	parameter CLK_RATE = 50000000
)
(
    input	wire		clk,

    // uart
    input	wire		rx,
    output  wire		tx,
	
	// uart recv
	output	wire		recv_en,
	output	wire [7:0]	recv_cmd,
	output	wire [7:0]	recv_data,
	
    // uart send
    input   wire		send_en,
    input   wire [7:0]	send_cmd,
    input   wire [7:0]	send_data,
    output  wire		send_ready
);

wire rx_en;
wire [7:0] rx_data;
wire tx_en;
wire [7:0] tx_data;
wire tx_ready;

//串口接收模块
uart_rx
#(
	.BAUDRATE	(BAUDRATE	    ),
	.CLK_RATE	(CLK_RATE	    )
)
u_uart_rx
(
    .clk        (clk            ),
    .rx         (rx             ),
    .rx_en    	(rx_en          ),
    .rx_data	(rx_data        )
);

//串口发送模块
uart_tx
#(
	.BAUDRATE	(BAUDRATE	    ),
	.CLK_RATE	(CLK_RATE	    )
)
u_uart_tx
(
    .clk        (clk            ),
    .tx         (tx             ),
    
`ifdef UART_LOOPBACK // 串口回环测试
    .tx_en		(rx_en          ),
    .tx_data	(rx_data        ),
`else
    .tx_en		(tx_en          ),
    .tx_data	(tx_data        ),
`endif

	.tx_ready	(tx_ready	    )
);

// 串口通信协议
ubus u_ubus
(
    .clk        (clk            ),
    
    // uart-rx
    .rx_en      (rx_en          ),
    .rx_data    (rx_data        ),
    
    // uart-tx
    .tx_en      (tx_en          ),
    .tx_data    (tx_data        ),
    .tx_ready   (tx_ready       ),
    
	// uart bus recv
    .recv_en    (recv_en        ),
    .recv_cmd	(recv_cmd		),
    .recv_data  (recv_data      ),
	
    // uart bus send
    .send_en    (send_en        ),
    .send_cmd	(send_cmd		),
    .send_data  (send_data      ),
    .send_ready (send_ready     )
);

endmodule
module uart_rx
#(
	parameter BAUDRATE = 115200,
	parameter CLK_RATE = 50000000
)
(
    input	wire		clk,
	
	// uart
    input	wire		rx,
	
	// data
    output  reg			rx_en,
    output  reg [7:0]	rx_data
);

reg start;
reg clk_en;
reg [3:0] cnt;
reg [7:0] data;
reg [1:0] rx_d;
reg [31:0] clk_cnt;

initial
begin
    start = 0;
end

// 边沿检测
always@(posedge clk)
begin
    rx_d <= {rx_d[0],rx};
end

// 数据传输控制
always@(posedge clk)
begin
    if(rx_d == 2'b10) // 检测到下降沿传输开始
        start <= 1;
    else if(cnt == 9) // 数据接收完成
        start <= 0;
end

// 波特率计数器
always@(posedge clk)
begin
	if(!start)
		clk_cnt <= (CLK_RATE / (BAUDRATE*2)); // 中间采样
	else if(clk_cnt == CLK_RATE / BAUDRATE - 1)
		clk_cnt <= 0;
	else
		clk_cnt <= clk_cnt + 1;
end

// 波特率计数器
always@(posedge clk)
begin
	clk_en <= (clk_cnt == CLK_RATE / BAUDRATE - 1);
end

// 接收数据计数器
always@(posedge clk)
begin
	if(!start)
        cnt <= 0;
	else if(clk_en)
        cnt <= cnt + 1;
end

// 接收数据采样
always@(posedge clk)
if(clk_en)
begin
    case(cnt)
        1: data[0] <= rx;
        2: data[1] <= rx;
        3: data[2] <= rx;
        4: data[3] <= rx;
        5: data[4] <= rx;
        6: data[5] <= rx;  
        7: data[6] <= rx;    
        8: data[7] <= rx;
    endcase   
end

// 数据输出使能
always@(posedge clk)
begin
    rx_en <= (start && cnt == 9);
end

// 数据输出
always@(posedge clk)
begin
    if(cnt == 9)
        rx_data <= data;
end

endmodule
module uart_tx
#(
	parameter BAUDRATE = 115200,
	parameter CLK_RATE = 50000000
)
(
    input	wire		clk,
	
	// uart
    output  reg			tx,
	
	// data
    input	wire		tx_en,
    input	wire [7:0]	tx_data,
	output	reg			tx_ready
);

reg start;
reg clk_en;
reg [3:0] cnt;
reg [7:0] data;
reg [31:0] clk_cnt;

initial
begin
	start = 0;
end

// 波特率计数器
always@(posedge clk)
begin
	if(!start)
		clk_cnt <= 0;
	else if(clk_cnt == CLK_RATE / BAUDRATE - 1)
		clk_cnt <= 0;
	else
		clk_cnt <= clk_cnt + 1;
end

// 波特率计数器
always@(posedge clk)
begin
	clk_en <= (clk_cnt == CLK_RATE / BAUDRATE - 1);
end

// 数据传输控制
always@(posedge clk)
begin
    if(tx_en) // 传输开始
        start <= 1;
    else if(cnt == 10) // 传输结束
        start <= 0;
end

// 数据寄存
always@(posedge clk)
begin
	if(tx_en && !start)
		data <= tx_data;
end

// 状态计数器
always@(posedge clk)
begin
    if(!start)
		cnt <= 0;
	else if(clk_en)
        cnt <= cnt + 1;
end

// 串口发送
always@(posedge clk)
begin
    case(cnt)
		0: tx <= 1'b1;    // 发送停止位(上电状态).
        1: tx <= 1'b0;    // 传输开始
        2: tx <= data[0]; // 发送数据位的第1位bit0
        3: tx <= data[1]; // 发送数据位的第2位bit1
        4: tx <= data[2]; // 发送数据位的第3位bit2
        5: tx <= data[3]; // 发送数据位的第4位bit3
        6: tx <= data[4]; // 发送数据位的第5位bit4
        7: tx <= data[5]; // 发送数据位的第6位bit5
        8: tx <= data[6]; // 发送数据位的第7位bit6
        9: tx <= data[7]; // 发送数据位的第8位bit7
        10:tx <= 1'b1;    // 发送停止位
    endcase
end

// 发送模块可用
always@(posedge clk)
begin
	if(tx_en)
		tx_ready <= 0;
	else
		tx_ready <= !start;
end

endmodule
module fetch
(
    input   wire		clk,
    
    // rom
    output  reg			rom_ren,
	output  reg  [23:0]	rom_raddr,
	input   wire [7:0]	rom_rdata,
    
    // debug
    input   wire		dbg_en,
    input   wire		dbg_rom_ren,
    input   wire [23:0]	dbg_rom_raddr,
    output  reg  [7:0]	dbg_rom_rdata,
    input   wire		dbg_inst_en,
    input   wire [7:0]	dbg_inst,

    // timer
    input   wire		timer_state,
    
    // pc
    input   wire		pc_wen,
    input   wire [23:0]	pc_wdata,
    
    // instruction
    output  reg			inst_en,
    output  reg [7:0]	inst
);

reg [23:0] pc;
reg fetch_en;
reg rom_bk_en;

// rom寻址使能
always@(posedge clk)
begin
    if(dbg_en)
        fetch_en <= 0;
    else if(timer_state)
        fetch_en <= 1;
    else
        fetch_en <= 0;
end

// pc计数器
always@(posedge clk)
begin
    if(dbg_en)
        pc <= 0;
    else if(pc_wen)
        pc <= pc_wdata;
    else if(fetch_en)
        pc <= pc + 1;
end

// 读rom使能
always@(posedge clk)
begin
    rom_ren <= dbg_rom_ren || fetch_en;
end

// 读rom数据
always@(posedge clk)
begin
    if(dbg_rom_ren)
        rom_raddr <= dbg_rom_raddr;
    else if(fetch_en)
        rom_raddr <= pc;
end

// 指令使能
always@(posedge clk)
begin
    rom_bk_en <= rom_ren;
    inst_en <= dbg_inst_en || rom_bk_en;
end

// 指令数据
always@(posedge clk)
begin
    if(dbg_inst_en)
        inst <= dbg_inst;
    else if(rom_bk_en)
        inst <= rom_rdata;
end

// 调试数据返回
always@(posedge clk)
begin
    if(dbg_en)
        dbg_rom_rdata <= rom_rdata;
end

endmodule
module timer
(
    input   wire		clk,
    
    // timer set
    input   wire		timer_wen,
    input   wire [23:0]	timer_wdata,
    
    output  reg			timer_state
);

reg [23:0] cnt;

// 定时器计时
always@(posedge clk)
begin
    if(timer_wen)
        cnt <= timer_wdata;
    else if(cnt != 0)
        cnt <= cnt - 1;
end

// 定时器状态
always@(posedge clk)
begin
    timer_state <= (cnt == 0);
end

endmodule
module ram
#(
  parameter Len = 256 // ram深度
)
(
    input   wire		clk,
    
    // write
    input   wire		ram_wen,
    input   wire [7:0]	ram_waddr,
    input   wire [7:0]	ram_wdata,
    
    // read
    input   wire		ram_ren,
    input   wire [7:0]	ram_raddr,
    output  reg  [7:0]	ram_rdata
);

reg [7:0] ram_reg [0:Len-1];

// 写入数据到ram
always@(posedge clk)
begin
    if(ram_wen)
        ram_reg[ram_waddr] <= ram_wdata;
end

// 读取ram数据
always@(posedge clk)
begin
    if(ram_ren)
        ram_rdata <= ram_reg[ram_raddr];
end

endmodule
module bus
(
    input   wire		clk,
    
	// write bus
	input	wire		bus_wen,
	input	wire [7:0]	bus_waddr,
	input	wire [7:0]	bus_wdata,
	
	// read bus
	input	wire		bus_ren,
	input	wire [7:0]	bus_raddr,
	output	reg  [7:0]	bus_rdata,
    
    // user port
	// vram
	output	reg			vram_wen,
	output	reg			vram_wdata,
	output	reg			vram_ren,
	input	wire		vram_rdata,
	output	reg [7:0]	vram_addr,
	
	// key & led
	input	wire [5:0]	key,
	output	reg			clear,
    output  reg			led
);

// 总线写数据
always@(posedge clk)
begin
    if(bus_wen)
    begin
        case(bus_waddr)
         0: led <= bus_wdata;
		 1: vram_addr <= bus_wdata;
		 2: vram_wdata <= bus_wdata;
		
        endcase
    end
end

// 总线读数据
always@(posedge clk)
begin
    if(bus_ren)
    begin
        case(bus_raddr)
         0: bus_rdata <= led;
		 1: bus_rdata <= key;
		 2: bus_rdata <= vram_rdata;
		 
		 
         default: bus_rdata <= 0;
        endcase
    end
end

// 控制信号
always@(posedge clk)
begin
	clear <= bus_ren && (bus_raddr == 1);
	vram_ren <= bus_wen && (bus_waddr == 1);
	vram_wen <= bus_wen && (bus_waddr == 2);
end

endmodule
module rom
#(
  parameter Len = 32768 // rom深度  
)
(
    input   wire		clk,
    
    // write
    input   wire		rom_wen,
    input   wire [23:0]	rom_waddr,
    input   wire [7:0]	rom_wdata,
    
    // read
    input   wire		rom_ren,
    input   wire [23:0]	rom_raddr,
    output  reg	 [7:0]	rom_rdata
);

reg [7:0] rom_reg [0:Len-1];

// 加载rom程序
initial
begin
    $readmemh("./sources/rtl/mcu/rom.o",rom_reg);
end

// 写入数据到rom
always@(posedge clk)
begin
    if(rom_wen)
        rom_reg[rom_waddr] <= rom_wdata;
end

// 读取rom数据
always@(posedge clk)
begin
    if(rom_ren)
        rom_rdata <= rom_reg[rom_raddr];
end

endmodule
module debug
(
    input   wire		clk,
    
    // rom write
    output  reg			rom_wen,
    output  reg [23:0]	rom_waddr,
    output  reg [7:0]	rom_wdata,
    
    // rom read
    output  reg			rom_ren,
    output  reg  [23:0]	rom_raddr,
    input   wire [7:0]	rom_rdata,
    
    // debug inst
    output  reg			dbg_en,
    output  reg			dbg_inst_en,
    output  reg  [7:0]	dbg_inst,
    
    // debug info
    output  reg  [3:0]	read_abcd,
    input   wire		dbg_info_en,
    input   wire [15:0]	dbg_info,
    
    // uart
	input	wire		recv_en,
	input	wire [7:0]	recv_cmd,
	input	wire [7:0]	recv_data,
    output  reg			send_en,
    output  reg  [7:0]	send_cmd,
    output  reg  [7:0]	send_data,
    input   wire		send_ready
);

reg free_run_cmd;
reg debug_cmd;
reg clear_rom_addr_cmd;
reg clear_rom_data_cmd;
reg read_rom_cmd;
reg write_rom_cmd;
reg read_a_cmd;
reg read_b_cmd;
reg read_c_cmd;
reg read_d_cmd;
reg rom_ren_d0;
reg rom_ren_d1;
reg rom_bk_en;

// 串口命令解析
always@(*)
begin
    free_run_cmd        = (recv_cmd == 0);
    debug_cmd           = (recv_cmd == 1);
    clear_rom_addr_cmd  = (recv_cmd == 2);
    clear_rom_data_cmd  = (recv_cmd == 3);
    read_rom_cmd        = (recv_cmd == 4);
    write_rom_cmd       = (recv_cmd == 5);
    read_a_cmd          = (recv_cmd == 6);
    read_b_cmd          = (recv_cmd == 7);
    read_c_cmd          = (recv_cmd == 8);
    read_d_cmd          = (recv_cmd == 9);
end

// 调试模式
always@(posedge clk)
begin
    if(free_run_cmd)
        dbg_en <= 0;
    else if(debug_cmd)
        dbg_en <= 1;
end

// 调试指令
always@(posedge clk)
begin
    dbg_inst_en <= recv_en && debug_cmd;
    if(debug_cmd)
        dbg_inst <= recv_data;
end

// 读取A、B、C、D寄存器值
always@(posedge clk)
begin
    read_abcd[0] <= recv_en && read_a_cmd;
    read_abcd[1] <= recv_en && read_b_cmd;
    read_abcd[2] <= recv_en && read_c_cmd;
    read_abcd[3] <= recv_en && read_d_cmd;
end

// 写rom使能
always@(posedge clk)
begin
    if(clear_rom_data_cmd)
        rom_wen <= 1;
    else
        rom_wen <= recv_en && write_rom_cmd;
end

// 写rom地址
always@(posedge clk)
begin
    if(clear_rom_addr_cmd)
        rom_waddr <= 0;
    else if(rom_wen)
        rom_waddr <= rom_waddr + 1;
end

// 写rom数据
always@(posedge clk)
begin
    if(clear_rom_data_cmd)
        rom_wdata <= 0;
    else if(recv_en && write_rom_cmd)
        rom_wdata <= recv_data;
end

// 读rom使能
always@(posedge clk)
begin
    rom_ren <= recv_en && read_rom_cmd;
end

// 读rom地址
always@(posedge clk)
begin
    if(clear_rom_addr_cmd)
        rom_raddr <= 0;
    else if(rom_ren)
        rom_raddr <= rom_raddr + 1;
end

// rom数据返回
always@(posedge clk)
begin
    rom_ren_d0 <= rom_ren;
    rom_ren_d1 <= rom_ren_d0;
    rom_bk_en <= rom_ren_d1;
end

// 串口发送使能
always@(posedge clk)
begin
    send_en <= send_ready && (dbg_info_en || rom_bk_en);
end

// 串口发送数据
always@(posedge clk)
begin
    if(dbg_info_en)
    begin
        send_cmd <= dbg_info[15:8];
        send_data <= dbg_info[7:0];
    end
    else if(rom_bk_en)
    begin
        send_cmd <= 0;
        send_data <= rom_rdata;
    end
end

endmodule
module alu
(
    input   wire		clk,
    
	// alu in
    input   wire [10:0]	alu_cmd,
	input	wire [7:0]	alu_in1,
	input	wire [7:0]	alu_in2,

    // alu out
	output  reg [8:0]	alu_out0,
	output  reg [15:0]	alu_out1,
	output  reg [7:0]	alu_out2,
	output  reg [7:0]	alu_out3,
	output  reg [7:0]	alu_out4
);

// 加/减运算
always@(posedge clk)
begin
    if(alu_cmd[0])  
		alu_out0  <= (alu_in1 + alu_in2);
    else if(alu_cmd[1])  
		alu_out0  <= (alu_in1 - alu_in2);
end

// 乘法运算
always@(posedge clk)
begin
    if(alu_cmd[2])  
		alu_out1  <= (alu_in1 * alu_in2);
end

// 比较运算
always@(posedge clk)
begin
    if(alu_cmd[3]) 
		alu_out2 <= (alu_in1 >  alu_in2);
    else if(alu_cmd[4]) 
		alu_out2 <= (alu_in1 == alu_in2);
end

// 逻辑运算
always@(posedge clk)
begin
    if(alu_cmd[5])  
		alu_out3 <= (alu_in1 && alu_in2);
    else if(alu_cmd[6])  
		alu_out3 <= (alu_in1 &  alu_in2);
    else if(alu_cmd[7])  
		alu_out3 <= (alu_in1 || alu_in2);
    else if(alu_cmd[8])  
		alu_out3 <= (alu_in1 |  alu_in2);
end

// 移位操作
always@(posedge clk)
begin
    if(alu_cmd[9])  
		alu_out4 <= (alu_in1 << alu_in2);
    else if(alu_cmd[10]) 
		alu_out4 <= (alu_in1 >> alu_in2);
end

endmodule
module key
(
	input	wire		clk,
	
	// cpu握手信号
	input	wire		clear,
	
	// 按键处理
	input	wire [5:0]	key_i, // 按键按下为低电平输入
	output	reg  [5:0]	key_o  // 按键按下为高电平输出
);

reg [18:0] cnt;
reg [5:0] key_d0;
reg [5:0] key_d1;
reg key_flag;

// 按键采样计数器(采样时间20ms左右)
always@(posedge clk)
begin
    cnt <= cnt + 1;
end

// 按键采样(消除抖动)
always@(posedge clk)
begin
    if(&cnt)
        key_d0 <= ~key_i;
end

// 下降沿提取
always@(posedge clk)
begin
    key_d1 <= key_d0;
	key_flag <= !key_d1 && key_d0;
end

// 按键握手处理
always@(posedge clk)
begin
	if(clear)
		key_o <= 0;
	else if(key_flag)
		key_o <= key_d1;
end

endmodule