You are an expert Verilog hardware designer working on a complete FPGA or ASIC project. You are given the full source code of a Verilog project. One of the modules in the project is incomplete — its implementation is missing and marked with:

// >>> Module Implementation Begin

// <<< Module Implementation End

Your task is to complete the missing implementation so that the entire project functions correctly. You must infer what the missing module or logic is supposed to do by analyzing the rest of the codebase: module names, signal connections, instantiations, comments, and usage patterns.

Follow these rules:

1. Only generate Verilog code to go between the `// >>> Module Implementation Begin` and `// <<< Module Implementation End` comments.
2. Use Verilog-2001 syntax. Ensure the code is synthesizable.
3. Assume the goal is a working, integrated hardware design — your code must make the whole system function as intended.
4. Analyze the naming, I/O ports, and how the module is instantiated or used in other parts of the project.
5. Implement correct behavior based on design context. Do not guess randomly — reason it out.
6. Avoid vendor-specific features unless explicitly required.
7. Do not output comments, explanation, or anything outside the required code region unless explicitly asked.

Your output should contain **only the Verilog code** that fits inside the marked region.

/*
 * Copyright (c) 2024 Bhavuk (Github: Bhavuk-HDL)
 * SPDX-License-Identifier: Apache-2.0
 */

`default_nettype none

module tt_um_comm_ic_bhavuk (
	input  wire [7:0] ui_in,    // Dedicated inputs
	output wire [7:0] uo_out,   // Dedicated outputs
	input  wire [7:0] uio_in,   // IOs: Input path
	output wire [7:0] uio_out,  // IOs: Output path
	output wire [7:0] uio_oe,   // IOs: Enable path (active high: 0=input, 1=output)
	input  wire       ena,      // always 1 when the design is powered, so you can ignore it
	input  wire       clk,      // clock
	input  wire       rst_n     // reset_n - low to reset
	);
// >>> Module Implementation Begin

// <<< Module Implementation End
endmodule




////////////////////////////////////////////////////////////////////////////////
// Top module for the Comm_IC project. Submitted for the TinyTapeout8 (TT8).  //
// Designed by:      Bhavuk                                                   //
// Github ID:        Bhavuk-HDL                                               //
// Date of creation: 04-Sept-2024                                             //
// Code version:     V01                                                      //
/******************************************************************************/
// This project combines three different communication protocols, namely:     //
// 1. UART: Universal Aynchronous Receiver Transmitter                        //
// 2. SPI:  Serial Peripheral Interface                                       //
// 3. I2C:  Inter Integrated Circuit                                          //
/******************************************************************************/
// To communicate with this project, there is 'data_en' signal.               //
// data_en should be low by default. When it gets high e receive 4 bit data   //
// from data_in (MSB first) based on the clk rising edge.                     //
/******************************************************************************/
// First 4-bits of data bits will decide the comm. protocol and read/write.   //
// data_in = 4'bab_cd:                                                        //
// ab: 00-> Read                                                              //
// ab: 11-> Write                                                             //
// cd: 00-> UART                                                              //
// cd: 01-> SPI                                                               //
// cd: 10-> I2C                                                               //
// ab: 10-> Use previous settings: valid only in 'write mode'.                //
/******************************************************************************/
// Second 4-bits will have two directions: 'read mode' or 'write mode'.       //
// Read mode: data will be read from the comm protocol and interrupt will be  //
// set to '0'.                                                                //
// Write mode: if cd was set to '11' in the last cycle, we use previous       //
// settings for the comunication. Otherwise we use fresh settings.            //
// Next few 4-bit sequences will be used to send the data to resp. module.    //
////////////////////////////////////////////////////////////////////////////////

`default_nettype none

