dakies/OSS_Verilog huggingface dataset:
module debouncing_button(
	input clk,rst_n,
	input sw_low, //active low
	output reg db
    );
	 
	 localparam N=20; //free-running counter, 2^N/50MHz=2^20/50MHz=20.9ms 
	 
	 //symbolic declaration for FSM
	 localparam [2:0] zero=3'd0,
							mid0_1=3'd1,
							mid0_2=3'd2,
							one=3'd3,
							mid1_1=3'd4,
							mid1_2=3'd5;
							
	 reg[2:0] state_reg=0,state_nxt=0;
	 reg[N-1:0] counter=0; 
	 wire[N-1:0] counter_nxt;
	 wire sw,tick;
	 assign sw=!sw_low; //sw is now active high
	 
	 //Logic for FSM and free-running-counter 
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
				state_reg<=zero;
				counter<=0;
		end
		
		else begin
				state_reg<=state_nxt;
				counter<=counter_nxt;			
		 end
	 end
	 //next-state logic of FSM and free-running-counter
	 assign counter_nxt=counter+1;
	 assign tick=(counter==0);
	 always @* begin
		 state_nxt=state_reg;
		 db=0;
		 case(state_reg)
				zero: if(sw) state_nxt=mid0_1;
				mid0_1: begin
							if(!sw) state_nxt=zero;
							else if(tick) state_nxt=mid0_2;
						  end
				mid0_2: begin 
							if(!sw) state_nxt=zero;
							else if(tick) state_nxt=one;
						  end
					one: begin
							 db=1;
							 if(!sw) state_nxt=mid1_1;
						  end
				mid1_1: begin
							 db=1;
							 if(sw) state_nxt=one;
							 else if(tick) state_nxt=mid1_2;
						  end
			  mid1_2:  begin
							 db=1;
							 if(sw) state_nxt=one;
							 else if(tick) state_nxt=zero;
						  end
			  default: state_nxt=zero;
		  endcase
	 end


endmodule
module keyboard_text_ps2
	(
	input clk,rst_n,
	input ps2c,ps2d, //ascii characters will come from ps2 keboard
	output[4:0] vga_out_r,
	output[5:0] vga_out_g,
	output[4:0] vga_out_b,
	output vga_out_vs,vga_out_hs
    );
	 
	 wire[11:0] pixel_x,pixel_y;
	 wire video_on;
	 wire[2:0] rgb;
	 
	 
	 assign vga_out_r=rgb[2]? 5'b111_11:0 ;
	 assign vga_out_g=rgb[1]? 6'b111_111:0 ;
	 assign vga_out_b=rgb[0]? 5'b111_11:0 ;
	 

	 vga_core m0
	(
		.clk(clk_out),  //clock must be 25MHz for 640x480 
		.rst_n(rst_n),
		.hsync(vga_out_hs),
		.vsync(vga_out_vs),
		.video_on(video_on),
		.pixel_x(pixel_x),
		.pixel_y(pixel_y)
    );	
	 
	full_screen_gen m1 //generates the characters to be displayed on screen, the ASCII characters will come from ps2 keyboard
	(
		.clk(clk_out),
		.rst_n(rst_n),
		.ps2c(ps2c),
		.ps2d(ps2d),
		.pixel_x(pixel_x),
		.pixel_y(pixel_y),
		.video_on(video_on),
		.rgb(rgb)
    );
	
	 dcm_25MHz m2
		(// Clock in ports
		 .clk(clk),      // IN
		 // Clock out ports
		 .clk_out(clk_out),     // OUT
		 // Status and control signals
		 .RESET(RESET),// IN
		 .LOCKED(LOCKED)
	 );      
	
endmodule
module kb(   //extract only the real bytes from received packets of data(no break code)
	input clk,rst_n,
	input ps2d,ps2c,
	input rd_fifo,
	output [8:0] rd_data,
	output fifo_empty,
	output breakcode
    );
	 wire[10:0] dout;
	 wire rx_done_tick;
	 wire wr;
	 wire [8:0] wr_data;
 
	 ps2_rx m0
	 (
		.clk(clk),
		.rst_n(rst_n),
		.rx_en(1),
		.ps2d(ps2d),
		.ps2c(ps2c),
		.dout(dout),
		.rx_done_tick(rx_done_tick)
    );
	 
	 kb_data m1
	 (
		.clk(clk),
		.rst_n(rst_n),
		.rx_done_tick(rx_done_tick),
		.din(dout[8:1]),
		.wr(wr),
		.wr_data(wr_data),
		.break_code(breakcode)
    );
	 
	  fifo #(.W(4),.B(9)) m2
	(
		.clk(clk),
		.rst_n(rst_n),
		.wr(wr),
		.rd(rd_fifo), //
		.wr_data(wr_data),
		.rd_data(rd_data),//
		.full(),
		.empty(fifo_empty) //
    );
	 
endmodule
module kb_data(
	input clk,rst_n,
	input rx_done_tick,
	input[7:0] din,
	output reg wr,
	output reg[8:0] wr_data, //9th bit is asserted if shift is pressed(for capital letters),
	output break_code
    );
	 //FSM state declarations
	 localparam[1:0] idle=2'd0,
							scan=2'd1,
							breakcode=2'd3;
	 reg[1:0] state_reg;
	 reg shift_reg=0;
	 
	 //FSM register operations
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			state_reg<=idle;
			shift_reg<=0;
		end
		
		else begin
		wr=0;
		wr_data=0;
			case(state_reg)
				idle: if(rx_done_tick) begin //wait for the makecode
							if(din==8'hf0) state_reg<=breakcode; //break code
							else begin
								if(din==8'h12 || din==8'h59) begin//shift key 
									shift_reg<=1;
									state_reg<=scan;
								end
								else begin//non-shift key
									wr_data={shift_reg,din};
									wr=1;
									state_reg<=scan;
								end
							end							
						 end
				scan: if(rx_done_tick) begin 
							if(din==8'hf0) state_reg<=breakcode; //break code
							else begin
								if(din==8'h12 || din==8'h59) shift_reg<=1; //shift key
								else begin //non-shift key
									wr_data={shift_reg,din};
									wr=1;
								end
							end
						end
		 breakcode: if(rx_done_tick) begin
							if(din==8'h12 || din==8'h59) shift_reg<=0; //end of shift key
							state_reg<=idle;	//skip the makecode after the breakcode 8'hf0 	
						end
			default: state_reg<=idle;
			endcase
		end
	 end
	 
	 assign break_code=state_reg==breakcode;
	 


endmodule
module sqwave_gen(
	input clk,rst_n,
	input[3:0] m,n,
	output out
    );
	 
	 reg[6:0] m_reg=0,n_reg=0; //counter for ON period of m*(100ns) and OFF period of n*(100ns)
	 reg sq_reg=0; //square wave output
	 reg[6:0] m_nxt=0,n_nxt=0;
	 reg sq_nxt=0;
	 reg m_max=0,n_max=0;
	 
	 //registers
	 always @(posedge clk,negedge rst_n) begin
		 if(!rst_n) begin
			m_reg<=0;
			n_reg<=0;
			sq_reg<=0;
		end
		
		else begin
			m_reg<=m_nxt;
			n_reg<=n_nxt;
			sq_reg<=sq_nxt;
		end
	end
	
	//next-state logic
	always @* begin
	m_nxt=m_reg;
	n_nxt=n_reg;
	m_max=0;
	n_max=0;
	sq_nxt=0;
		
		if( m==4'd0 || n==4'd0) begin  //if m or n is zero then out must remain in one position
			m_nxt=0;
			n_nxt=0;
			casez({|m,|n}) //reduction operator
			2'b00: sq_nxt=0;
			2'b01: sq_nxt=0;
			2'b10: sq_nxt=1;
			default: sq_nxt=0;
			endcase
		end
		
		//OFF logic with duration of n*100ns
		else if(sq_reg==0) begin
			m_nxt=0;
			n_nxt=(n_reg==5*n-1)?0:n_reg+1;  //50MHz*100ns*n=5*n
			n_max=(n_reg==5*n-1)?1:0;        //50MHz*100ns*n=5*n
			sq_nxt=n_max?1:0;
			end
		//ON logic with duration of m*100ns
		else if(sq_reg==1) begin
			n_nxt=0;
			m_nxt=(m_reg==5*m-1)?0:m_reg+1;
			m_max=(m_reg==5*m-1)?1:0;
			sq_nxt=m_max?0:1;
		end
	end
	
	assign out=sq_reg;
		
endmodule
module sqwave_gen_TB;

	// Inputs
	reg clk;
	reg rst_n;
	reg [3:0] m;
	reg [3:0] n;

	// Outputs
	wire out;

	// Instantiate the Unit Under Test (UUT)
	sqwave_gen uut (
		.clk(clk), 
		.rst_n(rst_n), 
		.m(m), 
		.n(n), 
		.out(out)
	);
	
	always begin
	clk=1'b0;
	#10;
	clk=1'b1;
	#10;
	end

	initial begin
		// Initialize Inputs
		rst_n = 1'b1;
		m = 0;
		n = 0;
		@(negedge clk) rst_n=0;
		@(negedge clk) rst_n=1;
		$display("ON=100ns OFF=200ns");
		m=4'd1;
		n=4'd2; // ON=100ns OFF=200ns (0-1000)
		#1000;
		$display("ON=300ns OFF=200ns");
		m=4'd3;
		n=4'd2; // ON=300ns OFF=100ns (1000-2000)
		#1000; 
		$display("ON=500ns OFF=500ns");
		m=4'd5;
		n=4'd5;  //ON=500ns OFF=500ns (2000-3500)
		#1500 ;
		$display("ON=0ns OFF=100ns");
		m=4'd0; //ON=0ns OFF=100ns (3500-4500)
		n=4'd1;
		#1000;
		$display("ON=100ns OFF=0ns");
		m=4'd1; //ON=0ns OFF=100ns (4500-5500)
		n=4'd0;
		#1000;
		$display("ON=300ns OFF=200ns");
		m=4'd3;
		n=4'd2; // ON=300ns OFF=100ns (5500-6500)
		#1000;
		$stop;
	end
	initial begin
		$display("Out Time");
		$monitor("%d   %d",out,$time);
	end
      
endmodule
module main_controller(
	input clk,rst_n,
	input sw1,sw2, //sw1=increase fibo input, sw2=display either the fibo input or the output
	output[7:0] seg_out,
	output[5:0] sel_out
    );
	 localparam[1:0] idle=2'd0,
							bcd2bin=2'd1,
							fibonacci=2'd2,
							bin2bcd=2'd3;
	 reg[1:0] state_reg,state_nxt;
	 reg start_bcd2bin,start_fibo,start_bin2bcd;
	 wire done_bcd2bin,done_fibo,done_bin2bcd;
	 wire[3:0] dig0_counter,dig1_counter;
	 wire [6:0] bin;
	 wire[20:0] fibo;
	 reg[3:0] dig0,dig1,dig2,dig3,dig4,dig5;
	 wire[3:0] dig0_bin,dig1_bin,dig2_bin,dig3_bin,dig4_bin,dig5_bin;
	 wire done_counter;
	 //FSM state declarations
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) state_reg<=idle;
		else state_reg<=state_nxt;
	 end
	 
	 //FSM next-state logics
	 always @* begin
		state_nxt=state_reg;
		start_bcd2bin=0;
		start_fibo=0;
		start_bin2bcd=0;
		case(state_reg)
				idle: if(done_counter) begin
							start_bcd2bin=1;
							state_nxt=bcd2bin;
						end
			bcd2bin: if(done_bcd2bin) begin
							start_fibo=1;
							state_nxt=fibonacci;
						end
		 fibonacci: if(done_fibo) begin
							start_bin2bcd=1;
							state_nxt=bin2bcd;
						end
			bin2bcd: if(done_bin2bcd) state_nxt=idle;
			default: state_nxt=idle;
		endcase
	 end
	 always @* begin
		if(sw2) begin
			dig0=dig0_counter;
			dig1=dig1_counter;
			dig2=0;
			dig3=0;
			dig4=0;
			dig5=0;
		end
		else begin
			dig0=dig0_bin;
			dig1=dig1_bin;
			dig2=dig2_bin;
			dig3=dig3_bin;
			dig4=dig4_bin;
			dig5=dig5_bin;
		end
	 end

	 //instantiation of all module used
	bcd_counter m0 //mod-50 counter
	(
		.clk(clk),
		.rst_n(rst_n),
		.sw(sw1),
		.dig1(dig1_counter),
		.dig0(dig0_counter),
		.done_tick(done_counter)
    );
	 
	bcd2bin m1 //convert 2 digit to binary(0-to-49)
	(
		.clk(clk),
		.rst_n(rst_n),
		.start(start_bcd2bin),
		.dig1(dig1_counter),
		.dig0(dig0_counter),
		.bin(bin), 
		.ready(),
		.done_tick(done_bcd2bin)
    );
	 
	fibonacci m2 //outputs fibonacci value of bin(bin>29 will get "999_999" as a result)
	(
	.clk(clk),
	.rst_n(rst_n),
	.start(start_fibo),
	.i(bin),
	.fibo(fibo),
	.ready(),
	.done_tick(done_fibo)
    );
	 
	 bin2bcd m3( //convertes fibo binary to bcd
	.clk(clk),
	.rst_n(rst_n),
	.start(start_bin2bcd),
	.bin(fibo),//limit is 6 digit of bcd so only 19 bits of fibo will be considered
	.ready(),
	.done_tick(done_bin2bcd),
	.dig0(dig0_bin),
	.dig1(dig1_bin),
	.dig2(dig2_bin),
	.dig3(dig3_bin),
	.dig4(dig4_bin),
	.dig5(dig5_bin)
    );
	 
	 LED_mux m4 //bcd value will used as input to 6-seven-segment display
	(
	.clk(clk),
	.rst(rst_n),
	.in0(dig0),
	.in1(dig1),
	.in2(dig2),
	.in3(dig3),
	.in4(dig4),
	.in5(dig5), //format: {dp,hex[3:0]}
	.seg_out(seg_out),
	.sel_out(sel_out)
    );

endmodule
module bcd2bin(
	input clk,rst_n,
	input start,
	input[3:0] dig1,dig0,
	output reg[6:0] bin, //2-digit number takes at most 7 bits
	output reg ready,done_tick
    );
	 //FSM state declarations
	 localparam[1:0] idle=2'd0,
							op=2'd1,
							done=2'd2;
	 reg[1:0] state_reg,state_nxt;
	 reg[6:0] bin_nxt;
	 reg[3:0] dig1_reg,dig1_nxt;
	 reg[3:0] dig0_reg,dig0_nxt;
	 reg[2:0] n_reg,n_nxt; //stores the width of the resulting binary
	 
	 //FSM register operation
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			state_reg<=idle;
			bin<=0;
			dig1_reg<=0;
			dig0_reg<=0;
			n_reg<=0;
		end
		else begin
			state_reg<=state_nxt;
			bin<=bin_nxt;
			dig1_reg<=dig1_nxt;
			dig0_reg<=dig0_nxt;
			n_reg<=n_nxt;
		end
	 end
	 //FSM next-state logic
	 always @* begin
		state_nxt=state_reg;
		bin_nxt=bin;
		dig1_nxt=dig1_reg;
		dig0_nxt=dig0_reg;
		n_nxt=n_reg;
		ready=0;
		done_tick=0;
		case(state_reg)
				idle: begin
							ready=1;
							if(start) begin
								bin_nxt=0;
								dig1_nxt=dig1;
								dig0_nxt=dig0;
								n_nxt=7; //binary has 7 bits of output thus 7 "shifts" are needed
								state_nxt=op;
							end
						end
				  op: begin //special shift-operation for converting bcd to bin.Check the book for more info
							if( {dig1_reg[0],dig0_reg[3:1]} >= 8 ) ///special shift-operation for converting bcd to bin.Check the book for more info
								dig0_nxt= {dig1_reg[0],dig0_reg[3:1]} - 3;
							else dig0_nxt= {dig1_reg[0],dig0_reg[3:1]};
							dig1_nxt=dig1_reg>>1;
							bin_nxt={dig0_reg[0],bin[6:1]};
							n_nxt=n_reg-1;
							if(n_nxt==0) state_nxt=done;
						end
				done: begin
							done_tick=1;
							state_nxt=idle;
						end
			default: state_nxt=idle;
		endcase
	 end
	 


endmodule
module fibonacci(
	input clk,rst_n,
	input start,
	input[5:0] i,
	output[20:0] fibo,
	output reg ready,done_tick
    );
	 //FSM declarations
	 localparam[1:0] idle=2'd0,
							op=2'd1,
							done=2'd2;
	 reg[1:0] state_reg,state_nxt;
	 reg[20:0] i1_reg,i0_reg,i1_nxt,i0_nxt;
	 reg[5:0] n_reg,n_nxt;
	 //FSM register operation
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			state_reg<=idle;
			i1_reg<=0;
			i0_reg<=0;
			n_reg<=0;
		end
		else begin
			state_reg<=state_nxt;
			i1_reg<=i1_nxt;
			i0_reg<=i0_nxt;
			n_reg<=n_nxt;
		end
	 end
	 
	 //FSM next-state logics
	 always @* begin
		state_nxt=state_reg;
		i1_nxt=i1_reg;
		i0_nxt=i0_reg;
		n_nxt=n_reg;
		ready=0;
		done_tick=0;
		
		case(state_reg) 
			idle: begin
						ready=1;
						if(start) begin
							i1_nxt=1;
							i0_nxt=0;
							n_nxt=i;
							state_nxt=op;
							if(i>30) begin
							i1_nxt=999_999;
							state_nxt=done;
							end
						end
					 end
			 op: begin
						 if(n_reg==0) begin
							i1_nxt=0;
							state_nxt=done;
						 end
						 else begin
							if(n_reg==1) state_nxt=done;
							else begin
								i1_nxt=i1_reg+i0_reg;
								i0_nxt=i1_reg;
								n_nxt=n_reg-1;
							end
						 end
				  end
			 done: begin
						done_tick=1;
						state_nxt=idle;
					 end
			 default: state_nxt=idle;
		endcase
	 end
	 assign fibo=i1_reg;
			
	 
endmodule
module bcd_counter(
	input clk,rst_n,
	input sw, //active-low
	output reg[3:0] dig1,dig0,
	output reg done_tick
    );
	 localparam idle=0,done=1;
	 reg state_reg,state_nxt;
	initial begin
		dig1=0;
		dig0=0;
	end
	 reg[3:0] dig1_nxt,dig0_nxt;
	 wire r_edg,sw_hi; //sw_hi:debounce module only use active high input so reverse the "sw" first
	 
	 assign sw_hi=!sw;
	 //debounce circuit
	debounce_explicit deb(
	.clk(clk),
	.rst_n(rst_n),
	.sw(sw_hi),
	.db_tick(r_edg)	
    );
	 
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			state_reg<=0;
			dig1<=0;
			dig0<=0;
		end
		else begin
			state_reg<=state_nxt;
			dig1<=dig1_nxt;
			dig0<=dig0_nxt;
		end
		
	end
	always @* begin
		state_nxt=state_reg;
		dig1_nxt=dig1;
		dig0_nxt=dig0;
		done_tick=0;
		case(state_reg)
			idle: if(r_edg) begin
						if(dig0!=9) dig0_nxt=dig0+1;
						else begin
							dig0_nxt=0;
							if(dig1!=4) dig1_nxt=dig1+1;
							else dig1_nxt=0;
						end	
						state_nxt=done;
					end
			done: begin
						done_tick=1;
						state_nxt=idle;
					end
		default: state_nxt=idle;
		endcase
	end


endmodule
module TEST(
	input clk,rst_n,
	input sw,
	output[7:0] seg_out,
	output[5:0] sel_out,
	output[9:0] signal
    );
	 localparam period=20_000; //in terms of microsec
	 
	 
	 localparam N=(period+1)*25;
	 reg[24:0] counter_reg=0,counter_nxt;
	 reg signal_reg=0,signal_nxt;
	 
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			counter_reg<=0;
			signal_reg<=0;
		end
		else begin
			counter_reg<=counter_nxt;
			signal_reg<=signal_nxt;
		end
	 end
	 
	 always @* begin
	 signal_nxt=signal_reg;
		if(counter_reg!=N-1) begin
			counter_nxt=counter_reg+1;
		end
		else begin
			counter_nxt=0;
			signal_nxt=!signal_reg;			
		end
	 end
	 master_controller m_master(
	.clk(clk),
	.rst_n(rst_n),
	.signal(signal_reg),
	.sw(sw),
	.seg_out(seg_out),
	.sel_out(sel_out),
	.done_tick()
    );
	 assign signal={10{signal_reg}};

endmodule
module adjust( //outputs the siz most significant bit with corresponding decimal
	input clk,rst_n,
	input start,
	input[3:0] dig0,dig1,dig2,dig3,dig4,dig5,dig6,dig7,dig8,dig9,dig10,
	output[4:0] in0,in1,in2,in3,in4,in5, //6 most significant digits 
	output reg done_tick
    );
	 //FSM state declarations
	 localparam[1:0] idle=2'd0,
							 op=2'd1,
							 done=2'd2;
	 reg[1:0] state_reg,state_nxt;
	 reg[4:0] dig0_reg,dig1_reg,dig2_reg,dig3_reg,dig4_reg,dig5_reg,dig6_reg,dig7_reg,dig8_reg,dig9_reg,dig10_reg;
	 reg[4:0] dig0_nxt,dig1_nxt,dig2_nxt,dig3_nxt,dig4_nxt,dig5_nxt,dig6_nxt,dig7_nxt,dig8_nxt,dig9_nxt,dig10_nxt;
	 //FSM register operations
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			state_reg<=idle;
			dig0_reg<=0;
			dig1_reg<=0;
			dig2_reg<=0;
			dig3_reg<=0;
			dig4_reg<=0;
			dig5_reg<=0;
			dig6_reg<=0;
			dig7_reg<=0;
			dig8_reg<=0;
			dig9_reg<=0;
			dig10_reg<=0;
		end
		else begin
			state_reg<=state_nxt;
			dig0_reg<=dig0_nxt;
			dig1_reg<=dig1_nxt;
			dig2_reg<=dig2_nxt;
			dig3_reg<=dig3_nxt;
			dig4_reg<=dig4_nxt;
			dig5_reg<=dig5_nxt;
			dig6_reg<=dig6_nxt;
			dig7_reg<=dig7_nxt;
			dig8_reg<=dig8_nxt;
			dig9_reg<=dig9_nxt;
			dig10_reg<=dig10_nxt;
		end
	 end
	 //FSM next-state declarations
	 always @* begin
		state_nxt=state_reg;
		dig0_nxt=dig0_reg;
		dig1_nxt=dig1_reg;
		dig2_nxt=dig2_reg;
		dig3_nxt=dig3_reg;
		dig4_nxt=dig4_reg;
		dig5_nxt=dig5_reg;
		dig6_nxt=dig6_reg;
		dig7_nxt=dig7_reg;
		dig8_nxt=dig8_reg;
		dig9_nxt=dig9_reg;
		dig10_nxt=dig10_reg;
		done_tick=0;
		case(state_reg) 
			   idle: if(start) begin
							dig0_nxt={1'b0,dig0};
							dig1_nxt={1'b0,dig1};
							dig2_nxt={1'b0,dig2};
							dig3_nxt={1'b0,dig3};
							dig4_nxt={1'b0,dig4};
							dig5_nxt={1'b1,dig5};//decimal digit before the last 5 digits
							dig6_nxt={1'b0,dig6};
							dig7_nxt={1'b0,dig7};
							dig8_nxt={1'b0,dig8};
							dig9_nxt={1'b0,dig9};
							dig10_nxt={1'b0,dig10};
							state_nxt=op;
						end
			     op: begin
							if(dig10_nxt==0) begin
								{dig0_nxt,dig1_nxt,dig2_nxt,dig3_nxt,dig4_nxt,dig5_nxt,dig6_nxt,dig7_nxt,dig8_nxt,dig9_nxt,dig10_nxt}=
									{dig0_nxt,dig1_nxt,dig2_nxt,dig3_nxt,dig4_nxt,dig5_nxt,dig6_nxt,dig7_nxt,dig8_nxt,dig9_nxt,dig10_nxt}>>5;
							end
							else state_nxt=done;
						end
			   done: begin
							done_tick=1;
							state_nxt=idle;
						end
			default: state_nxt=idle;
		endcase
		
	 end
	 assign in5=dig10_reg,
				in4=dig9_reg,
				in3=dig8_reg,
				in2=dig7_reg,
				in1=dig6_reg,
				in0=dig5_reg;
	 
	 


endmodule
module div
	#(parameter W=32, N=6) //W is the width of both dividend and divisor, N is the size of the register that stores binary value of W: N=log_2(W)+1
	(
	input clk,rst_n,
	input start,
	input [W-1:0] dividend,divisor,
	output[W-1:0] quotient,remainder,
	output reg ready,done_tick
    );
	

	 //FSM declarations
	 localparam[1:0] idle=2'd0,
							op=2'd1,
							last=2'd2,
							done=2'd3;
	 reg[1:0] state_reg,state_nxt;
	 reg[W-1:0] dividend_reg,divisor_reg,dividend_nxt,divisor_nxt;
	 reg[W-1:0] remainder_reg,remainder_nxt;
	 reg[N-1:0] n_reg,n_nxt;
	 reg[W-1:0] temp;
	 reg q;
	 
	 //FSM register operations
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			dividend_reg<=0;
			divisor_reg<=0;
			remainder_reg<=0;
			n_reg<=0;
			state_reg<=0;
		end
		else begin
			dividend_reg<=dividend_nxt;
			divisor_reg<=divisor_nxt;
			remainder_reg<=remainder_nxt;
			n_reg<=n_nxt;
			state_reg<=state_nxt;
		end
	 end
	 
	//FSM next-state logics
	always @* begin
		dividend_nxt=dividend_reg;
		divisor_nxt=divisor_reg;
		remainder_nxt=remainder_reg;
		state_nxt=state_reg;
		n_nxt=n_reg;
		ready=0;
		temp=0;
		done_tick=0;
		q=0;
		case(state_reg)
			idle: begin
						ready=1;
						if(start) begin
						dividend_nxt=dividend;
						divisor_nxt=divisor;
						remainder_nxt=0;
						n_nxt=W; //decrements until all dividend is used
						state_nxt=op;
						end
					end
			  op: begin
						if(remainder_reg>=divisor_reg) begin
							temp=remainder_reg-divisor_reg;
							q=1;
						end
						else begin 
							temp=remainder_reg;
							q=0;
						end
						{remainder_nxt,dividend_nxt}={temp[W-2:0],dividend_reg,q};
						n_nxt=n_reg-1;
						if(n_nxt==0) state_nxt=last;
					end
			last: begin
						if(remainder_reg>=divisor_reg) begin
							temp=remainder_reg-divisor_reg;
							q=1;
						end
						else begin 
							temp=remainder_reg;
							q=0;
						end
						dividend_nxt={dividend_reg[W-2:0],q};
						remainder_nxt=temp;
						state_nxt=done;
					end
			done: begin
						done_tick=1;
						state_nxt=idle;
					end
		default: state_nxt=idle;
		endcase
	end
	assign quotient=dividend_reg;
	assign remainder=remainder_reg;
	

endmodule
module master_controller(
	input clk,rst_n,
	input signal,sw,
	output[7:0] seg_out,
	output[5:0] sel_out,
	output reg done_tick
    );
	 //FSMstate declarations
	 localparam[2:0] idle=3'd0,
							pcounter=2'd1,
							div=3'd2,
							bin2bcd=3'd3,
							adjust=3'd4;
	 reg[2:0] state_reg,state_nxt;
	 reg start_pcounter,start_div,start_bin2bcd,start_adjust;
	 wire done_pcounter,done_div,done_bin2bcd,done_adjust;
	 wire[19:0] period;
	 wire[36:0] bin;
	 wire[3:0] dig0,dig1,dig2,dig3,dig4,dig5,dig6,dig7,dig8,dig9,dig10;
	 wire[4:0] in0,in1,in2,in3,in4,in5;
	 wire signal_hi;
	 reg sw_reg;
	 wire sw_edg;
	 
	 //FSM register operations
	 always @(posedge clk,negedge rst_n) begin
		 if(!rst_n) begin
				state_reg<=0;
				sw_reg<=0;
		 end
		 else begin
			state_reg<=state_nxt;
			sw_reg<=sw;
		 end
	 end
	 
	 //edge detector for "sw"
	 assign sw_edg= !sw && sw_reg; //sw is active low
	 
	 
	 //FSM next-state logics
	 always @* begin
		start_pcounter=0;
		start_div=0;
		start_bin2bcd=0;
		start_adjust=0;
		state_nxt=state_reg;
		done_tick=0;
		case(state_reg) 
			    idle: if(sw_edg) begin
							start_pcounter=1;
							state_nxt=pcounter;
						 end
			pcounter: if(done_pcounter) begin
							start_div=1;
							state_nxt=div;
						 end
				  div: if(done_div) begin
							start_bin2bcd=1;
							state_nxt=bin2bcd;
						 end
			 bin2bcd: if(done_bin2bcd) begin
							start_adjust=1;
							state_nxt=adjust;
						 end
			  adjust: if(done_adjust) begin
							state_nxt=idle;
							done_tick=1;
						 end
			 default: state_nxt=idle;
		endcase
	 end
	 assign signal_hi=!signal;
	 //module declarations
	 period_counter m0
	 (
		.clk(clk),
		.rst_n(rst_n),
		.start(start_pcounter),
		.signal(signal_hi),
		.ready(),
		.done_tick(done_pcounter),
		.period(period) //limit of 1.023 seconds of period
    );
	 
	 div #(.W(37),.N(6)) m1 //W is the width of both dividend and divisor, N is the size of the register that stores binary value of W: N=log_2(W)+1
	(
		.clk(clk),
		.rst_n(rst_n),
		.start(start_div),
		.dividend(37'd10**11),
		.divisor({17'd0,period}),
		.quotient(bin),
		.remainder(),
		.ready(),
		.done_tick(done_div)
    );
	 
	 bin2bcd m2
	 (
		.clk(clk),
		.rst_n(rst_n),
		.start(start_bin2bcd),
		.bin(bin),//11 digit max of {11{9}}
		.ready(),
		.done_tick(done_bin2bcd),
		.dig0(dig0),
		.dig1(dig1),
		.dig2(dig2),
		.dig3(dig3),
		.dig4(dig4),
		.dig5(dig5),
		.dig6(dig6),
		.dig7(dig7),
		.dig8(dig8),
		.dig9(dig9),
		.dig10(dig10)
    );
	 
	 adjust m3 //outputs the six most significant digits with corresponding decimal
	 ( 
		.clk(clk),
		.rst_n(rst_n),
		.start(start_adjust),
		.dig0(dig0),
		.dig1(dig1),
		.dig2(dig2),
		.dig3(dig3),
		.dig4(dig4),
		.dig5(dig5),
		.dig6(dig6),
		.dig7(dig7),
		.dig8(dig8),
		.dig9(dig9),
		.dig10(dig10),
		.in0(in0),
		.in1(in1),
		.in2(in2),
		.in3(in3),
		.in4(in4),
		.in5(in5), //6 most significant digits 
		.done_tick(done_adjust)
    );
	 
	LED_mux m4
	(
		.clk(clk),
		.rst(rst_n),
		.in0(in0),
		.in1(in1),
		.in2(in2),
		.in3(in3),
		.in4(in4),
		.in5(in5),
		.seg_out(seg_out),
		.sel_out(sel_out)
    );


endmodule
module period_counter(
		input clk,rst_n,
		input start,signal,
		output reg ready,done_tick,
		output [19:0] period //limit of 1.023 seconds of period
    );
	 
	 //FSM declarations
	 localparam[1:0] idle=2'd0,
							waiting=2'd1,
							op=2'd2,
							done=2'd3;
	 localparam N=50; // N/50Mhz=1us	
	 reg[1:0] state_reg,state_nxt;
	 reg[19:0] period_reg,period_nxt; // records period in terms of us
	 reg[5:0] tick_reg,tick_nxt; //ticks for every 1us (width of tick_reg is log_2(N))
	 reg signal_reg;
	 wire edg;
	 
	 //FSM register operations
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			state_reg<=idle;
			period_reg<=0;
			tick_reg<=0;
			signal_reg<=0;
		end
		else begin
			state_reg<=state_nxt;
			period_reg<=period_nxt;
			tick_reg<=tick_nxt;
			signal_reg<=signal;
		end
	 end
	 
	 //FSM next-state logic
	 always @* begin
		state_nxt=state_reg;
		period_nxt=period_reg;
		tick_nxt=tick_reg;
		ready=0;
		done_tick=0;
		case(state_reg) 
				idle: begin //rest
							ready=1;
							if(start) begin
								period_nxt=0;
								tick_nxt=0;
								state_nxt=waiting;
							end
						end
			waiting: begin //waiting for rising edge
							if(edg) //rising edge-detector
								state_nxt=op;
						end
				  op: begin //counting the number of ms then stop when rising edge is detected again
							if(edg) state_nxt=done;
							else begin
								if(tick_reg==N-1) begin
									tick_nxt=0;
									period_nxt=period_reg+1;
								end
								else tick_nxt=tick_reg+1;	
							end
						end
				done: begin
							done_tick=1;
							state_nxt=idle;
						end
			default: state_nxt=idle;
		endcase
	 end
	 
	 //rising-edge detector circuit
	 assign edg=signal && !signal_reg;
	 
	 
	 
	 //output combi-logic
	 assign period=period_reg;
	 
	 


endmodule
module cos_sine( 
	input clk,rst_n,
	input[9:0] x, //input has a 10-bit resolution(from 0 to 2pi)
	output[7:0] y_sine,y_cos //output has 8-bit resolution(from -1 to 1)
    );
	 
	reg[7:0] y_sine_q=0,y_sine_d,y_cos_q=0,y_cos_d;
	reg[7:0] x_sine_addr,x_cos_addr; //determines the address to be inserted in ROM
	wire[6:0] dout_sine,dout_cos;
	
	always  @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			y_sine_q<=0;
			y_cos_q<=0;
		end
		else begin
			y_sine_q<=y_sine_d;
			y_cos_q<=y_cos_d;
		end
	end
	
	//logic to obtain values of other quadrants
	always @* begin
		y_sine_d=y_sine_q;
		y_cos_d=y_cos_q; 
		
		case(x[9:8]) //logic for sine and cosine output , middle point of sine/cosine wave is at 2^7
			2'b00: begin	//first quadrant(0 to pi/2 for sine, and pi/2 to pi for cosine)    
						x_sine_addr=x[7:0]; 
						y_sine_d=dout_sine+2**7;
						
						x_cos_addr=255-x[7:0];
						y_cos_d=dout_cos+2**7;
					end
			2'b01: begin  //second quadrant(pi/2 to pi for sine, and pi to 3pi/2 for cosine)
						x_sine_addr=255-x[7:0]; 
						y_sine_d=dout_sine+2**7;
						
						x_cos_addr=x[7:0];
						y_cos_d=2**7-dout_cos;
					 end
			2'b10: begin  //third quadrant(pi to 3pi/2 for sine, and 3pi/2 to 2pi for cosine)
						x_sine_addr=x[7:0];
						y_sine_d=2**7-dout_sine;
						
						x_cos_addr=255-x[7:0];
						y_cos_d=2**7-dout_cos;
					 end
			2'b11: begin  //fourth quadrant(3pi/2 to 2pi for sine, and 2pi(0) to 5/2pi(pi/2) for cos))
						x_sine_addr=255-x[7:0];
						y_sine_d=2**7-dout_sine;
						
						x_cos_addr=x[7:0];
						y_cos_d=dout_cos+2**7;
					 end
		endcase

	end
	
	assign y_sine=y_sine_q;
	assign y_cos=y_cos_q;

	
	dual_port_rom m0
	(
	  .clka(clk), // input clka
	  .addra(x_sine_addr), // input [7 : 0] addra
	  .douta(dout_sine), // output [6 : 0] douta
	  .clkb(clk), // input clkb
	  .addrb(x_cos_addr), // input [7 : 0] addrb
	  .doutb(dout_cos) // output [6 : 0] doutb
	);


endmodule
module cos_sine_func_TB;

	// Inputs
	reg clk;
	reg rst_n;
	reg [9:0] x;

	// Outputs
	wire [7:0] y_sine,y_cos;
	reg[9:0] counter=0;

	// Instantiate the Unit Under Test (UUT)
	cos_sine uut (
		.clk(clk), 
		.rst_n(rst_n), 
		.x(x), 
		.y_sine(y_sine),
		.y_cos(y_cos)
	);
	always begin
		clk=0;
		#5;
		clk=1;
		#5;
	end
	always @(posedge clk) begin
		counter=counter+1'b1;
		x=counter;
	end

	initial begin
		rst_n = 1;
		@(negedge clk);
		wait(counter==0);
		@(negedge clk);
		wait(counter==0);
		@(negedge clk);
		wait(counter==0);
		@(negedge clk);
		wait(counter==0);
		@(negedge clk);
		wait(counter==0);
		@(negedge clk);
		wait(counter==0);
		@(negedge clk);
		wait(counter==0);
		@(negedge clk);
		wait(counter==0);
		$stop;
	end
      
endmodule
module dual_prioenc(
	input wire[11:0] in,
	output reg[3:0] first,second
    );
	 integer i;

	 always @(in) begin
	 first=4'd0;
	 second=4'd0;

	 
	 for(i=11;i>=0;i=i-1) begin  //use for-loop to locate the bit "1"
	 if(in[i] && !first) first=i+1;
	 else if(first && in[i] && !second) second=i+1; //if "first" already has a value,then the next bit of 1 will be the "second"
	 end
	 end
	
endmodule
module dual_pioenc_TB;

	// Inputs
	reg [11:0] in;

	// Outputs
	wire [3:0] first;
	wire [3:0] second;

	// Instantiate the Unit Under Test (UUT)
	dual_prioenc uut (
		.in(in), 
		.first(first), 
		.second(second)
	);

	initial begin
		// Initialize Inputs
		in = 0;

		// Wait 100 ns for global reset to finish
		#100;
		for(in=12'd0;in<12'd4095;in=in+1) #5;
		#100 $finish;
	end
	initial begin
	$display ("Input        First Second");
	$monitor ("%b %d     %d",in,first,second);
	end
      
endmodule
module dual_comparator(
	input[7:0] a,b,
	input mode,
	output signed agtb
    );
	 wire signed [7:0] a_signed,b_signed; ///storage for signed operation
	 wire[7:0] a_unsigned,b_unsigned; //storage for unsigned operation
	 
	 assign a_signed=a,
				 b_signed=b,
				 a_unsigned=a,
				 b_unsigned=b;
 
	 
	 assign agtb=mode? ((a_signed>b_signed)?1:0) : ((a_unsigned>b_unsigned)?1:0);
				


endmodule
module dual_comparator_TB;

	// Inputs
	reg [7:0] a;
	reg [7:0] b;
	reg mode;

	// Outputs
	wire agtb;

	// Instantiate the Unit Under Test (UUT)
	dual_comparator uut (
		.a(a), 
		.b(b), 
		.mode(mode), 
		.agtb(agtb)
	);

	initial begin
		
		a = 8'b0000_1111; //15 or 15
		b = 8'b1111_0000; //240 or -16
		mode = 0; //unsigned comparison
		#50; //agbt=0  since 15<240
		mode=1; //signed comparison
		#50; //agbt=1 since 15>-16
		$stop;

		

	end
      
endmodule
module barrel_shifter_8(  
		input wire[7:0] num,
		input wire[2:0] amt,
		input wire LR,
		output wire[7:0] real_out);
		wire[7:0] out_1,out_2;
		Rotate_R8 m0(num,amt,out_1);
		Rotate_L8 m1(num,amt,out_2);
		assign real_out=LR?out_2:out_1;   //MUX for left or right 8-bit shifter
endmodule
module Rotate_R8(
	input wire[7:0] num, 
	input wire[2:0] amt,
	output wire[7:0] out
    );
	 wire[7:0] s0,s1,s2;
	 assign s0=amt[0]?{num[0],num[7:1]}:num; //1 move
	 assign s1=amt[1]?{s0[1:0],s0[7:2]}:s0;  //2 moves
	 assign s2=amt[2]?{s1[3:0],s1[7:4]}:s1;  //4 moves
	 assign out=s2;
endmodule
module Rotate_L8(
	input wire[7:0] num, 
	input wire[2:0] amt,
	output wire[7:0] out
    );
	 wire[7:0] s0,s1,s2;
	 assign s0=amt[0]?{num[6:0],num[7]}:num; //1 move
	 assign s1=amt[1]?{s0[5:0],s0[7:6]}:s0;  //2 moves
	 assign s2=amt[2]?{s1[3:0],s1[7:4]}:s1;  //4 moves
	 assign out=s2;
endmodule
module Multi_Barrel_Shifter8x16x32x    //adjust param M and N for 8,16,or 32 bits
#( parameter N=32,
   parameter M=5)
	(  input wire[N-1:0] num,
		input wire[M-1:0] amt,
		input wire LR,
		output wire[N-1:0] out	
		 );
		 generate 
			if(N==8) barrel_shifter_8 m0(num,amt,LR,out);
			else if(N==16) barrel_shifter_16 m1(num,amt,LR,out);
			else if(N==32) barrel_shifter_32 m2(num,amt,LR,out);			
		 endgenerate

endmodule
module barrel_shifter_32(
		input wire[31:0] num,
		input wire[4:0] amt,
		input wire LR,
		output wire[31:0] real_out);
		wire[31:0] out_1,out_2;
		Rotate_R32 m0(num,amt,out_1);
		Rotate_L32 m1(num,amt,out_2);
		assign real_out=LR?out_2:out_1;  //MUX for left or right 16-bit shifter
endmodule
module Rotate_R32(
	input wire[31:0] num, 
	input wire[4:0] amt,
	output wire[31:0] out
    );
	 wire[31:0] s0,s1,s2,s3,s4;
	 assign s0=amt[0]?{num[0],num[31:1]}:num; //1 move
	 assign s1=amt[1]?{s0[1:0],s0[31:2]}:s0;   //2 moves
	 assign s2=amt[2]?{s1[3:0],s1[31:4]}:s1;   //4 moves
	 assign s3=amt[3]?{s2[7:0],s2[31:8]}:s2;   //8 moves
	 assign s4=amt[4]?{s2[15:0],s3[31:16]}:s3; //16 bits
	 assign out=s4;

endmodule
module Rotate_L32(
	input wire[31:0] num, 
	input wire[4:0] amt,
	output wire[31:0] out
    );
	 wire[31:0] s0,s1,s2,s3,s4;
	 assign s0=amt[0]?{num[30:0],num[31]}:num; //1 move
	 assign s1=amt[1]?{s0[29:0],s0[31:30]}:s0;  //2 moves
	 assign s2=amt[2]?{s1[27:0],s1[31:28]}:s1;  //4 moves
	 assign s3=amt[3]?{s2[23:0],s2[31:24]}:s2;  //8 moves
	 assign s4=amt[4]?{s3[15:0],s3[31:16]}:s3;  //16 moves
	 assign out=s4;


endmodule
module barrel_shifter_16(
		input wire[15:0] num,
		input wire[3:0] amt,
		input wire LR,
		output wire[15:0] real_out);
		wire[15:0] out_1,out_2;
		Rotate_R16 m0(num,amt,out_1);
		Rotate_L16 m1(num,amt,out_2);
		assign real_out=LR?out_2:out_1;  //MUX for left or right 16-bit shifter
endmodule
module Rotate_R16(
	input wire[15:0] num, 
	input wire[3:0] amt,
	output wire[15:0] out
    );
	 wire[15:0] s0,s1,s2,s3;
	 assign s0=amt[0]?{num[0],num[15:1]}:num; //1 move
	 assign s1=amt[1]?{s0[1:0],s0[15:2]}:s0;   //2 moves
	 assign s2=amt[2]?{s1[3:0],s1[15:4]}:s1;   //4 moves
	 assign s3=amt[3]?{s2[7:0],s2[15:8]}:s2;   //8 moves
	 assign out=s3;
	 
endmodule
module Rotate_L16(
	input wire[15:0] num, 
	input wire[3:0] amt,
	output wire[15:0] out
    );
	 wire[15:0] s0,s1,s2,s3;
	 assign s0=amt[0]?{num[14:0],num[15]}:num; //1 move
	 assign s1=amt[1]?{s0[13:0],s0[15:14]}:s0;  //2 moves
	 assign s2=amt[2]?{s1[11:0],s1[15:12]}:s1;  //4 moves
	 assign s3=amt[3]?{s2[7:0],s2[15:8]}:s2;  //8 moves
	 assign out=s3;

endmodule
module barreLshifter;

	// Inputs
	reg [15:0] num;
	reg [3:0] amt;
	reg LR;

	// Outputs
	wire [15:0] out;

	// Instantiate the Unit Under Test (UUT)
	Multi_Barrel_Shifter8x16x32x #(.N(16),.M(4)) uut (
		.num(num), 
		.amt(amt), 
		.LR(LR), 
		.out(out)
	);

	initial begin
		// Initialize Inputs
			num = 0;
			amt = 0;
			LR = 0; //0=right, 1=left

			#100
			#10 num=16'b11111111_00000000;
			
			//Rotate right bit by bit
			$display("ROTATE RIGHT");
			for(amt=4'd0;amt<4'b1111;amt=amt+1) begin
				#5 $display("%b",out);
			end
			#5 $display("%b",out);
			
			
			
			//Rotate left bit by bit
			$display(" ");
			$display("ROTATE LEFT");
			LR=1;
			for(amt=4'd0;amt<4'b1111;amt=amt+1) begin
				#5 $display("%b",out);
			end
			#5 $display("%b",out);
			
		#100 $finish;
		end
			
		
      
endmodule
module fifo_test_vector #(parameter W=4,B=8)
	(
		output reg clk,rst_n,
		output reg wr,rd,
		output reg[B-1:0] wr_data
    );
	 always begin
		clk=0;
		#5;
		clk=1;
		#5;
	 end
	 
	 initial begin
		initialize();
		write("A"); ////0
		write("B"); ////1
		write("C"); ////2
		write("D"); ////3
		write("E"); ////4
		write("F"); ////5
		write("G"); ////6
		write("H"); ////7
		read(10); //read(from A to H to x) until empty
		write("I"); ////8
		write("J"); ////9
		write("K"); ////10
		write("L"); ////11
		write("M"); ////12
		write("N"); ////13
		write("O"); ////14
		write("P"); ////15
		write("Q"); ////0
		write("R"); ////1
		write("S"); ////2
		write("T"); ////3
		write("U"); ////4
		write("V"); ////5
		write("W"); ////6
		write("X"); ////7 
		write("Y"); //full
		write("Z"); //full
		read(20); //read(from I to X to I) until empty
		write(1);
		write(2);
		write(3);
		write(4);
		write(5);
		write(6);
		write(7);
		write(8); 
		rd_wr(9); //1
		rd_wr(10); //2
		rd_wr(11); //3
		rd_wr(12); //4
		rd_wr(13); //5
		rd_wr(14); //6
		rd_wr(15); //7
		rd_wr(16); //8
		rd_wr(17); //9
		rd_wr(18); //10
		rd_wr(20); //11
		rd_wr(21); //12
		rd_wr(22); //13
		rd_wr(23); //14
		rd_wr(24); //15
		rd_wr(25); //16
		rd_wr(26); //17
		rd_wr(27); //18
		$stop;
	 end
	 
	 task initialize(); begin
		@(negedge clk);
		rst_n=1;
		wr=0;
		rd=0;
		wr_data=0;
	 end
	 endtask

	 task read(input integer i); begin
		@(negedge clk);
		rd=1;
		repeat(i) @(negedge clk);
		rd=0;
	 end
	 endtask
	 
	 task write(input integer data); begin
		@(negedge clk);
		wr=1;
		wr_data=data;
		@(negedge clk);
		wr=0;
	 end
	 endtask
	
	task rd_wr(input integer data); begin
		@(negedge clk);
		wr=1; 
		rd=1;
		wr_data=data;
		@(negedge clk);
		wr=0; rd=0;
	 end
	 endtask

endmodule
module fifo
	#(parameter W=11,B=8) //W for address width , B for data bits  (2k by 8 fifo and uses block RAM for storage)
	(
	input clk,rst_n,
	input wr,rd,
	input[B-1:0] wr_data,
	output[B-1:0] rd_data,
	output reg full,empty	
    );
	 initial begin
		full=0;
		empty=1;
	 end
	 
	 reg[W-1:0] rd_ptr_q=0,rd_ptr_d; 
	 reg[W-1:0] wr_ptr_q=0,wr_ptr_d;
	 reg full_d,empty_d;
	 reg we; //write enable signal for the block ram
	 
	 
	 //assign rd_data=array_reg[rd_ptr];
	 
	 //register operation
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			rd_ptr_q<=0;
			wr_ptr_q<=0;
			wr_ptr_q<=0;
			full<=0;
			empty<=1;
		end
		else begin
			rd_ptr_q<=rd_ptr_d;
			wr_ptr_q<=wr_ptr_d;
			full<=full_d;
			empty<=empty_d;
		end
	 end
	 
	 
	 always @* begin
	   rd_ptr_d=rd_ptr_q;
		wr_ptr_d=wr_ptr_q;
	   full_d=full;
	   empty_d=empty;
		we=0;
			case({rd,wr})
				2'b01: if(!full) begin //advance the write pointer if not yet full
							we=1;
							wr_ptr_d=wr_ptr_q+1'b1;
							empty_d=0;
							full_d=(wr_ptr_d==rd_ptr_q);
						 end
				2'b10: if(!empty) begin //advance the read pointer if not yet empty(notice that read is synchronous but the operation is immediate, 
							rd_ptr_d=rd_ptr_q+1'b1;          //read data changes instantly as read pointer changes
							full_d=0;
							empty_d=(rd_ptr_d==wr_ptr_q);
						 end
				2'b11: if(!empty && !full) begin  //read and write simultaneous if and only if its not empty and not full
								we=1;                          
								rd_ptr_d=rd_ptr_q+1'b1;
								wr_ptr_d=wr_ptr_q+1'b1;
						 end
			endcase
	 end
	 
	 dual_port_syn
	 #(.ADDR_WIDTH(W),.DATA_WIDTH(B)) m0
		(
			.clk(clk),
			.we(we),
			.din(wr_data),
			.addr_a(wr_ptr_q),
			.addr_b(rd_ptr_d),
			.dout(rd_data)
		);
endmodule
module dual_port_syn //syncrhonous dual port ram(uses block ram)
	#(
		parameter ADDR_WIDTH=11, //12k by 8 RAM (16k block RAM)
					 DATA_WIDTH=8
	)
	(
		input clk,
		input we,
		input[DATA_WIDTH-1:0] din,
		input[ADDR_WIDTH-1:0] addr_a,addr_b, //addr_a for writing address, addr_b for reading address
		output[DATA_WIDTH-1:0] dout
	);
	reg[DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];
	reg[ADDR_WIDTH-1:0]addr_b_q;
	
	always @(posedge clk) begin
		if(we) ram[addr_a]=din;
		addr_b_q<=addr_b;
	end
	assign dout=ram[addr_b_q];
	
endmodule
module fifo_TB;

	// Inputs
	wire clk;
	wire rst_n;
	wire wr;
	wire rd;
	wire [7:0] wr_data;

	// Outputs
	wire [7:0] rd_data;
	wire full;
	wire empty;

	// Instantiate the Unit Under Test (UUT)
	fifo #(.W(4),.B(8)) uut1
	(
		.clk(clk), 
		.rst_n(rst_n), 
		.wr(wr), 
		.rd(rd), 
		.wr_data(wr_data), 
		.rd_data(rd_data), 
		.full(full), 
		.empty(empty)
	);

	fifo_test_vector #(.W(4),.B(8)) uut2
	(
		.clk(clk),
		.rst_n(rst_n),
		.wr(wr),
		.rd(rd),
		.wr_data(wr_data)
    );
	 
	 fifo_monitor	#(.W(4),.B(8)) uut3
	(
	.clk(clk),
	.rd(rd),
	.rd_data(rd_data)
    );


      
endmodule
module fifo_monitor #(parameter W=4,B=8)
	(
	input clk,
	input rd,
	input[B-1:0] rd_data,
	input full,empty
    );

	 reg[7:0] array_reg[1024:0];
	 integer i;
	 reg [39:0] msg;
	 
	 initial begin	
		$display("Output Desired");
		i=0;
		array_reg[0]="A";
		array_reg[1]="B";
		array_reg[2]="C";
		array_reg[3]="D";
		array_reg[4]="E";
		array_reg[5]="F";
		array_reg[6]="G";
		array_reg[7]="H";
		//array_reg[8];
		//array_reg[9];
		array_reg[10]="I";
		array_reg[11]="J";
		array_reg[12]="K";
		array_reg[13]="L";
		array_reg[14]="M";
		array_reg[15]="N";
		array_reg[16]="O";
		array_reg[17]="P";
		array_reg[18]="Q";
		array_reg[19]="R";
		array_reg[20]="S";
		array_reg[21]="T";
		array_reg[22]="U";
		array_reg[23]="V";
		array_reg[24]="W";
		array_reg[25]="X";
		array_reg[26]="I";
		array_reg[27]="I";
		array_reg[28]="I";
		array_reg[29]="I";
		array_reg[30]=1;
		array_reg[31]=2;
		array_reg[32]=3;
		array_reg[33]=4;
		array_reg[34]=5;
		array_reg[35]=6;
		array_reg[36]=7;
		array_reg[37]=8;
		array_reg[38]=9;
		array_reg[39]=10;
		array_reg[40]=11;
		array_reg[41]=12;
		array_reg[42]=13;
		array_reg[43]=14;
		array_reg[44]=15;
		array_reg[45]=16;
		array_reg[46]=17;
		array_reg[47]=18;
		array_reg[48]=19;
		array_reg[49]=20;
	 end
	 

	 
	 always @(posedge clk) begin
			if(rd) begin
				i<=i+1;
			end
			if(array_reg[i]==rd_data) begin
				msg=" ";
			end
			else msg="ERROR";
		
			$display("%h %h %s",rd_data,array_reg[i],msg);
			
	 end


endmodule
module LED_mux
	#(parameter N=19) //last 3 bits will be used as output. Frequency=50MHz/(2^(N-3)). So N=19 will have 763Hz
	(
	input clk,rst,
	input[5:0] in0,in1,in2,in3,in4,in5, //format: {dp,char[4:0]} , dp is active high
	output reg[7:0] seg_out,
	output reg[5:0] sel_out
    );
	 
	 reg[N-1:0] r_reg=0;
	 reg[5:0] hex_out=0;
	 wire[N-1:0] r_nxt;
	 wire[2:0] out_counter; //last 3 bits to be used as output signal
	 
	 
	 //N-bit counter
	 always @(posedge clk,negedge rst)
	 if(!rst) r_reg<=0;
	 else r_reg<=r_nxt;
	 
	 assign r_nxt=(r_reg=={3'd5,{(N-3){1'b1}}})?19'd0:r_reg+1'b1; //last 3 bits counts from 0 to 5(6 turns) then wraps around
	 assign out_counter=r_reg[N-1:N-3];
	 
	 
	 //sel_out output logic
	 always @(out_counter) begin
		 sel_out=6'b111_111;    //active low
		 sel_out[out_counter]=1'b0;
	 end
	  
	 //hex_out output logic
	 always @* begin
		 hex_out=0;
			 casez(out_counter)
			 3'b000: hex_out=in0;
			 3'b001: hex_out=in1;
			 3'b010: hex_out=in2;
			 3'b011: hex_out=in3;
			 3'b100: hex_out=in4;
			 3'b101: hex_out=in5;
			 endcase
	 end
	 	 
	 //hex-to-seg decoder
	 always @* begin
		 seg_out=0;
			 case(hex_out[4:0])
			 5'd0: seg_out[6:0]=7'b0000_001;
			 5'd1: seg_out[6:0]=7'b1001_111;
			 5'd2: seg_out[6:0]=7'b0010_010;
			 5'd3: seg_out[6:0]=7'b0000_110;
			 5'd4: seg_out[6:0]=7'b1001_100;
			 5'd5: seg_out[6:0]=7'b0100_100;
			 5'd6: seg_out[6:0]=7'b0100_000;
			 5'd7: seg_out[6:0]=7'b0001_111;
			 5'd8: seg_out[6:0]=7'b0000_000;
			 5'd9: seg_out[6:0]=7'b0001_100;
	  /*A*/5'd10: seg_out[6:0]=7'b0001_000; 
	  /*b*/5'd11: seg_out[6:0]=7'b1100_000;
	  /*C*/5'd12: seg_out[6:0]=7'b0110_001;
	  /*d*/5'd13: seg_out[6:0]=7'b1000_010;
	  /*E*/5'd14: seg_out[6:0]=7'b0110_000;
	  /*F*/5'd15: seg_out[6:0]=7'b0111_000;
	  /*G*/5'd16: seg_out[6:0]=7'b0100_000;
	  /*H*/5'd17: seg_out[6:0]=7'b1001_000;
	  /*I*/5'd18: seg_out[6:0]=7'b1111_001;
	  /*J*/5'd19: seg_out[6:0]=7'b1000_011;
	  /*L*/5'd20: seg_out[6:0]=7'b1110_001;
	  /*N*/5'd21: seg_out[6:0]=7'b0001_001;
	  /*O*/5'd22: seg_out[6:0]=7'b0000_001;
	  /*P*/5'd23: seg_out[6:0]=7'b0011_000; 
	  /*R*/5'd24: seg_out[6:0]=7'b0001_000;
	  /*S*/5'd25: seg_out[6:0]=7'b0100_100;
	  /*U*/5'd26: seg_out[6:0]=7'b1000_001;
	  /*y*/5'd27: seg_out[6:0]=7'b1000_100;
	  /*Z*/5'd28: seg_out[6:0]=7'b0010_010; 
	/*OFF*/5'd29: seg_out[6:0]=7'b1111_111; //decimal 30 to 31 will be alloted for future use
	  /*Z*/5'd30: seg_out[6:0]=7'b1111_110; 

			 endcase
		 seg_out[7]=!hex_out[5]; //active high decimal
	 end

endmodule
module baud_generator
	(
	input clk,rst_n,
	input[11:0] baud_dvsr, //2605 for 12000baud , 1303 for 2400baud , 652 for 4800baud , 326 for 9600baud , 162 for 19200 , 27 for 115200
	output reg s_tick
    );
	 reg[11:0] counter=0;
	 reg[11:0] baud_dvsr_reg;//use to store the last value of dvsr input. If the dvsr changes, the counter resets (with this, there will be no delay)
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			counter<=0;
			baud_dvsr_reg<=0;
		end
		else begin
			s_tick=0;
			if(baud_dvsr_reg!=baud_dvsr) counter<=0;
			else if(counter==baud_dvsr_reg-1) begin
				s_tick=1;
				counter<=0;
			end
			else begin
				counter<=counter+1;
			end
			baud_dvsr_reg<=baud_dvsr;
		end
	 end
	 
endmodule
module uart_rx  
	(
		input clk,rst_n,
		input rx,
		input s_tick,
		input[3:0] databits, //either 8 or 7 databits
		input[5:0] stopbits, //either 16 or 32 ticks for 1 and 2 stopbits,respectively
		input [1:0] paritybit, //0-no parity, 1=odd parity , 2=even parity
		output reg rx_done_tick,
		output[7:0] dout,
		output reg parity_error, //high if there is error
		output reg frame_error //high if there is error
    );
	 //FSM state declarations
	 localparam[2:0] idle=3'd0,
							start=3'd1,
							data=3'd2,
							parity=3'd3,
							stop=3'd4;
	 reg[2:0] state_reg,state_nxt;
	 reg[5:0] s_reg,s_nxt; //check if number of ticks is 7(middle of start bit), or 15(middle of a data bit)
	 reg[2:0] n_reg,n_nxt; //checks how many data bits is already passed(value is 7 for last bit)
	 reg[7:0] b_reg,b_nxt; //stores 8-bit binary value of received data bits
	 reg parity_error_nxt,frame_error_nxt;
	 //FSM register operation
	 always @(posedge clk,negedge rst_n) begin
		if(!rst_n) begin
			state_reg<=idle;
			s_reg<=0;
			n_reg<=0;
			b_reg<=0;
			parity_error<=0;
			frame_error<=0;
		end
		else begin
			state_reg<=state_nxt;
			s_reg<=s_nxt;
			n_reg<=n_nxt;
			b_reg<=b_nxt;	
			parity_error<=parity_error_nxt;
			frame_error<=frame_error_nxt;
		end
	 end
	 //FSM next-state logic
	 always @* begin
		state_nxt=state_reg;
		s_nxt=s_reg;
		n_nxt=n_reg;
		b_nxt=b_reg;
		rx_done_tick=0;
		parity_error_nxt=parity_error;
		frame_error_nxt=frame_error;
		case(state_reg)
			 idle: if(rx==0) begin //wait for start bit(rx of zero)
						s_nxt=0;
						state_nxt=start;
					 end						
			start: if(s_tick==1) begin //wait for middle of start bit
						if(s_reg==7) begin
							s_nxt=0;
							n_nxt=0;
							state_nxt=data;
						end
						else s_nxt=s_reg+1;
					 end
		    data: if(s_tick==1) begin //wait to pass all middle points of every data bits
						if(s_reg==15) begin
							b_nxt={rx,b_reg[7:1]};
							s_nxt=0;
							if(n_reg==databits-1) state_nxt=parity;
							else n_nxt=n_reg+1;
						end
						else s_nxt=s_reg+1;
					 end
			parity: if(paritybit==0) state_nxt=stop; //no parity
			
						else  begin  //odd or even parity
							if(s_tick==1) begin 
								if(s_reg==15) begin //go to middle point of parity bit
									parity_error_nxt=(paritybit==1)? !{^{dout,rx}} : {^{dout,rx}} ; 
									s_nxt=0;
									state_nxt=stop;
								end
								else s_nxt=s_reg+1;
							end
						end
			
			 stop: if(s_tick==1) begin  //wait to pass the required stop bits
						if(s_reg==stopbits-1) begin
							frame_error_nxt=!rx;
							rx_done_tick=1;
							state_nxt=idle;
						end
  						else s_nxt=s_reg+1;
					 end	
		 default: state_nxt=idle;
		endcase
	 end
	 assign dout=(databits==8)? b_reg : (b_reg>>1);
endmodule
module uart_test(
	input clk,rst_n,
	input btn0,btn1,btn2,
	input rx,
	output tx,
	output[7:0] seg_out,
	output[5:0] sel_out,
	output[3:0] led
    );
	 
	 wire btn2_tick;
	 wire[7:0] wr_data,rd_data;
	 wire rx_empty,tx_empty;
	 
	 top_module m0
	 (
		.clk(clk),
		.rst_n(rst_n),
		.btn0(btn0),
		.btn1(btn1),	//btn0=enter key , btn1=activate autobaud-parity detector 
		.rx(rx), 
		.rd_uart(btn2_tick),
		.wr_uart(btn2_tick),
		.wr_data(wr_data),
		.rd_data(rd_data),
		.tx(tx),
		.rx_empty(rx_empty),
		.tx_empty(tx_empty),
		.seg_out(seg_out),
		.sel_out(sel_out)
    );
	 debounce_explicit m1
	(
		.clk(clk),
		.rst_n(rst_n),
		.sw({!btn2}),
		.db_level(),
		.db_tick(btn2_tick)
    );
	 
	 assign wr_data=rd_data+1;
	 assign led={4{rx_empty}};
	 

endmodule