// Main module
module comm_ic (
	// Clk and Reset
	input	wire			clk,		// Clock input
	input	wire			reset_n,	// Reset input; low enabled
	
	// IOs
	// Comm. signals
	// UART
	input	wire			UART_RX,	// Data in pin
	output	wire			UART_TX,	// Data out pin
	
	// SPI
	output	wire			SEN,		// Serial Interface Enable; Active low
	output	wire			SCLK,		// Serial Interface Clock
	output	wire			MOSI,		// Serial Interface Data Out
	input	wire			MISO,		// Serial Interface Data In
	
	// I2C
	output	wire			SCL,		// Serial Clock
	output	wire			SDA_op,		// Serial Data Out;			inout[0]
	input	wire			SDA_in,		// Serial Data In;			inout[0]
	output	wire			SDA_op_en,	// SDA Mode Select
	
	// Interrupts out
	output	wire			new_uart,	// New data from UART Rx
	output	wire			busy_uart,	// Busy from UART Tx
	output	wire			busy_spi,	// Busy from SPI
	output	wire			busy_i2c,	// Busy from I2C
	output	wire			error_i2c,	// Error I2C
	
	// Data load in comm_ic
	input	wire	[3:0]	data_in,	// Data in for IC;			inout[4:1]
	output	reg		[3:0]	data_out,	// Data out from IC;		inout[4:1]
	output	reg		[3:0]	data_op_en,	// Data out mode select
	input	wire			data_en		// Enable the data transmission
	);
	
	// Local parameters
	localparam DATA_BITS = 16;
	localparam CLK_RATIO = 8;
	
	// Internal registers and wires
	reg		[1:0]			comm_sel;
	reg		[1:0]			send_cnt;
	
	wire	[7:0]			rx_data;
	reg						rx_ack;
	wire					rx_new;
	wire					rx_error;
	reg						parity_en;
	reg						parity_odd;
	reg						tx_new;
	reg		[7:0]			tx_data;
	reg		[7:0]			uart_clk_cnt;
	reg						uart_enable;
	reg						uart_setting;
	
	wire	[15:0]			spi_data_out;
	reg						spi_bits16;
	reg		[15:0]			spi_data_in;
	reg						spi_start;
	reg		[1:0]			spi_mode;
	reg		[7:0]			spi_clk_cnt;
	
	wire	[15:0]			i2c_data_out;
	reg						i2c_bits16;
	reg						i2c_start;
	reg		[15:0]			i2c_data_in;
	reg						i2c_write_n;
	reg		[6:0]			i2c_address;
	reg		[7:0]			i2c_clk_cnt;
	reg						i2c_addr_en;
	
	// Module declarations
	spi #(.DATA_BITS(DATA_BITS), .CLK_RATIO(CLK_RATIO))
	spi0 (.clk(clk), .reset_n(reset_n), .start(spi_start), .bits16(spi_bits16),
		 .mode(spi_mode), .data_in(spi_data_in), .clk_cnt(spi_clk_cnt),
		 .data_out(spi_data_out), .busy(busy_spi),
		 .SEN(SEN), .SCLK(SCLK), .MOSI(MOSI), .MISO(MISO));
	
	i2c  #(.DATA_BITS(DATA_BITS), .CLK_RATIO(CLK_RATIO))
	i2c0 (.clk(clk), .reset_n(reset_n), .start(i2c_start), .bits16(i2c_bits16),
		 .write_n(i2c_write_n), .address(i2c_address), .data_in(i2c_data_in),
		 .clk_cnt(i2c_clk_cnt), .data_out(i2c_data_out), .busy(busy_i2c), .error(error_i2c),
		 .SCL(SCL), .SDA_op(SDA_op), .SDA_in(SDA_in), .op_en(SDA_op_en));
	
	uart #(.CLK_RATIO(CLK_RATIO))
	uart0 (.clk(clk), .reset_n(reset_n), .enable(uart_enable), .setting(uart_setting),
		  .parity_en(parity_en), .parity_odd(parity_odd), .tx_new(tx_new),
		  .rx_ack(rx_ack), .tx_busy(busy_uart), .rx_new(rx_new), .rx_error(rx_error),
		  .clk_cnt(uart_clk_cnt), .tx_data(tx_data), .rx_data(rx_data),
		  .UART_RX(UART_RX), .UART_TX(UART_TX));
	
	//	State machine
	reg	[1:0]	curr_st;
	localparam	[1:0]
		idle		= 2'b00,
		read_mode	= 2'b01,
		write_mode0	= 2'b10,
		write_mode1	= 2'b11;
	
	// Combinational logic
	assign new_uart = rx_new & (~rx_error);
	
	// Sequential logic
	always @(posedge clk) begin
		if (~reset_n) begin
			comm_sel			<= 2'b00;
			data_op_en			<= 4'b0000;		// Input enabled
			send_cnt			<= 2'd0;
			
			rx_ack				<= 1'b0;
			parity_en			<= 1'b0;
			parity_odd			<= 1'b0;
			tx_new				<= 1'b0;
			tx_data				<= 8'd0;
			uart_clk_cnt		<= 8'd0;
			uart_enable			<= 1'b0;
			uart_setting		<= 1'b0;
			
			spi_bits16			<= 1'b0;
			spi_data_in			<= 16'd0;
			spi_start			<= 1'b1;
			spi_mode			<= 2'd0;
			spi_clk_cnt			<= 8'd0;
			
			i2c_start			<= 1'b0;
			i2c_data_in			<= 16'd0;
			i2c_write_n			<= 1'b0;
			i2c_address			<= 7'd0;
			i2c_clk_cnt			<= 8'd0;
			i2c_bits16			<= 1'b0;
			i2c_addr_en			<= 1'b0;
			
			curr_st				<= idle;
		end
		else begin
			case(curr_st)
				// Idle
				idle: begin
					comm_sel			<= 2'b00;
					data_op_en			<= 4'b0000;		// Input enabled
					send_cnt			<= 2'd1;
					send_cnt			<= 2'd0;
					if (busy_uart) begin
						tx_new			<= 1'b0;
						uart_setting	<= 1'b0;
					end
					if (busy_spi) begin
						spi_start		<= 1'b0;
					end
					if (busy_i2c) begin
						i2c_start		<= 1'b0;
					end
					
					if (data_en) begin
						comm_sel		<= data_in[1:0];
						
						if (data_in[3:2] == 2'b00) begin	// Data out state
							data_op_en	<= 4'b1111;		// Output enabled
							send_cnt	<= 2'd1;
							if (data_in[1:0] == 2'b01) begin	// SPI
								if (spi_bits16)
									send_cnt	<= 2'd3;
							end
							if (data_in[1:0] == 2'b10) begin	// I2C
								if (i2c_bits16)
									send_cnt	<= 2'd3;
							end
							
							curr_st		<= read_mode;
						end
						if (data_in[3:2] == 2'b11) begin	// Data in state; new settings
							data_op_en	<= 4'b0000;		// Input enabled
							send_cnt	<= 2'd2;
							curr_st		<= write_mode1;
						end
						if (data_in[3:2] == 2'b10) begin	// Data in state; old settings
							data_op_en	<= 4'b0000;		// Input enabled
							send_cnt	<= 2'd1;
							if (data_in[1:0] == 2'b01) begin	// SPI
								if (spi_bits16)
									send_cnt	<= 2'd3;
							end
							if (data_in[1:0] == 2'b10) begin	// I2C
								i2c_addr_en		<= 1'b1;
								//if (i2c_bits16)
								//	send_cnt	<= 2'd3;
							end
							curr_st		<= write_mode0;
						end
					end
				end
				
				// Read mode
				read_mode: begin
					if (comm_sel == 2'b00) begin	// UART
						case(send_cnt)
							2'd1: begin
								data_out	<= rx_data[7:4];
								send_cnt	<= 2'd0;
							end
							2'd0: begin
								data_out	<= rx_data[3:0];
								rx_ack		<= 1'b1;
								
								curr_st		<= idle;
							end
							default: curr_st		<= idle;
						endcase
					end
					if (comm_sel == 2'b01) begin	// SPI
						case(send_cnt)
							2'd3: begin
								data_out	<= spi_data_out[15:12];
								send_cnt	<= 2'd2;
							end
							2'd2: begin
								data_out	<= spi_data_out[11:8];
								send_cnt	<= 2'd1;
							end
							2'd1: begin
								data_out	<= spi_data_out[7:4];
								send_cnt	<= 2'd0;
							end
							2'd0: begin
								data_out	<= spi_data_out[3:0];
								curr_st		<= idle;
							end
						endcase
					end
					if (comm_sel == 2'b10) begin	// I2C
						case(send_cnt)
							2'd3: begin
								data_out	<= i2c_data_out[15:12];
								send_cnt	<= 2'd2;
							end
							2'd2: begin
								data_out	<= i2c_data_out[11:8];
								send_cnt	<= 2'd1;
							end
							2'd1: begin
								data_out	<= i2c_data_out[7:4];
								send_cnt	<= 2'd0;
							end
							2'd0: begin
								data_out	<= i2c_data_out[3:0];
								curr_st		<= idle;
							end
						endcase
					end
				end
				
				// Write mode: previous settings
				write_mode0: begin		// Use previous settings
					if (comm_sel == 2'b00) begin	// UART
						uart_enable					<= 1'b1;
						case(send_cnt)
							2'd1: begin
								tx_data[7:4]		<= data_in;
								send_cnt			<= 2'd0;
							end
							2'd0: begin
								tx_data[3:0]		<= data_in;
								tx_new				<= 1'b1;
								curr_st				<= idle;
							end
							default: curr_st		<= idle;
						endcase
					end
					if (comm_sel == 2'b01) begin	// SPI
						case(send_cnt)
							2'd3: begin
								spi_data_in[15:12]	<= data_in;
								send_cnt			<= 2'd2;
							end
							2'd2: begin
								spi_data_in[11:8]	<= data_in;
								send_cnt			<= 2'd1;
							end
							2'd1: begin
								spi_data_in[7:4]	<= data_in;
								send_cnt			<= 2'd0;
							end
							2'd0: begin
								spi_data_in[3:0]	<= data_in;
								spi_start			<= 1'b1;
								curr_st				<= idle;
							end
						endcase
					end
					if (comm_sel == 2'b10) begin	// I2C
						if (i2c_addr_en) begin
							case(send_cnt)
								2'd1: begin
									i2c_address[6:3]	<= data_in;
									send_cnt			<= 2'd0;
								end
								2'd0: begin
									i2c_address[2:0]	<= data_in[3:1];
									i2c_addr_en			<= 1'b0;
									if (i2c_bits16)
										send_cnt	<= 2'd3;
									else
										send_cnt	<= 2'd1;
									send_cnt			<= 2'd0;
								end
								default: curr_st		<= idle;
							endcase
						end
						else begin
							case(send_cnt)
								2'd3: begin
									i2c_data_in[15:12]	<= data_in;
									send_cnt			<= 2'd2;
								end
								2'd2: begin
									i2c_data_in[11:8]	<= data_in;
									send_cnt			<= 2'd1;
								end
								2'd1: begin
									i2c_data_in[7:4]	<= data_in;
									send_cnt			<= 2'd0;
								end
								2'd0: begin
									i2c_data_in[3:0]	<= data_in;
									i2c_start			<= 1'b1;
									curr_st				<= idle;
								end
							endcase
						end
					end
				end
				
				// Write mode: new settings
				write_mode1: begin		// Use new settings
					if (comm_sel == 2'b00) begin	// UART
						case(send_cnt)
							2'd2: begin
								uart_clk_cnt[7:4]	<= data_in;
								send_cnt			<= 2'd1;
							end
							2'd1: begin
								uart_clk_cnt[3:0]	<= data_in;
								send_cnt			<= 2'd0;
							end
							2'd0: begin
								uart_enable			<= data_in[3];
								uart_setting		<= data_in[2];
								parity_en			<= data_in[1];
								parity_odd			<= data_in[0];
								
								if (data_in[3] & data_in[2]) begin
									curr_st		<= write_mode0;
									send_cnt	<= 2'd1;
								end
								else
									curr_st		<= idle;
							end
							default: curr_st	<= idle;
						endcase
					end
					if (comm_sel == 2'b01) begin	// SPI
						case(send_cnt)
							2'd2: begin
								spi_clk_cnt[7:4]	<= data_in;
								send_cnt			<= 2'd1;
							end
							2'd1: begin
								spi_clk_cnt[3:0]	<= data_in;
								send_cnt			<= 2'd0;
							end
							2'd0: begin
								spi_mode			<= data_in[3:2];
								spi_bits16			<= data_in[1];
								//spi_start			<= data_in[0];	// start bit
								
								if (data_in[0]) begin
									curr_st		<= write_mode0;
									if (data_in[1])
										send_cnt	<= 2'd3;
									else
										send_cnt	<= 2'd1;
								end
								else
									curr_st		<= idle;
							end
							default: curr_st	<= idle;
						endcase
					end
					if (comm_sel == 2'b10) begin	// I2C
						case(send_cnt)
							2'd2: begin
								i2c_clk_cnt[7:4]	<= data_in;
								send_cnt			<= 2'd1;
							end
							2'd1: begin
								i2c_clk_cnt[3:0]	<= data_in;
								send_cnt			<= 2'd0;
							end
							2'd0: begin
								i2c_write_n			<= data_in[3];
								i2c_bits16			<= data_in[2];
								//i2c_start			<= data_in[1];	// start bit
								
								if (data_in[1]) begin
									curr_st		<= write_mode0;
									i2c_addr_en	<= 1'b1;
									send_cnt	<= 2'd1;
								end
								else
									curr_st		<= idle;
							end
							default: curr_st	<= idle;
						endcase
					end
				end
			endcase
		end
	end
	
endmodule


`default_nettype none

// Module for the I2C
module i2c #(
	parameter DATA_BITS = 16,
	parameter CLK_RATIO = 8
		)(
	// Internal ports
	input	wire			clk,
	input	wire			reset_n,
	input	wire			start,
	input	wire			bits16,
	input	wire			write_n,	// "0" for write
	input	wire [6:0]		address,
	input	wire [DATA_BITS-1:0]	data_in,
	input	wire [CLK_RATIO-1:0]	clk_cnt,	// clk_cnt of SCL wrt IPCLK (>=2)
	output	reg  [DATA_BITS-1:0]	data_out,
	output	reg			busy,
	output	reg			error,
	
	// External ports
	output	reg			SCL,		// Serial Interface Clock
	output	reg			SDA_op,	// Serial Interface Data Out
	input	wire			SDA_in,	// Serial Interface Data In
	output	reg			op_en		// SDA Mode Select
	);
	
	reg			read_mode;
	reg [7:0]		addr_wr;
	reg [DATA_BITS-1:0]	data_wr;
	reg [CLK_RATIO-1:0]	clk_cnt_reg;
	reg [CLK_RATIO-1:0]	scl_cnt;
	
	reg [2:0]		addr_ind;
	reg [$clog2(DATA_BITS)-1: 0] data_ind;
	
	// State machine
	reg [2:0] curr_st;
	localparam [2:0]
		idle		= 3'b000,
		start_seq	= 3'b001,
		wait_st0	= 3'b010,
		addr_tr	= 3'b011,
		ack_tr		= 3'b100,
		data_tr	= 3'b101,
		wait_st1	= 3'b110,
		stop		= 3'b111;
	
	// State register
	always @(posedge clk) begin
		if (~reset_n) begin
			SCL		<= 1'b1;
			SDA_op		<= 1'b1;
			op_en		<= 1'b1;
			
			data_out	<= {DATA_BITS{1'b0}};
			busy		<= 1'b0;
			error		<= 1'b0;
			
			read_mode	<= 1'b0;
			addr_wr	<= 8'd0;
			data_wr	<= {DATA_BITS{1'b0}};
			scl_cnt	<= {CLK_RATIO{1'b0}};
			clk_cnt_reg	<= {CLK_RATIO{1'b0}};
			addr_ind	<= 3'd0;
			data_ind	<= {$clog2(DATA_BITS){1'b0}};
			
			curr_st	<= idle;
		end
		else begin
			case(curr_st)
				idle: begin
					SCL		<= 1'b1;
					SDA_op		<= 1'b1;
					op_en		<= 1'b1;
					
					busy		<= 1'b0;
					
					read_mode	<= 1'b0;
					addr_wr	<= 8'd0;
					data_wr	<= {DATA_BITS{1'b0}};
					scl_cnt	<= {CLK_RATIO{1'b0}};
					clk_cnt_reg	<= {CLK_RATIO{1'b0}};
					addr_ind	<= 3'd0;
					data_ind	<= {$clog2(DATA_BITS){1'b0}};
					
					if (start) begin
						data_out	<= {DATA_BITS{1'b0}};
						busy		<= 1'b1;
						error		<= 1'b0;
						
						read_mode	<= write_n;
						addr_wr	<= {address, write_n};
						data_wr	<= data_in;
						scl_cnt	<= clk_cnt-1;
						clk_cnt_reg	<= clk_cnt;
						addr_ind	<= 3'd7;
						data_ind	<= bits16 ? (DATA_BITS-1) : ((DATA_BITS >> 1)-1);
						
						curr_st	<= start_seq;
					end
				end
				
				start_seq: begin
					scl_cnt	<= scl_cnt - 1;
					
					if (scl_cnt == (clk_cnt_reg >> 1))
						SDA_op		<= 1'b0;
					if (scl_cnt == 0) begin
						SCL		<= 1'b0;
						
						scl_cnt	<= clk_cnt_reg-1;
						curr_st	<= wait_st0;
					end
				end
				
				wait_st0 : begin
					scl_cnt	<= scl_cnt - 1;
					
					if (scl_cnt == (clk_cnt_reg >> 1)) begin
						SDA_op		<= addr_wr[addr_ind];
						
						scl_cnt	<= clk_cnt_reg-1;
						curr_st	<= addr_tr;
					end
				end
				
				addr_tr: begin
					scl_cnt	<= scl_cnt - 1;
					
					if (scl_cnt == (clk_cnt_reg >> 1)) begin
						SCL		<= 1'b1;
						
						if (addr_ind > 0)
							addr_ind	<= addr_ind-1;
						if (addr_ind == 0)
							curr_st	<= ack_tr;
					end
					if (scl_cnt == 0) begin
						SCL		<= 1'b0;
						
						SDA_op		<= addr_wr[addr_ind];
						scl_cnt	<= clk_cnt_reg-1;
					end
				end
				
				ack_tr: begin
					scl_cnt	<= scl_cnt - 1;
					
					if (scl_cnt == 0) begin
						SCL		<= 1'b0;
						SDA_op		<= 1'b0;
						op_en		<= 1'b0;
						
						scl_cnt	<= clk_cnt_reg-1;
					end
					
					if (scl_cnt == (clk_cnt_reg >> 1)) begin
						SCL		<= 1'b1;
						
						if (SDA_in == 0)
							curr_st	<= data_tr;
						else begin
							error		<= 1'b1;
							
							curr_st	<= idle;
						end
					end
				end
				
				data_tr: begin
					scl_cnt	<= scl_cnt - 1;
					
					if (scl_cnt == 0) begin
						SCL		<= 1'b0;
						
						if (~read_mode) begin
							SDA_op		<= data_wr[data_ind];
							op_en		<= 1'b1;
						end
						
						scl_cnt	<= clk_cnt_reg-1;
					end
					
					if (scl_cnt == (clk_cnt_reg >> 1)) begin
						SCL		<= 1'b1;
						
						if (read_mode)
							data_out[data_ind]	<= SDA_in;
						if (data_ind > 0)
							data_ind	<= data_ind-1;
						if (data_ind == 0)
							curr_st	<= wait_st1;
					end
				end
				
				wait_st1: begin
					scl_cnt	<= scl_cnt - 1;
					
					if (scl_cnt == 0) begin
						SCL		<= 1'b0;
						
						scl_cnt	<= clk_cnt_reg-1;
					end
					
					if (scl_cnt == (clk_cnt_reg >> 1)) begin
						SCL		<= 1'b1;
						op_en		<= 1'b1;
						
						curr_st	<= stop;
					end
				end
				
				stop: begin
					scl_cnt	<= scl_cnt - 1;
					
					if (scl_cnt == 0) begin
						SDA_op		<= 1'b1;
						
						busy		<= 1'b0;
						
						curr_st	<= idle;
					end
				end
			endcase
		end
	end
	
endmodule



`default_nettype none

// Module for the SPI
module spi #(
	parameter DATA_BITS = 16,
	parameter CLK_RATIO = 8
		)(
	// Internal ports
	input	wire			clk,
	input	wire			reset_n,
	input	wire			start,
	input	wire			bits16,
	input	wire [1:0]		mode,
	input	wire [DATA_BITS-1:0]	data_in,
	input	wire [CLK_RATIO-1:0]	clk_cnt,	// clk_cnt of SCLK wrt IPCLK (>=2)
	output	reg  [DATA_BITS-1:0]	data_out,
	output	reg			busy,
	
	// External ports
	output	reg			SEN,	// Serial Interface Enable; Active low
	output	reg			SCLK,	// Serial Interface Clock
	output	reg			MOSI,	// Serial Interface Data Out
	input	wire			MISO	// Serial Interface Data In
	);
	
	reg CPOL, CPHA;
	
	reg [DATA_BITS-1:0]	data_wr;
	reg [CLK_RATIO-1: 0]	clk_cnt_reg;
	reg [CLK_RATIO-1: 0]	sclk_cnt;
	
	reg [$clog2(DATA_BITS)-1: 0] data_ind;

	// State machine
	reg [1:0] curr_st;
	localparam [1:0]
		idle		= 2'b00,
		data_tr	= 2'b01,
		setting	= 2'b10,
		stop		= 2'b11;
	
	
	// State register
	always @(posedge clk) begin
		if (~reset_n) begin
			SEN		<= 1'b1;
			SCLK		<= 1'b0;
			MOSI		<= 1'b0;
			
			CPOL		<= 1'b0;
			CPHA		<= 1'b0;

			data_ind	<= {$clog2(DATA_BITS){1'b0}};
			sclk_cnt	<= {CLK_RATIO{1'b0}};
			clk_cnt_reg	<= {CLK_RATIO{1'b0}};
			data_wr	<= {DATA_BITS{1'b0}};
			data_out <= {DATA_BITS{1'b0}};
			
			busy		<= 1'b0;
			
			curr_st	<= idle;
		end
		else begin
			case(curr_st)
				idle: begin
					SEN		<= 1'b1;
					SCLK		<= 1'b0;
					MOSI		<= 1'b0;
					
					CPOL		<= 1'b0;
					CPHA		<= 1'b0;
					
					data_ind	<= {$clog2(DATA_BITS){1'b0}};
					sclk_cnt	<= {CLK_RATIO{1'b0}};
					clk_cnt_reg	<= {CLK_RATIO{1'b0}};
					data_wr	<= {DATA_BITS{1'b0}};
					
					busy 		<= 1'b0;
					
					if (start) begin						
						data_ind	<= bits16 ? (DATA_BITS-1) : ((DATA_BITS >> 1)-1);
						sclk_cnt	<= clk_cnt-1;
						clk_cnt_reg	<= clk_cnt;
						data_wr	<= data_in;
						data_out <= {DATA_BITS{1'b0}};
						
						
						CPOL		<= mode[1];
						CPHA		<= mode[0];
						
						busy		<= 1'b1;
						
						curr_st	<= setting;
					end
				end
				
				setting: begin
					SCLK		<= CPOL;
					
					sclk_cnt	<= sclk_cnt - 1;
					if (sclk_cnt == (clk_cnt_reg >> 1)) begin
						SEN		<= 1'b0;
						MOSI		<= data_wr[data_ind];
						
						sclk_cnt	<= clk_cnt_reg-1;
						
						curr_st	<= data_tr;
					end
				end
				
				data_tr: begin
					sclk_cnt <= sclk_cnt - 1;
					if (sclk_cnt == (clk_cnt_reg >> 1)) begin
						SCLK <= ~SCLK;
						
						case({CPOL, CPHA})
							2'b00: begin	// Mode 0; rising edge
								data_out[data_ind]	<= MISO;
							
								if (data_ind > 0)
									data_ind	<= data_ind-1;
								if (data_ind == 0)
									curr_st	<= stop;
							end
							2'b01: begin	// Mode 1; rising edge
								MOSI		<= data_wr[data_ind];
							end
							2'b10: begin	// Mode 2; falling edge
								data_out[data_ind]	<= MISO;
							
								if (data_ind > 0)
									data_ind	<= data_ind-1;
								if (data_ind == 0)
									curr_st	<= stop;
							end
							2'b11: begin	// Mode 3; falling edge
								MOSI		<= data_wr[data_ind];
							end
						endcase
					end
					if (sclk_cnt == 0) begin
						SCLK <= ~SCLK;
						
						sclk_cnt <= clk_cnt_reg - 1;
						
						case({CPOL, CPHA})
							2'b00: begin	// Mode 0; falling edge
								MOSI		<= data_wr[data_ind];
							end
							2'b01: begin	// Mode 1; falling edge
								data_out[data_ind]	<= MISO;
							
								if (data_ind > 0)
									data_ind	<= data_ind-1;
								if (data_ind == 0)
									curr_st	<= stop;
							end
							2'b10: begin	// Mode 2; rising edge
								MOSI		<= data_wr[data_ind];
							end
							2'b11: begin	// Mode 3; rising edge
								data_out[data_ind]	<= MISO;
							
								if (data_ind > 0)
									data_ind	<= data_ind-1;
								if (data_ind == 0)
									curr_st	<= stop;
							end
						endcase
					end
				end
				
				stop: begin
					sclk_cnt <= sclk_cnt - 1;
					if ((sclk_cnt == 0) | (sclk_cnt == (clk_cnt_reg >> 1))) begin
						SEN <= 1'b1;
						
						busy	<= 1'b0;
						
						curr_st <= idle;
					end
				end
			endcase
		end
	end
	
endmodule



`default_nettype none

// Module for  UART
module uart #(
	parameter CLK_RATIO = 8
		)(
	// Internal Ports
	input	wire					clk,
	input	wire					reset_n,
	
	input	wire					enable,
	input	wire					setting,
	input	wire					parity_en,
	input	wire					parity_odd,
	input	wire					tx_new,
	input	wire					rx_ack,
	output	reg						tx_busy,
	output	reg						rx_new,
	output	reg						rx_error,
	
	input	wire	[CLK_RATIO-1:0]	clk_cnt,	// clk_cnt of baudrate wrt IPCLK (>=2)
	input 	wire	[7:0]   		tx_data,
	output	reg 	[7:0] 	  		rx_data,
	
	// External Ports
	input	wire					UART_RX,	// Data in pin
	output	reg						UART_TX		// Data out pin
	);
	
	// Uart settings
	reg         par_en;		// Enable the parity bit
	reg         par_odd;	// 1'b0: Even parity; 1'b1: Odd parity
	reg			clk_b;
	
	reg	[10:0]	tx_data_reg;
	reg	[10:0]	rx_data_reg;
	reg	[3:0]	tx_ind;
	reg	[3:0]	rx_ind;
	
	reg	[CLK_RATIO-1:0] clk_cnt_reg;	// Clk_rate/(baud_rate*2)
	reg	[CLK_RATIO-1:0] uclk_cnt;
	
	// State instantiations
	reg [1:0]		curr_st;
	localparam
		idle 	= 2'b00,
		setup	= 2'b01,
		working	= 2'b10;
	
	reg				tx_st;
	localparam
		idle_tx		= 1'b0,
		data_st_tx	= 1'b1;
	
	reg	[1:0]		rx_st;
	localparam
		idle_rx		= 2'b00,
		data_st_rx	= 2'b01,
		valid_rx	= 2'b10;
	
	
	always @(posedge clk) begin
		if(~reset_n) begin
			clk_b		<= 1'b0;
			par_en		<= 1'b0;
			par_odd		<= 1'b0;
			clk_cnt_reg	<= {CLK_RATIO{1'b0}};
			uclk_cnt	<= {CLK_RATIO{1'b0}};
			
			curr_st		<= idle;
		end
		else begin
			case(curr_st)
				idle: begin
					clk_b		<= 1'b0;
					par_en		<= 1'b0;
					par_odd		<= 1'b0;
					clk_cnt_reg	<= {CLK_RATIO{1'b0}};
					uclk_cnt	<= {CLK_RATIO{1'b0}};
					
					if (setting)
						curr_st		<= setup;
				end
				
				setup: begin
					clk_cnt_reg	<= clk_cnt;
					uclk_cnt	<= clk_cnt-1;
					par_en		<= parity_en;
					par_odd		<= parity_odd;
					
					if (enable)
						curr_st		<= working;
				end
				
				working: begin
					// Uart clk generation
					uclk_cnt	<= uclk_cnt-1;
					if (uclk_cnt == 0) begin
						uclk_cnt	<= clk_cnt_reg-1;
						clk_b		<= 1'b1;
					end
					if (uclk_cnt == (clk_cnt_reg >> 1))
						clk_b		<= 1'b0;
					if (~enable)
						curr_st		<= idle;
				end
				
				default:
					curr_st	<= idle;
			endcase
		end
	end
	
	// UART Tx
	always @(posedge(clk_b)) begin
		if (~reset_n) begin
			tx_data_reg	<= 11'd0;
			tx_ind		<= 4'd0;
			tx_busy		<= 1'b0;
			
			UART_TX		<= 1'b1;
			
			tx_st		<= idle_tx;
		end
		else begin
			case(tx_st)
				idle_tx: begin
					tx_data_reg	<= 11'd0;
					tx_ind		<= 4'd0;
					tx_busy		<= 1'b0;
					
					UART_TX		<= 1'b1;
					
					if (enable & tx_new) begin
						tx_ind		<= par_en ? 4'd10 : 4'd9;
						tx_busy		<= 1'b1;
						if (par_en) begin
							if (par_odd)
								tx_data_reg	<= {1'b0, tx_data, ~^(tx_data), 1'b1};
							else
								tx_data_reg	<= {1'b0, tx_data, ^(tx_data), 1'b1};
						end
						else
							tx_data_reg	<= {2'b0, tx_data, 1'b1};
						
						tx_st	<= data_st_tx;
					end
				end
				
				data_st_tx: begin
					UART_TX		<= tx_data_reg[tx_ind];
					tx_ind		<= tx_ind-1;
					
					if (tx_ind == 0) begin
						tx_busy	<= 1'b0;
						
						tx_st	<= idle_tx;
					end
				end
			endcase
		end
	end
	
	// UART Rx
	always @(posedge(clk_b)) begin
		if (~reset_n) begin
			rx_data_reg	<= 11'd0;
			rx_ind		<= 4'd0;
			rx_new		<= 1'b0;
			rx_error	<= 1'b0;
			
			rx_st		<= idle_rx;
		end
		else begin
			case(rx_st)
				idle_rx: begin
					rx_data_reg	<= 11'd0;
					rx_ind		<= par_en ? 4'd10 : 4'd9;
					
					if (rx_ack)
						rx_new	<= 1'b0;
					
					if (enable & ~UART_RX) begin
						rx_data_reg[rx_ind]	<= UART_RX;
						rx_ind				<= rx_ind-1;
						
						rx_new				<= 1'b0;
						rx_error			<= 1'b0;
						
						rx_st				<= data_st_rx;
					end
				end
				
				data_st_rx: begin
					rx_data_reg[rx_ind]	<= UART_RX;
					rx_ind				<= rx_ind-1;
					
					if (rx_ind == 0)
						rx_st	<= valid_rx;
				end
				
				valid_rx: begin
					rx_st	<= idle;
					
					if (par_en) begin
						if (par_odd) begin
							if ((rx_data_reg[0] == 1'b1) & (rx_data_reg[10] == 1'b0) & (rx_data_reg[1] == ~^(rx_data_reg[9:2]))) begin
								rx_data <= rx_data_reg[9:2];
								rx_new	<= 1'b1;
							end
							else
								rx_error	<= 1'b1;
						end
						else begin
							if ((rx_data_reg[0] == 1'b1) & (rx_data_reg[10] == 1'b0) & (rx_data_reg[1] == ^(rx_data_reg[9:2]))) begin
								rx_data <= rx_data_reg[9:2];
								rx_new	<= 1'b1;
							end
							else
								rx_error	<= 1'b1;
						end
					end
					else begin
						if ((rx_data_reg[0] == 1'b1) & (rx_data_reg[9] == 1'b0)) begin
							rx_data <= rx_data_reg[8:1];
							rx_new	<= 1'b1;
						end
						else
							rx_error	<= 1'b1;
					end
				end
			endcase
		end
	end

endmodule



Reference solution:
rtl/generated.v: 
	// All output pins must be assigned. If not used, assign to 0.
	assign uio_out[7] = clk;
	assign uio_oe[1]  = 1'b1;
	assign uio_oe[6]  = 1'b1;
	assign uio_oe[7]  = 1'b1;

	// List all unused inputs to prevent warnings
	wire _unused = &{ena, ui_in[7:3], uio_in[1], uio_in[7:6]};
	
	comm_ic comm_ic0 (.clk(clk), .reset_n(rst_n), 
			  .UART_RX(ui_in[0]), .UART_TX(uo_out[0]),
			  .SEN(uo_out[1]), .SCLK(uo_out[2]), .MOSI(uo_out[3]), .MISO(ui_in[1]),
			  .SCL(uo_out[4]), .SDA_in(uio_in[0]), .SDA_op(uio_out[0]), .SDA_op_en(uio_oe[0]),
			  .busy_uart(uo_out[5]), .busy_spi(uo_out[6]), .busy_i2c(uo_out[7]), .new_uart(uio_out[1]), .error_i2c(uio_out[6]),
			  .data_in(uio_in[5:2]), .data_out(uio_out[5:2]), .data_op_en(uio_oe[5:2]), .data_en(ui_in[2]));