FPU , I2C , PTC and RTC RTL added to user project area
diff --git a/verilog/rtl/fpu/except.v b/verilog/rtl/fpu/except.v
new file mode 100644
index 0000000..007099f
--- /dev/null
+++ b/verilog/rtl/fpu/except.v
@@ -0,0 +1,153 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  EXCEPT                                                     ////
+////  Floating Point Exception/Special Numbers Unit              ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+
+`timescale 1ns / 100ps
+
+
+module except(	clk, opa, opb, inf, ind, qnan, snan, opa_nan, opb_nan,
+		opa_00, opb_00, opa_inf, opb_inf, opa_dn, opb_dn);
+input		clk;
+input	[31:0]	opa, opb;
+output		inf, ind, qnan, snan, opa_nan, opb_nan;
+output		opa_00, opb_00;
+output		opa_inf, opb_inf;
+output		opa_dn;
+output		opb_dn;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+wire	[7:0]	expa, expb;		// alias to opX exponent
+wire	[22:0]	fracta, fractb;		// alias to opX fraction
+reg		expa_ff, infa_f_r, qnan_r_a, snan_r_a;
+reg		expb_ff, infb_f_r, qnan_r_b, snan_r_b;
+reg		inf, ind, qnan, snan;	// Output registers
+reg		opa_nan, opb_nan;
+reg		expa_00, expb_00, fracta_00, fractb_00;
+reg		opa_00, opb_00;
+reg		opa_inf, opb_inf;
+reg		opa_dn, opb_dn;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Aliases
+//
+
+assign   expa = opa[30:23];
+assign   expb = opb[30:23];
+assign fracta = opa[22:0];
+assign fractb = opb[22:0];
+
+////////////////////////////////////////////////////////////////////////
+//
+// Determine if any of the input operators is a INF or NAN or any other special number
+//
+
+always @(posedge clk)
+	expa_ff <= #1 &expa;
+
+always @(posedge clk)
+	expb_ff <= #1 &expb;
+	
+always @(posedge clk)
+	infa_f_r <= #1 !(|fracta);
+
+always @(posedge clk)
+	infb_f_r <= #1 !(|fractb);
+
+always @(posedge clk)
+	qnan_r_a <= #1  fracta[22];
+
+always @(posedge clk)
+	snan_r_a <= #1 !fracta[22] & |fracta[21:0];
+	
+always @(posedge clk)
+	qnan_r_b <= #1  fractb[22];
+
+always @(posedge clk)
+	snan_r_b <= #1 !fractb[22] & |fractb[21:0];
+
+always @(posedge clk)
+	ind  <= #1 (expa_ff & infa_f_r) & (expb_ff & infb_f_r);
+
+always @(posedge clk)
+	inf  <= #1 (expa_ff & infa_f_r) | (expb_ff & infb_f_r);
+
+always @(posedge clk)
+	qnan <= #1 (expa_ff & qnan_r_a) | (expb_ff & qnan_r_b);
+
+always @(posedge clk)
+	snan <= #1 (expa_ff & snan_r_a) | (expb_ff & snan_r_b);
+
+always @(posedge clk)
+	opa_nan <= #1 &expa & (|fracta[22:0]);
+
+always @(posedge clk)
+	opb_nan <= #1 &expb & (|fractb[22:0]);
+
+always @(posedge clk)
+	opa_inf <= #1 (expa_ff & infa_f_r);
+
+always @(posedge clk)
+	opb_inf <= #1 (expb_ff & infb_f_r);
+
+always @(posedge clk)
+	expa_00 <= #1 !(|expa);
+
+always @(posedge clk)
+	expb_00 <= #1 !(|expb);
+
+always @(posedge clk)
+	fracta_00 <= #1 !(|fracta);
+
+always @(posedge clk)
+	fractb_00 <= #1 !(|fractb);
+
+always @(posedge clk)
+	opa_00 <= #1 expa_00 & fracta_00;
+
+always @(posedge clk)
+	opb_00 <= #1 expb_00 & fractb_00;
+
+always @(posedge clk)
+	opa_dn <= #1 expa_00;
+
+always @(posedge clk)
+	opb_dn <= #1 expb_00;
+
+endmodule
+
diff --git a/verilog/rtl/fpu/fpu.v b/verilog/rtl/fpu/fpu.v
new file mode 100644
index 0000000..245ef20
--- /dev/null
+++ b/verilog/rtl/fpu/fpu.v
@@ -0,0 +1,558 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  FPU                                                        ////
+////  Floating Point Unit (Single precision)                     ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+`timescale 1ns / 100ps
+
+/*
+
+FPU Operations (fpu_op):
+========================
+
+0 = add
+1 = sub
+2 = mul
+3 = div
+4 =
+5 =
+6 =
+7 =
+
+Rounding Modes (rmode):
+=======================
+
+0 = round_nearest_even
+1 = round_to_zero
+2 = round_up
+3 = round_down
+
+*/
+
+
+module fpu( clk, rmode, fpu_op, opa, opb, out, inf, snan, qnan, ine, overflow, underflow, zero, div_by_zero);
+input		clk;
+input	[1:0]	rmode;
+input	[2:0]	fpu_op;
+input	[31:0]	opa, opb;
+output	[31:0]	out;
+output		inf, snan, qnan;
+output		ine;
+output		overflow, underflow;
+output		zero;
+output		div_by_zero;
+
+parameter	INF  = 31'h7f800000,
+		QNAN = 31'h7fc00001,
+		SNAN = 31'h7f800001;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires
+//
+reg		zero;
+reg	[31:0]	opa_r, opb_r;		// Input operand registers
+reg	[31:0]	out;			// Output register
+reg		div_by_zero;		// Divide by zero output register
+wire		signa, signb;		// alias to opX sign
+wire		sign_fasu;		// sign output
+wire	[26:0]	fracta, fractb;		// Fraction Outputs from EQU block
+wire	[7:0]	exp_fasu;		// Exponent output from EQU block
+reg	[7:0]	exp_r;			// Exponent output (registerd)
+wire	[26:0]	fract_out_d;		// fraction output
+wire		co;			// carry output
+reg	[27:0]	fract_out_q;		// fraction output (registerd)
+wire	[30:0]	out_d;			// Intermediate final result output
+wire		overflow_d, underflow_d;// Overflow/Underflow Indicators
+reg		overflow, underflow;	// Output registers for Overflow & Underflow
+reg		inf, snan, qnan;	// Output Registers for INF, SNAN and QNAN
+reg		ine;			// Output Registers for INE
+reg	[1:0]	rmode_r1, rmode_r2, 	// Pipeline registers for rounding mode
+		rmode_r3;
+reg	[2:0]	fpu_op_r1, fpu_op_r2,	// Pipeline registers for fp opration
+		fpu_op_r3;
+wire		mul_inf, div_inf;
+wire		mul_00, div_00;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Input Registers
+//
+
+always @(posedge clk)
+	opa_r <= #1 opa;
+
+always @(posedge clk)
+	opb_r <= #1 opb;
+
+always @(posedge clk)
+	rmode_r1 <= #1 rmode;
+
+always @(posedge clk)
+	rmode_r2 <= #1 rmode_r1;
+
+always @(posedge clk)
+	rmode_r3 <= #1 rmode_r2;
+
+always @(posedge clk)
+	fpu_op_r1 <= #1 fpu_op;
+
+always @(posedge clk)
+	fpu_op_r2 <= #1 fpu_op_r1;
+
+always @(posedge clk)
+	fpu_op_r3 <= #1 fpu_op_r2;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Exceptions block
+//
+wire		inf_d, ind_d, qnan_d, snan_d, opa_nan, opb_nan;
+wire		opa_00, opb_00;
+wire		opa_inf, opb_inf;
+wire		opa_dn, opb_dn;
+
+except u0(	.clk(clk),
+		.opa(opa_r), .opb(opb_r),
+		.inf(inf_d), .ind(ind_d),
+		.qnan(qnan_d), .snan(snan_d),
+		.opa_nan(opa_nan), .opb_nan(opb_nan),
+		.opa_00(opa_00), .opb_00(opb_00),
+		.opa_inf(opa_inf), .opb_inf(opb_inf),
+		.opa_dn(opa_dn), .opb_dn(opb_dn)
+		);
+
+////////////////////////////////////////////////////////////////////////
+//
+// Pre-Normalize block
+// - Adjusts the numbers to equal exponents and sorts them
+// - determine result sign
+// - determine actual operation to perform (add or sub)
+//
+
+wire		nan_sign_d, result_zero_sign_d;
+reg		sign_fasu_r;
+wire	[7:0]	exp_mul;
+wire		sign_mul;
+reg		sign_mul_r;
+wire	[23:0]	fracta_mul, fractb_mul;
+wire		inf_mul;
+reg		inf_mul_r;
+wire	[1:0]	exp_ovf;
+reg	[1:0]	exp_ovf_r;
+wire		sign_exe;
+reg		sign_exe_r;
+wire	[2:0]	underflow_fmul_d;
+
+
+pre_norm u1(.clk(clk),				// System Clock
+	.rmode(rmode_r2),			// Roundin Mode
+	.add(!fpu_op_r1[0]),			// Add/Sub Input
+	.opa(opa_r),  .opb(opb_r),		// Registered OP Inputs
+	.opa_nan(opa_nan),			// OpA is a NAN indicator
+	.opb_nan(opb_nan),			// OpB is a NAN indicator
+	.fracta_out(fracta),			// Equalized and sorted fraction
+	.fractb_out(fractb),			// outputs (Registered)
+	.exp_dn_out(exp_fasu),			// Selected exponent output (registered);
+	.sign(sign_fasu),			// Encoded output Sign (registered)
+	.nan_sign(nan_sign_d),			// Output Sign for NANs (registered)
+	.result_zero_sign(result_zero_sign_d),	// Output Sign for zero result (registered)
+	.fasu_op(fasu_op)			// Actual fasu operation output (registered)
+	);
+
+always @(posedge clk)
+	sign_fasu_r <= #1 sign_fasu;
+
+pre_norm_fmul u2(
+		.clk(clk),
+		.fpu_op(fpu_op_r1),
+		.opa(opa_r), .opb(opb_r),
+		.fracta(fracta_mul),
+		.fractb(fractb_mul),
+		.exp_out(exp_mul),	// FMUL exponent output (registered)
+		.sign(sign_mul),	// FMUL sign output (registered)
+		.sign_exe(sign_exe),	// FMUL exception sign output (registered)
+		.inf(inf_mul),		// FMUL inf output (registered)
+		.exp_ovf(exp_ovf),	// FMUL exponnent overflow output (registered)
+		.underflow(underflow_fmul_d)
+		);
+
+
+always @(posedge clk)
+	sign_mul_r <= #1 sign_mul;
+
+always @(posedge clk)
+	sign_exe_r <= #1 sign_exe;
+
+always @(posedge clk)
+	inf_mul_r <= #1 inf_mul;
+
+always @(posedge clk)
+	exp_ovf_r <= #1 exp_ovf;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Add/Sub
+//
+
+add_sub27 u3(
+	.add(fasu_op),			// Add/Sub
+	.opa(fracta),			// Fraction A input
+	.opb(fractb),			// Fraction B Input
+	.sum(fract_out_d),		// SUM output
+	.co(co_d) );			// Carry Output
+
+always @(posedge clk)
+	fract_out_q <= #1 {co_d, fract_out_d};
+
+////////////////////////////////////////////////////////////////////////
+//
+// Mul
+//
+wire	[47:0]	prod;
+
+mul_r2 u5(.clk(clk), .opa(fracta_mul), .opb(fractb_mul), .prod(prod));
+
+////////////////////////////////////////////////////////////////////////
+//
+// Divide
+//
+wire	[49:0]	quo;
+wire	[49:0]	fdiv_opa;
+wire	[49:0]	remainder;
+wire		remainder_00;
+reg	[4:0]	div_opa_ldz_d, div_opa_ldz_r1, div_opa_ldz_r2;
+
+always @(fracta_mul)
+	casex(fracta_mul[22:0])
+	   23'b1??????????????????????: div_opa_ldz_d = 1;
+	   23'b01?????????????????????: div_opa_ldz_d = 2;
+	   23'b001????????????????????: div_opa_ldz_d = 3;
+	   23'b0001???????????????????: div_opa_ldz_d = 4;
+	   23'b00001??????????????????: div_opa_ldz_d = 5;
+	   23'b000001?????????????????: div_opa_ldz_d = 6;
+	   23'b0000001????????????????: div_opa_ldz_d = 7;
+	   23'b00000001???????????????: div_opa_ldz_d = 8;
+	   23'b000000001??????????????: div_opa_ldz_d = 9;
+	   23'b0000000001?????????????: div_opa_ldz_d = 10;
+	   23'b00000000001????????????: div_opa_ldz_d = 11;
+	   23'b000000000001???????????: div_opa_ldz_d = 12;
+	   23'b0000000000001??????????: div_opa_ldz_d = 13;
+	   23'b00000000000001?????????: div_opa_ldz_d = 14;
+	   23'b000000000000001????????: div_opa_ldz_d = 15;
+	   23'b0000000000000001???????: div_opa_ldz_d = 16;
+	   23'b00000000000000001??????: div_opa_ldz_d = 17;
+	   23'b000000000000000001?????: div_opa_ldz_d = 18;
+	   23'b0000000000000000001????: div_opa_ldz_d = 19;
+	   23'b00000000000000000001???: div_opa_ldz_d = 20;
+	   23'b000000000000000000001??: div_opa_ldz_d = 21;
+	   23'b0000000000000000000001?: div_opa_ldz_d = 22;
+	   23'b0000000000000000000000?: div_opa_ldz_d = 23;
+	endcase
+
+assign fdiv_opa = !(|opa_r[30:23]) ? {(fracta_mul<<div_opa_ldz_d), 26'h0} : {fracta_mul, 26'h0};
+
+
+div_r2 u6(.clk(clk), .opa(fdiv_opa), .opb(fractb_mul), .quo(quo), .rem(remainder));
+
+assign remainder_00 = !(|remainder);
+
+always @(posedge clk)
+	div_opa_ldz_r1 <= #1 div_opa_ldz_d;
+
+always @(posedge clk)
+	div_opa_ldz_r2 <= #1 div_opa_ldz_r1;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Normalize Result
+//
+wire		ine_d;
+reg	[47:0]	fract_denorm;
+wire	[47:0]	fract_div;
+wire		sign_d;
+reg		sign;
+reg	[30:0]	opa_r1;
+reg	[47:0]	fract_i2f;
+reg		opas_r1, opas_r2;
+wire		f2i_out_sign;
+
+always @(posedge clk)			// Exponent must be once cycle delayed
+	case(fpu_op_r2)
+	  0,1:	exp_r <= #1 exp_fasu;
+	  2,3:	exp_r <= #1 exp_mul;
+	  4:	exp_r <= #1 0;
+	  5:	exp_r <= #1 opa_r1[30:23];
+	endcase
+
+assign fract_div = (opb_dn ? quo[49:2] : {quo[26:0], 21'h0});
+
+always @(posedge clk)
+	opa_r1 <= #1 opa_r[30:0];
+
+always @(posedge clk)
+	fract_i2f <= #1 (fpu_op_r2==5) ?
+			(sign_d ?  1-{24'h00, (|opa_r1[30:23]), opa_r1[22:0]}-1 : {24'h0, (|opa_r1[30:23]), opa_r1[22:0]}) :
+			(sign_d ? 1 - {opa_r1, 17'h01} : {opa_r1, 17'h0});
+
+always @(fpu_op_r3 or fract_out_q or prod or fract_div or fract_i2f)
+	case(fpu_op_r3)
+	   0,1:	fract_denorm = {fract_out_q, 20'h0};
+	   2:	fract_denorm = prod;
+	   3:	fract_denorm = fract_div;
+	   4,5:	fract_denorm = fract_i2f;
+	endcase
+
+
+always @(posedge clk)
+	opas_r1 <= #1 opa_r[31];
+
+always @(posedge clk)
+	opas_r2 <= #1 opas_r1;
+
+assign sign_d = fpu_op_r2[1] ? sign_mul : sign_fasu;
+
+always @(posedge clk)
+	sign <= #1 (rmode_r2==2'h3) ? !sign_d : sign_d;
+
+post_norm u4(.clk(clk),			// System Clock
+	.fpu_op(fpu_op_r3),		// Floating Point Operation
+	.opas(opas_r2),			// OPA Sign
+	.sign(sign),			// Sign of the result
+	.rmode(rmode_r3),		// Rounding mode
+	.fract_in(fract_denorm),	// Fraction Input
+	.exp_ovf(exp_ovf_r),		// Exponent Overflow
+	.exp_in(exp_r),			// Exponent Input
+	.opa_dn(opa_dn),		// Operand A Denormalized
+	.opb_dn(opb_dn),		// Operand A Denormalized
+	.rem_00(remainder_00),		// Diveide Remainder is zero
+	.div_opa_ldz(div_opa_ldz_r2),	// Divide opa leading zeros count
+	.output_zero(mul_00 | div_00),	// Force output to Zero
+	.out(out_d),			// Normalized output (un-registered)
+	.ine(ine_d),			// Result Inexact output (un-registered)
+	.overflow(overflow_d),		// Overflow output (un-registered)
+	.underflow(underflow_d),	// Underflow output (un-registered)
+	.f2i_out_sign(f2i_out_sign)	// F2I Output Sign
+	);
+
+////////////////////////////////////////////////////////////////////////
+//
+// FPU Outputs
+//
+reg		fasu_op_r1, fasu_op_r2;
+wire	[30:0]	out_fixed;
+wire		output_zero_fasu;
+wire		output_zero_fdiv;
+wire		output_zero_fmul;
+reg		inf_mul2;
+wire		overflow_fasu;
+wire		overflow_fmul;
+wire		overflow_fdiv;
+wire		inf_fmul;
+wire		sign_mul_final;
+wire		out_d_00;
+wire		sign_div_final;
+wire		ine_mul, ine_mula, ine_div, ine_fasu;
+wire		underflow_fasu, underflow_fmul, underflow_fdiv;
+wire		underflow_fmul1;
+reg	[2:0]	underflow_fmul_r;
+reg		opa_nan_r;
+
+
+always @(posedge clk)
+	fasu_op_r1 <= #1 fasu_op;
+
+always @(posedge clk)
+	fasu_op_r2 <= #1 fasu_op_r1;
+
+always @(posedge clk)
+	inf_mul2 <= #1 exp_mul == 8'hff;
+
+
+// Force pre-set values for non numerical output
+assign mul_inf = (fpu_op_r3==3'b010) & (inf_mul_r | inf_mul2) & (rmode_r3==2'h0);
+assign div_inf = (fpu_op_r3==3'b011) & (opb_00 | opa_inf);
+
+assign mul_00 = (fpu_op_r3==3'b010) & (opa_00 | opb_00);
+assign div_00 = (fpu_op_r3==3'b011) & (opa_00 | opb_inf);
+
+assign out_fixed = (	(qnan_d | snan_d) |
+			(ind_d & !fasu_op_r2) | 
+			((fpu_op_r3==3'b011) & opb_00 & opa_00) |
+			(((opa_inf & opb_00) | (opb_inf & opa_00 )) & fpu_op_r3==3'b010)
+		   )  ? QNAN : INF;
+
+always @(posedge clk)
+	out[30:0] <= #1 (mul_inf | div_inf | (inf_d & (fpu_op_r3!=3'b011) & (fpu_op_r3!=3'b101)) | snan_d | qnan_d) & fpu_op_r3!=3'b100 ? out_fixed :
+			out_d;
+
+assign out_d_00 = !(|out_d);
+
+assign sign_mul_final = (sign_exe_r & ((opa_00 & opb_inf) | (opb_00 & opa_inf))) ? !sign_mul_r : sign_mul_r;
+assign sign_div_final = (sign_exe_r & (opa_inf & opb_inf)) ? !sign_mul_r : sign_mul_r | (opa_00 & opb_00);
+
+always @(posedge clk)
+	out[31] <= #1	((fpu_op_r3==3'b101) & out_d_00) ? (f2i_out_sign & !(qnan_d | snan_d) ) :
+			((fpu_op_r3==3'b010) & !(snan_d | qnan_d)) ?	sign_mul_final :
+			((fpu_op_r3==3'b011) & !(snan_d | qnan_d)) ?	sign_div_final :
+			(snan_d | qnan_d | ind_d) ?			nan_sign_d :
+			output_zero_fasu ?				result_zero_sign_d :
+									sign_fasu_r;
+
+// Exception Outputs
+assign ine_mula = ((inf_mul_r |  inf_mul2 | opa_inf | opb_inf) & (rmode_r3==2'h1) & 
+		!((opa_inf & opb_00) | (opb_inf & opa_00 )) & fpu_op_r3[1]);
+
+assign ine_mul  = (ine_mula | ine_d | inf_fmul | out_d_00 | overflow_d | underflow_d) &
+		  !opa_00 & !opb_00 & !(snan_d | qnan_d | inf_d);
+assign ine_div  = (ine_d | overflow_d | underflow_d) & !(opb_00 | snan_d | qnan_d | inf_d);
+assign ine_fasu = (ine_d | overflow_d | underflow_d) & !(snan_d | qnan_d | inf_d);
+
+always @(posedge  clk)
+	ine <= #1	 fpu_op_r3[2] ? ine_d :
+			!fpu_op_r3[1] ? ine_fasu :
+			 fpu_op_r3[0] ? ine_div  : ine_mul;
+
+
+assign overflow_fasu = overflow_d & !(snan_d | qnan_d | inf_d);
+assign overflow_fmul = !inf_d & (inf_mul_r | inf_mul2 | overflow_d) & !(snan_d | qnan_d);
+assign overflow_fdiv = (overflow_d & !(opb_00 | inf_d | snan_d | qnan_d));
+
+always @(posedge clk)
+	overflow <= #1	 fpu_op_r3[2] ? 0 :
+			!fpu_op_r3[1] ? overflow_fasu :
+			 fpu_op_r3[0] ? overflow_fdiv : overflow_fmul;
+
+always @(posedge clk)
+	underflow_fmul_r <= #1 underflow_fmul_d;
+
+
+assign underflow_fmul1 = underflow_fmul_r[0] |
+			(underflow_fmul_r[1] & underflow_d ) |
+			((opa_dn | opb_dn) & out_d_00 & (prod!=0) & sign) |
+			(underflow_fmul_r[2] & ((out_d[30:23]==0) | (out_d[22:0]==0)));
+
+assign underflow_fasu = underflow_d & !(inf_d | snan_d | qnan_d);
+assign underflow_fmul = underflow_fmul1 & !(snan_d | qnan_d | inf_mul_r);
+assign underflow_fdiv = underflow_fasu & !opb_00;
+
+always @(posedge clk)
+	underflow <= #1  fpu_op_r3[2] ? 0 :
+			!fpu_op_r3[1] ? underflow_fasu :
+			 fpu_op_r3[0] ? underflow_fdiv : underflow_fmul;
+
+always @(posedge clk)
+	snan <= #1 snan_d;
+/*
+wire		mul_uf_del;
+wire		uf2_del, ufb2_del, ufc2_del,  underflow_d_del;
+wire		co_del;
+wire	[30:0]	out_d_del;
+wire		ov_fasu_del, ov_fmul_del;
+wire	[2:0]	fop;
+wire	[4:0]	ldza_del;
+wire	[49:0]	quo_del;
+
+delay1  #0 ud000(clk, underflow_fmul1, mul_uf_del);
+delay1  #0 ud001(clk, underflow_fmul_r[0], uf2_del);
+delay1  #0 ud002(clk, underflow_fmul_r[1], ufb2_del);
+delay1  #0 ud003(clk, underflow_d, underflow_d_del);
+delay1  #0 ud004(clk, test.u0.u4.exp_out1_co, co_del);
+delay1  #0 ud005(clk, underflow_fmul_r[2], ufc2_del);
+delay1 #30 ud006(clk, out_d, out_d_del);
+
+delay1  #0 ud007(clk, overflow_fasu, ov_fasu_del);
+delay1  #0 ud008(clk, overflow_fmul, ov_fmul_del);
+
+delay1  #2 ud009(clk, fpu_op_r3, fop);
+
+delay3  #4 ud010(clk, div_opa_ldz_d, ldza_del);
+
+delay1  #49 ud012(clk, quo, quo_del);
+
+always @(test.error_event)
+   begin
+	#0.2
+	$display("muf: %b uf0: %b uf1: %b uf2: %b, tx0: %b, co: %b, out_d: %h (%h %h), ov_fasu: %b, ov_fmul: %b, fop: %h",
+			mul_uf_del, uf2_del, ufb2_del, ufc2_del, underflow_d_del, co_del, out_d_del, out_d_del[30:23], out_d_del[22:0],
+			ov_fasu_del, ov_fmul_del, fop );
+	$display("ldza: %h, quo: %b",
+			ldza_del, quo_del);
+   end
+*/
+
+
+// Status Outputs
+always @(posedge clk)
+	qnan <= #1	fpu_op_r3[2] ? 0 : (
+						snan_d | qnan_d | (ind_d & !fasu_op_r2) |
+						(opa_00 & opb_00 & fpu_op_r3==3'b011) |
+						(((opa_inf & opb_00) | (opb_inf & opa_00 )) & fpu_op_r3==3'b010)
+					   );
+
+assign inf_fmul = 	(((inf_mul_r | inf_mul2) & (rmode_r3==2'h0)) | opa_inf | opb_inf) & 
+			!((opa_inf & opb_00) | (opb_inf & opa_00 )) &
+			fpu_op_r3==3'b010;
+
+always @(posedge clk)
+	inf <= #1	fpu_op_r3[2] ? 0 :
+			(!(qnan_d | snan_d) & (
+						((&out_d[30:23]) & !(|out_d[22:0]) & !(opb_00 & fpu_op_r3==3'b011)) |
+						(inf_d & !(ind_d & !fasu_op_r2) & !fpu_op_r3[1]) |
+						inf_fmul |
+						(!opa_00 & opb_00 & fpu_op_r3==3'b011) |
+						(fpu_op_r3==3'b011 & opa_inf & !opb_inf)
+					      )
+			);
+
+assign output_zero_fasu = out_d_00 & !(inf_d | snan_d | qnan_d);
+assign output_zero_fdiv = (div_00 | (out_d_00 & !opb_00)) & !(opa_inf & opb_inf) &
+			  !(opa_00 & opb_00) & !(qnan_d | snan_d);
+assign output_zero_fmul = (out_d_00 | opa_00 | opb_00) &
+			  !(inf_mul_r | inf_mul2 | opa_inf | opb_inf | snan_d | qnan_d) &
+			  !(opa_inf & opb_00) & !(opb_inf & opa_00);
+
+always @(posedge clk)
+	zero <= #1	fpu_op_r3==3'b101 ?	out_d_00 & !(snan_d | qnan_d):
+			fpu_op_r3==3'b011 ?	output_zero_fdiv :
+			fpu_op_r3==3'b010 ?	output_zero_fmul :
+						output_zero_fasu ;
+
+always @(posedge clk)
+	opa_nan_r <= #1 !opa_nan & fpu_op_r2==3'b011;
+
+always @(posedge clk)
+	div_by_zero <= #1 opa_nan_r & !opa_00 & !opa_inf & opb_00;
+
+endmodule
diff --git a/verilog/rtl/fpu/post_norm.v b/verilog/rtl/fpu/post_norm.v
new file mode 100644
index 0000000..ff9cf6f
--- /dev/null
+++ b/verilog/rtl/fpu/post_norm.v
@@ -0,0 +1,676 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Post Norm                                                  ////
+////  Floating Point Post Normalisation Unit                     ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+
+`timescale 1ns / 100ps
+
+module post_norm( clk, fpu_op, opas, sign, rmode, fract_in, exp_in, exp_ovf,
+		opa_dn, opb_dn, rem_00, div_opa_ldz, output_zero, out,
+		ine, overflow, underflow, f2i_out_sign);
+input		clk;
+input	[2:0]	fpu_op;
+input		opas;
+input		sign;
+input	[1:0]	rmode;
+input	[47:0]	fract_in;
+input	[1:0]	exp_ovf;
+input	[7:0]	exp_in;
+input		opa_dn, opb_dn;
+input		rem_00;
+input	[4:0]	div_opa_ldz;
+input		output_zero;
+output	[30:0]	out;
+output		ine;
+output		overflow, underflow;
+output		f2i_out_sign;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+wire	[22:0]	fract_out;
+wire	[7:0]	exp_out;
+wire	[30:0]	out;
+wire		exp_out1_co, overflow, underflow;
+wire	[22:0]	fract_out_final;
+reg	[22:0]	fract_out_rnd;
+wire	[8:0]	exp_next_mi;
+wire		dn;
+wire		exp_rnd_adj;
+wire	[7:0]	exp_out_final;
+reg	[7:0]	exp_out_rnd;
+wire		op_dn = opa_dn | opb_dn;
+wire		op_mul = fpu_op[2:0]==3'b010;
+wire		op_div = fpu_op[2:0]==3'b011;
+wire		op_i2f = fpu_op[2:0]==3'b100;
+wire		op_f2i = fpu_op[2:0]==3'b101;
+reg	[5:0]	fi_ldz;
+
+wire		g, r, s;
+wire		round, round2, round2a, round2_fasu, round2_fmul;
+wire	[7:0]	exp_out_rnd0, exp_out_rnd1, exp_out_rnd2, exp_out_rnd2a;
+wire	[22:0]	fract_out_rnd0, fract_out_rnd1, fract_out_rnd2, fract_out_rnd2a;
+wire		exp_rnd_adj0, exp_rnd_adj2a;
+wire		r_sign;
+wire		ovf0, ovf1;
+wire	[23:0]	fract_out_pl1;
+wire	[7:0]	exp_out_pl1, exp_out_mi1;
+wire		exp_out_00, exp_out_fe, exp_out_ff, exp_in_00, exp_in_ff;
+wire		exp_out_final_ff, fract_out_7fffff;
+wire	[24:0]	fract_trunc;
+wire	[7:0]	exp_out1;
+wire		grs_sel;
+wire		fract_out_00, fract_in_00;
+wire		shft_co;
+wire	[8:0]	exp_in_pl1, exp_in_mi1;
+wire	[47:0]	fract_in_shftr;
+wire	[47:0]	fract_in_shftl;
+
+wire	[7:0]	exp_div;
+wire	[7:0]	shft2;
+wire	[7:0]	exp_out1_mi1;
+wire		div_dn;
+wire		div_nr;
+wire		grs_sel_div;
+
+wire		div_inf;
+wire	[6:0]	fi_ldz_2a;
+wire	[7:0]	fi_ldz_2;
+wire	[7:0]	div_shft1, div_shft2, div_shft3, div_shft4;
+wire		div_shft1_co;
+wire	[8:0]	div_exp1;
+wire	[7:0]	div_exp2, div_exp3;
+wire		left_right, lr_mul, lr_div;
+wire	[7:0]	shift_right, shftr_mul, shftr_div;
+wire	[7:0]	shift_left,  shftl_mul, shftl_div;
+wire	[7:0]	fasu_shift;
+wire	[7:0]	exp_fix_div;
+
+wire	[7:0]	exp_fix_diva, exp_fix_divb;
+wire	[5:0]	fi_ldz_mi1;
+wire	[5:0]	fi_ldz_mi22;
+wire		exp_zero;
+wire	[6:0]	ldz_all;
+wire	[7:0]	ldz_dif;
+
+wire	[8:0]	div_scht1a;
+wire	[7:0]	f2i_shft;
+wire	[55:0]	exp_f2i_1;
+wire		f2i_zero, f2i_max;
+wire	[7:0]	f2i_emin;
+wire	[7:0]	conv_shft;
+wire	[7:0]	exp_i2f, exp_f2i, conv_exp;
+wire		round2_f2i;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Normalize and Round Logic
+//
+
+// ---------------------------------------------------------------------
+// Count Leading zeros in fraction
+
+always @(fract_in)
+   casex(fract_in)	// synopsys full_case parallel_case
+	48'b1???????????????????????????????????????????????: fi_ldz =  1;
+	48'b01??????????????????????????????????????????????: fi_ldz =  2;
+	48'b001?????????????????????????????????????????????: fi_ldz =  3;
+	48'b0001????????????????????????????????????????????: fi_ldz =  4;
+	48'b00001???????????????????????????????????????????: fi_ldz =  5;
+	48'b000001??????????????????????????????????????????: fi_ldz =  6;
+	48'b0000001?????????????????????????????????????????: fi_ldz =  7;
+	48'b00000001????????????????????????????????????????: fi_ldz =  8;
+	48'b000000001???????????????????????????????????????: fi_ldz =  9;
+	48'b0000000001??????????????????????????????????????: fi_ldz =  10;
+	48'b00000000001?????????????????????????????????????: fi_ldz =  11;
+	48'b000000000001????????????????????????????????????: fi_ldz =  12;
+	48'b0000000000001???????????????????????????????????: fi_ldz =  13;
+	48'b00000000000001??????????????????????????????????: fi_ldz =  14;
+	48'b000000000000001?????????????????????????????????: fi_ldz =  15;
+	48'b0000000000000001????????????????????????????????: fi_ldz =  16;
+	48'b00000000000000001???????????????????????????????: fi_ldz =  17;
+	48'b000000000000000001??????????????????????????????: fi_ldz =  18;
+	48'b0000000000000000001?????????????????????????????: fi_ldz =  19;
+	48'b00000000000000000001????????????????????????????: fi_ldz =  20;
+	48'b000000000000000000001???????????????????????????: fi_ldz =  21;
+	48'b0000000000000000000001??????????????????????????: fi_ldz =  22;
+	48'b00000000000000000000001?????????????????????????: fi_ldz =  23;
+	48'b000000000000000000000001????????????????????????: fi_ldz =  24;
+	48'b0000000000000000000000001???????????????????????: fi_ldz =  25;
+	48'b00000000000000000000000001??????????????????????: fi_ldz =  26;
+	48'b000000000000000000000000001?????????????????????: fi_ldz =  27;
+	48'b0000000000000000000000000001????????????????????: fi_ldz =  28;
+	48'b00000000000000000000000000001???????????????????: fi_ldz =  29;
+	48'b000000000000000000000000000001??????????????????: fi_ldz =  30;
+	48'b0000000000000000000000000000001?????????????????: fi_ldz =  31;
+	48'b00000000000000000000000000000001????????????????: fi_ldz =  32;
+	48'b000000000000000000000000000000001???????????????: fi_ldz =  33;
+	48'b0000000000000000000000000000000001??????????????: fi_ldz =  34;
+	48'b00000000000000000000000000000000001?????????????: fi_ldz =  35;
+	48'b000000000000000000000000000000000001????????????: fi_ldz =  36;
+	48'b0000000000000000000000000000000000001???????????: fi_ldz =  37;
+	48'b00000000000000000000000000000000000001??????????: fi_ldz =  38;
+	48'b000000000000000000000000000000000000001?????????: fi_ldz =  39;
+	48'b0000000000000000000000000000000000000001????????: fi_ldz =  40;
+	48'b00000000000000000000000000000000000000001???????: fi_ldz =  41;
+	48'b000000000000000000000000000000000000000001??????: fi_ldz =  42;
+	48'b0000000000000000000000000000000000000000001?????: fi_ldz =  43;
+	48'b00000000000000000000000000000000000000000001????: fi_ldz =  44;
+	48'b000000000000000000000000000000000000000000001???: fi_ldz =  45;
+	48'b0000000000000000000000000000000000000000000001??: fi_ldz =  46;
+	48'b00000000000000000000000000000000000000000000001?: fi_ldz =  47;
+	48'b00000000000000000000000000000000000000000000000?: fi_ldz =  48;
+   endcase
+
+
+// ---------------------------------------------------------------------
+// Normalize
+
+wire		exp_in_80;
+wire		rmode_00, rmode_01, rmode_10, rmode_11;
+
+// Misc common signals
+assign exp_in_ff        = &exp_in;
+assign exp_in_00        = !(|exp_in);
+assign exp_in_80	= exp_in[7] & !(|exp_in[6:0]);
+assign exp_out_ff       = &exp_out;
+assign exp_out_00       = !(|exp_out);
+assign exp_out_fe       = &exp_out[7:1] & !exp_out[0];
+assign exp_out_final_ff = &exp_out_final;
+
+assign fract_out_7fffff = &fract_out;
+assign fract_out_00     = !(|fract_out);
+assign fract_in_00      = !(|fract_in);
+
+assign rmode_00 = (rmode==2'b00);
+assign rmode_01 = (rmode==2'b01);
+assign rmode_10 = (rmode==2'b10);
+assign rmode_11 = (rmode==2'b11);
+
+// Fasu Output will be denormalized ...
+assign dn = !op_mul & !op_div & (exp_in_00 | (exp_next_mi[8] & !fract_in[47]) );
+
+// ---------------------------------------------------------------------
+// Fraction Normalization
+parameter	f2i_emax = 8'h9d;
+
+// Incremented fraction for rounding
+assign fract_out_pl1 = fract_out + 1;
+
+// Special Signals for f2i
+assign f2i_emin = rmode_00 ? 8'h7e : 8'h7f;
+assign f2i_zero = (!opas & (exp_in<f2i_emin)) | (opas & (exp_in>f2i_emax)) | (opas & (exp_in<f2i_emin) & (fract_in_00 | !rmode_11));
+assign f2i_max = (!opas & (exp_in>f2i_emax)) | (opas & (exp_in<f2i_emin) & !fract_in_00 & rmode_11);
+
+// Claculate various shifting options
+
+assign {shft_co,shftr_mul} = (!exp_ovf[1] & exp_in_00) ? {1'b0, exp_out} : exp_in_mi1 ;
+assign {div_shft1_co, div_shft1} = exp_in_00 ? {1'b0, div_opa_ldz} : div_scht1a;
+
+assign div_scht1a = exp_in-div_opa_ldz; // 9 bits - includes carry out
+assign div_shft2  = exp_in+2;
+assign div_shft3  = div_opa_ldz+exp_in;
+assign div_shft4  = div_opa_ldz-exp_in;
+
+assign div_dn    = op_dn & div_shft1_co;
+assign div_nr    = op_dn & exp_ovf[1]  & !(|fract_in[46:23]) & (div_shft3>8'h16);
+
+assign f2i_shft  = exp_in-8'h7d;
+
+// Select shifting direction
+assign left_right = op_div ? lr_div : op_mul ? lr_mul : 1;
+
+assign lr_div = 	(op_dn & !exp_ovf[1] & exp_ovf[0])     ? 1 :
+			(op_dn & exp_ovf[1])                   ? 0 :
+			(op_dn & div_shft1_co)                 ? 0 :
+			(op_dn & exp_out_00)                   ? 1 :
+			(!op_dn & exp_out_00 & !exp_ovf[1])    ? 1 :
+			exp_ovf[1]                             ? 0 :
+			                                         1;
+assign lr_mul = 	(shft_co | (!exp_ovf[1] & exp_in_00) |
+			(!exp_ovf[1] & !exp_in_00 & (exp_out1_co | exp_out_00) )) ? 	1 :
+			( exp_ovf[1] | exp_in_00 ) ?					0 :
+											1;
+
+// Select Left and Right shift value
+assign fasu_shift  = (dn | exp_out_00) ? (exp_in_00 ? 8'h2 : exp_in_pl1[7:0]) : {2'h0, fi_ldz};
+assign shift_right = op_div ? shftr_div : shftr_mul;
+
+assign conv_shft = op_f2i ? f2i_shft : {2'h0, fi_ldz};
+
+assign shift_left  = op_div ? shftl_div : op_mul ? shftl_mul : (op_f2i | op_i2f) ? conv_shft : fasu_shift;
+
+assign shftl_mul = 	(shft_co |
+			(!exp_ovf[1] & exp_in_00) |
+			(!exp_ovf[1] & !exp_in_00 & (exp_out1_co | exp_out_00))) ? exp_in_pl1[7:0] : {2'h0, fi_ldz};
+
+assign shftl_div = 	( op_dn & exp_out_00 & !(!exp_ovf[1] & exp_ovf[0]))	? div_shft1[7:0] :
+			(!op_dn & exp_out_00 & !exp_ovf[1])    			? exp_in[7:0] :
+			                                        		 {2'h0, fi_ldz};
+assign shftr_div = 	(op_dn & exp_ovf[1])                   ? div_shft3 :
+			(op_dn & div_shft1_co)                 ? div_shft4 :
+								 div_shft2;
+// Do the actual shifting
+assign fract_in_shftr   = (|shift_right[7:6])                      ? 0 : fract_in>>shift_right[5:0];
+assign fract_in_shftl   = (|shift_left[7:6] | (f2i_zero & op_f2i)) ? 0 : fract_in<<shift_left[5:0];
+
+// Chose final fraction output
+assign {fract_out,fract_trunc} = left_right ? fract_in_shftl : fract_in_shftr;
+
+// ---------------------------------------------------------------------
+// Exponent Normalization
+
+assign fi_ldz_mi1    = fi_ldz - 1;
+assign fi_ldz_mi22   = fi_ldz - 22;
+assign exp_out_pl1   = exp_out + 1;
+assign exp_out_mi1   = exp_out - 1;
+assign exp_in_pl1    = exp_in  + 1;	// 9 bits - includes carry out
+assign exp_in_mi1    = exp_in  - 1;	// 9 bits - includes carry out
+assign exp_out1_mi1  = exp_out1 - 1;
+
+assign exp_next_mi  = exp_in_pl1 - fi_ldz_mi1;	// 9 bits - includes carry out
+
+assign exp_fix_diva = exp_in - fi_ldz_mi22;
+assign exp_fix_divb = exp_in - fi_ldz_mi1;
+
+assign exp_zero  = (exp_ovf[1] & !exp_ovf[0] & op_mul & (!exp_rnd_adj2a | !rmode[1])) | (op_mul & exp_out1_co);
+assign {exp_out1_co, exp_out1} = fract_in[47] ? exp_in_pl1 : exp_next_mi;
+
+assign f2i_out_sign =  !opas ? ((exp_in<f2i_emin) ? 0 : (exp_in>f2i_emax) ? 0 : opas) :
+			       ((exp_in<f2i_emin) ? 0 : (exp_in>f2i_emax) ? 1 : opas);
+
+assign exp_i2f   = fract_in_00 ? (opas ? 8'h9e : 0) : (8'h9e-fi_ldz);
+assign exp_f2i_1 = {{8{fract_in[47]}}, fract_in }<<f2i_shft;
+assign exp_f2i   = f2i_zero ? 0 : f2i_max ? 8'hff : exp_f2i_1[55:48];
+assign conv_exp  = op_f2i ? exp_f2i : exp_i2f;
+
+assign exp_out = op_div ? exp_div : (op_f2i | op_i2f) ? conv_exp : exp_zero ? 8'h0 : dn ? {6'h0, fract_in[47:46]} : exp_out1;
+
+assign ldz_all   = div_opa_ldz + fi_ldz;
+assign ldz_dif   = fi_ldz_2 - div_opa_ldz;
+assign fi_ldz_2a = 6'd23 - fi_ldz;
+assign fi_ldz_2  = {fi_ldz_2a[6], fi_ldz_2a[6:0]};
+
+assign div_exp1  = exp_in_mi1 + fi_ldz_2;	// 9 bits - includes carry out
+
+assign div_exp2  = exp_in_pl1 - ldz_all;
+assign div_exp3  = exp_in + ldz_dif;
+
+assign exp_div =(opa_dn & opb_dn)					? div_exp3 :
+		 opb_dn							? div_exp1[7:0] :
+		(opa_dn & !( (exp_in<div_opa_ldz) | (div_exp2>9'hfe) ))	? div_exp2 :
+		(opa_dn | (exp_in_00 & !exp_ovf[1]) )			? 0 :
+									  exp_out1_mi1;
+
+assign div_inf = opb_dn & !opa_dn & (div_exp1[7:0] < 8'h7f);
+
+// ---------------------------------------------------------------------
+// Round
+
+// Extract rounding (GRS) bits
+assign grs_sel_div = op_div & (exp_ovf[1] | div_dn | exp_out1_co | exp_out_00);
+
+assign g = grs_sel_div ? fract_out[0]                   : fract_out[0];
+assign r = grs_sel_div ? (fract_trunc[24] & !div_nr)    : fract_trunc[24];
+assign s = grs_sel_div ? |fract_trunc[24:0]             : (|fract_trunc[23:0] | (fract_trunc[24] & op_div));
+
+// Round to nearest even
+assign round = (g & r) | (r & s) ;
+assign {exp_rnd_adj0, fract_out_rnd0} = round ? fract_out_pl1 : {1'b0, fract_out};
+assign exp_out_rnd0 =  exp_rnd_adj0 ? exp_out_pl1 : exp_out;
+assign ovf0 = exp_out_final_ff & !rmode_01 & !op_f2i;
+
+// round to zero
+assign fract_out_rnd1 = (exp_out_ff & !op_div & !dn & !op_f2i) ? 23'h7fffff : fract_out;
+assign exp_fix_div    = (fi_ldz>22) ? exp_fix_diva : exp_fix_divb;
+assign exp_out_rnd1   = (g & r & s & exp_in_ff) ? (op_div ? exp_fix_div : exp_next_mi[7:0]) :
+			(exp_out_ff & !op_f2i) ? exp_in : exp_out;
+assign ovf1 = exp_out_ff & !dn;
+
+// round to +inf (UP) and -inf (DOWN)
+assign r_sign = sign;
+
+assign round2a = !exp_out_fe | !fract_out_7fffff | (exp_out_fe & fract_out_7fffff);
+assign round2_fasu = ((r | s) & !r_sign) & (!exp_out[7] | (exp_out[7] & round2a));
+
+assign round2_fmul = !r_sign & 
+		(
+			(exp_ovf[1] & !fract_in_00 &
+				( ((!exp_out1_co | op_dn) & (r | s | (!rem_00 & op_div) )) | fract_out_00 | (!op_dn & !op_div))
+			 ) |
+			(
+				(r | s | (!rem_00 & op_div)) & (
+						(!exp_ovf[1] & (exp_in_80 | !exp_ovf[0])) | op_div |
+						( exp_ovf[1] & !exp_ovf[0] & exp_out1_co)
+					)
+			)
+		);
+
+assign round2_f2i = rmode_10 & (( |fract_in[23:0] & !opas & (exp_in<8'h80 )) | (|fract_trunc));
+assign round2 = (op_mul | op_div) ? round2_fmul : op_f2i ? round2_f2i : round2_fasu;
+
+assign {exp_rnd_adj2a, fract_out_rnd2a} = round2 ? fract_out_pl1 : {1'b0, fract_out};
+assign exp_out_rnd2a  = exp_rnd_adj2a ? ((exp_ovf[1] & op_mul) ? exp_out_mi1 : exp_out_pl1) : exp_out;
+
+assign fract_out_rnd2 = (r_sign & exp_out_ff & !op_div & !dn & !op_f2i) ? 23'h7fffff : fract_out_rnd2a;
+assign exp_out_rnd2   = (r_sign & exp_out_ff & !op_f2i) ? 8'hfe      : exp_out_rnd2a;
+
+
+// Choose rounding mode
+always @(rmode or exp_out_rnd0 or exp_out_rnd1 or exp_out_rnd2)
+	case(rmode)	// synopsys full_case parallel_case
+	   0: exp_out_rnd = exp_out_rnd0;
+	   1: exp_out_rnd = exp_out_rnd1;
+	 2,3: exp_out_rnd = exp_out_rnd2;
+	endcase
+
+always @(rmode or fract_out_rnd0 or fract_out_rnd1 or fract_out_rnd2)
+	case(rmode)	// synopsys full_case parallel_case
+	   0: fract_out_rnd = fract_out_rnd0;
+	   1: fract_out_rnd = fract_out_rnd1;
+	 2,3: fract_out_rnd = fract_out_rnd2;
+	endcase
+
+// ---------------------------------------------------------------------
+// Final Output Mux
+// Fix Output for denormalized and special numbers
+wire	max_num, inf_out;
+
+assign	max_num =  ( !rmode_00 & (op_mul | op_div ) & (
+							  ( exp_ovf[1] &  exp_ovf[0]) |
+							  (!exp_ovf[1] & !exp_ovf[0] & exp_in_ff & (fi_ldz_2<24) & (exp_out!=8'hfe) )
+							  )
+		   ) |
+
+		   ( op_div & (
+				   ( rmode_01 & ( div_inf |
+							 (exp_out_ff & !exp_ovf[1] ) |
+							 (exp_ovf[1] &  exp_ovf[0] )
+						)
+				   ) |
+		
+				   ( rmode[1] & !exp_ovf[1] & (
+								   ( exp_ovf[0] & exp_in_ff & r_sign & fract_in[47]
+								   ) |
+						
+								   (  r_sign & (
+										(fract_in[47] & div_inf) |
+										(exp_in[7] & !exp_out_rnd[7] & !exp_in_80 & exp_out!=8'h7f ) |
+										(exp_in[7] &  exp_out_rnd[7] & r_sign & exp_out_ff & op_dn &
+											 div_exp1>9'h0fe )
+										)
+								   ) |
+
+								   ( exp_in_00 & r_sign & (
+												div_inf |
+												(r_sign & exp_out_ff & fi_ldz_2<24)
+											  )
+								   )
+							       )
+				  )
+			    )
+		   );
+
+
+assign inf_out = (rmode[1] & (op_mul | op_div) & !r_sign & (	(exp_in_ff & !op_div) |
+								(exp_ovf[1] & exp_ovf[0] & (exp_in_00 | exp_in[7]) ) 
+							   )
+		) | (div_inf & op_div & (
+				 rmode_00 |
+				(rmode[1] & !exp_in_ff & !exp_ovf[1] & !exp_ovf[0] & !r_sign ) |
+				(rmode[1] & !exp_ovf[1] & exp_ovf[0] & exp_in_00 & !r_sign)
+				)
+		) | (op_div & rmode[1] & exp_in_ff & op_dn & !r_sign & (fi_ldz_2 < 24)  & (exp_out_rnd!=8'hfe) );
+
+assign fract_out_final =	(inf_out | ovf0 | output_zero ) ? 23'h0 :
+				(max_num | (f2i_max & op_f2i) ) ? 23'h7fffff :
+				fract_out_rnd;
+
+assign exp_out_final =	((op_div & exp_ovf[1] & !exp_ovf[0]) | output_zero ) ? 8'h00 :
+			((op_div & exp_ovf[1] &  exp_ovf[0] & rmode_00) | inf_out | (f2i_max & op_f2i) ) ? 8'hff :
+			max_num ? 8'hfe :
+			exp_out_rnd;
+
+
+// ---------------------------------------------------------------------
+// Pack Result
+
+assign out = {exp_out_final, fract_out_final};
+
+// ---------------------------------------------------------------------
+// Exceptions
+wire		underflow_fmul;
+wire		overflow_fdiv;
+wire		undeflow_div;
+
+wire		z =	shft_co | ( exp_ovf[1] |  exp_in_00) |
+			(!exp_ovf[1] & !exp_in_00 & (exp_out1_co | exp_out_00));
+
+assign underflow_fmul = ( (|fract_trunc) & z & !exp_in_ff ) |
+			(fract_out_00 & !fract_in_00 & exp_ovf[1]);
+
+assign undeflow_div =	!(exp_ovf[1] &  exp_ovf[0] & rmode_00) & !inf_out & !max_num & exp_out_final!=8'hff & (
+
+			((|fract_trunc) & !opb_dn & (
+							( op_dn & !exp_ovf[1] & exp_ovf[0])	|
+							( op_dn &  exp_ovf[1])			|
+							( op_dn &  div_shft1_co)		| 
+							  exp_out_00				|
+							  exp_ovf[1]
+						  )
+
+			) |
+
+			( exp_ovf[1] & !exp_ovf[0] & (
+							(  op_dn & exp_in>8'h16 & fi_ldz<23) |
+							(  op_dn & exp_in<23 & fi_ldz<23 & !rem_00) |
+							( !op_dn & (exp_in[7]==exp_div[7]) & !rem_00) |
+							( !op_dn & exp_in_00 & (exp_div[7:1]==7'h7f) ) |
+							( !op_dn & exp_in<8'h7f & exp_in>8'h20 )
+							)
+			) |
+
+			(!exp_ovf[1] & !exp_ovf[0] & (
+							( op_dn & fi_ldz<23 & exp_out_00) |
+							( exp_in_00 & !rem_00) |
+							( !op_dn & ldz_all<23 & exp_in==1 & exp_out_00 & !rem_00)
+							)
+			)
+
+			);
+
+assign underflow = op_div ? undeflow_div : op_mul ? underflow_fmul : (!fract_in[47] & exp_out1_co) & !dn;
+
+assign overflow_fdiv =	inf_out |
+			(!rmode_00 & max_num) |
+			(exp_in[7] & op_dn & exp_out_ff) |
+			(exp_ovf[0] & (exp_ovf[1] | exp_out_ff) );
+
+assign overflow  = op_div ? overflow_fdiv : (ovf0 | ovf1);
+
+wire		f2i_ine;
+
+assign f2i_ine =	(f2i_zero & !fract_in_00 & !opas) |
+			(|fract_trunc) |
+			(f2i_zero & (exp_in<8'h80) & opas & !fract_in_00) |
+			(f2i_max & rmode_11 & (exp_in<8'h80));
+
+
+
+assign ine =	op_f2i ? f2i_ine :
+		op_i2f ? (|fract_trunc) :
+		((r & !dn) | (s & !dn) | max_num | (op_div & !rem_00));
+
+// ---------------------------------------------------------------------
+// Debugging Stuff
+
+// synopsys translate_off
+
+wire	[26:0]	fracta_del, fractb_del;
+wire	[2:0]	grs_del;
+wire		dn_del;
+wire	[7:0]	exp_in_del;
+wire	[7:0]	exp_out_del;
+wire	[22:0]	fract_out_del;
+wire	[47:0]	fract_in_del;
+wire		overflow_del;
+wire	[1:0]	exp_ovf_del;
+wire	[22:0]	fract_out_x_del, fract_out_rnd2a_del;
+wire	[24:0]	trunc_xx_del;
+wire		exp_rnd_adj2a_del;
+wire	[22:0]	fract_dn_del;
+wire	[4:0]	div_opa_ldz_del;
+wire	[23:0]	fracta_div_del;
+wire	[23:0]	fractb_div_del;
+wire		div_inf_del;
+wire	[7:0]	fi_ldz_2_del;
+wire		inf_out_del, max_out_del;
+wire	[5:0]	fi_ldz_del;
+wire		rx_del;
+wire		ez_del;
+wire		lr;
+wire	[7:0]	shr, shl, exp_div_del;
+
+delay2 #26 ud000(clk, test.u0.fracta, fracta_del);
+delay2 #26 ud001(clk, test.u0.fractb, fractb_del);
+delay1  #2 ud002(clk, {g,r,s}, grs_del);
+delay1  #0 ud004(clk, dn, dn_del);
+delay1  #7 ud005(clk, exp_in, exp_in_del);
+delay1  #7 ud007(clk, exp_out_rnd, exp_out_del);
+delay1 #47 ud009(clk, fract_in, fract_in_del);
+delay1  #0 ud010(clk, overflow, overflow_del);
+delay1  #1 ud011(clk, exp_ovf, exp_ovf_del);
+delay1 #22 ud014(clk, fract_out, fract_out_x_del);
+delay1 #24 ud015(clk, fract_trunc, trunc_xx_del);
+delay1 	#0 ud017(clk, exp_rnd_adj2a, exp_rnd_adj2a_del);
+delay1  #4 ud019(clk, div_opa_ldz, div_opa_ldz_del);
+delay3 #23 ud020(clk, test.u0.fdiv_opa[49:26],	fracta_div_del);
+delay3 #23 ud021(clk, test.u0.fractb_mul,	fractb_div_del);
+delay1 	#0 ud023(clk, div_inf, div_inf_del);
+delay1  #7 ud024(clk, fi_ldz_2, fi_ldz_2_del);
+delay1 	#0 ud025(clk, inf_out, inf_out_del);
+delay1 	#0 ud026(clk, max_num, max_num_del);
+delay1 	#5 ud027(clk, fi_ldz, fi_ldz_del);
+delay1  #0 ud028(clk, rem_00, rx_del);
+
+delay1  #0 ud029(clk, left_right, lr);
+delay1  #7 ud030(clk, shift_right, shr);
+delay1  #7 ud031(clk, shift_left, shl);
+delay1 #22 ud032(clk, fract_out_rnd2a, fract_out_rnd2a_del);
+
+delay1  #7 ud033(clk, exp_div, exp_div_del);
+
+always @(test.error_event)
+   begin
+
+	$display("\n----------------------------------------------");
+
+	$display("ERROR: GRS: %b exp_ovf: %b dn: %h exp_in: %h exp_out: %h, exp_rnd_adj2a: %b",
+			grs_del, exp_ovf_del, dn_del, exp_in_del, exp_out_del, exp_rnd_adj2a_del);
+
+	$display("      div_opa: %b, div_opb: %b, rem_00: %b, exp_div: %h",
+			fracta_div_del, fractb_div_del, rx_del, exp_div_del);
+
+	$display("      lr: %b, shl: %h, shr: %h",
+			lr, shl, shr);
+
+
+	$display("       overflow: %b, fract_in=%b  fa:%h fb:%h",
+			overflow_del, fract_in_del, fracta_del, fractb_del);
+
+	$display("       div_opa_ldz: %h, div_inf: %b, inf_out: %b, max_num: %b, fi_ldz: %h, fi_ldz_2: %h",
+			div_opa_ldz_del, div_inf_del, inf_out_del, max_num_del, fi_ldz_del, fi_ldz_2_del);
+
+	$display("       fract_out_x: %b, fract_out_rnd2a_del: %h, fract_trunc: %b\n",
+			fract_out_x_del, fract_out_rnd2a_del, trunc_xx_del);
+   end
+
+
+// synopsys translate_on
+
+endmodule
+
+// synopsys translate_off
+
+module delay1(clk, in, out);
+parameter	N = 1;
+input	[N:0]	in;
+output	[N:0]	out;
+input		clk;
+
+reg	[N:0]	out;
+
+always @(posedge clk)
+	out <= #1 in;
+
+endmodule
+
+
+module delay2(clk, in, out);
+parameter	N = 1;
+input	[N:0]	in;
+output	[N:0]	out;
+input		clk;
+
+reg	[N:0]	out, r1;
+
+always @(posedge clk)
+	r1 <= #1 in;
+
+always @(posedge clk)
+	out <= #1 r1;
+
+endmodule
+
+module delay3(clk, in, out);
+parameter	N = 1;
+input	[N:0]	in;
+output	[N:0]	out;
+input		clk;
+
+reg	[N:0]	out, r1, r2;
+
+always @(posedge clk)
+	r1 <= #1 in;
+
+always @(posedge clk)
+	r2 <= #1 r1;
+
+always @(posedge clk)
+	out <= #1 r2;
+
+endmodule
+
+// synopsys translate_on
\ No newline at end of file
diff --git a/verilog/rtl/fpu/pre_norm.v b/verilog/rtl/fpu/pre_norm.v
new file mode 100644
index 0000000..c54c71f
--- /dev/null
+++ b/verilog/rtl/fpu/pre_norm.v
@@ -0,0 +1,270 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Pre Normalize                                              ////
+////  Pre Normalization Unit for Add/Sub Operations              ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+`timescale 1ns / 100ps
+
+
+module pre_norm(clk, rmode, add, opa, opb, opa_nan, opb_nan, fracta_out,
+		fractb_out, exp_dn_out, sign, nan_sign, result_zero_sign,
+		fasu_op);
+input		clk;
+input	[1:0]	rmode;
+input		add;
+input	[31:0]	opa, opb;
+input		opa_nan, opb_nan;
+output	[26:0]	fracta_out, fractb_out;
+output	[7:0]	exp_dn_out;
+output		sign;
+output		nan_sign, result_zero_sign;
+output		fasu_op;			// Operation Output
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+wire		signa, signb;		// alias to opX sign
+wire	[7:0]	expa, expb;		// alias to opX exponent
+wire	[22:0]	fracta, fractb;		// alias to opX fraction
+wire		expa_lt_expb;		// expa is larger than expb indicator
+wire		fractb_lt_fracta;	// fractb is larger than fracta indicator
+reg	[7:0]	exp_dn_out;		// de normalized exponent output
+wire	[7:0]	exp_small, exp_large;
+wire	[7:0]	exp_diff;		// Numeric difference of the two exponents
+wire	[22:0]	adj_op;			// Fraction adjustment: input
+wire	[26:0]	adj_op_tmp;
+wire	[26:0]	adj_op_out;		// Fraction adjustment: output
+wire	[26:0]	fracta_n, fractb_n;	// Fraction selection after normalizing
+wire	[26:0]	fracta_s, fractb_s;	// Fraction Sorting out
+reg	[26:0]	fracta_out, fractb_out;	// Fraction Output
+reg		sign, sign_d;		// Sign Output
+reg		add_d;			// operation (add/sub)
+reg		fasu_op;		// operation (add/sub) register
+wire		expa_dn, expb_dn;
+reg		sticky;
+reg		result_zero_sign;
+reg		add_r, signa_r, signb_r;
+wire	[4:0]	exp_diff_sft;
+wire		exp_lt_27;
+wire		op_dn;
+wire	[26:0]	adj_op_out_sft;
+reg		fracta_lt_fractb, fracta_eq_fractb;
+wire		nan_sign1;
+reg		nan_sign;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Aliases
+//
+
+assign  signa = opa[31];
+assign  signb = opb[31];
+assign   expa = opa[30:23];
+assign   expb = opb[30:23];
+assign fracta = opa[22:0];
+assign fractb = opb[22:0];
+
+////////////////////////////////////////////////////////////////////////
+//
+// Pre-Normalize exponents (and fractions)
+//
+
+assign expa_lt_expb = expa > expb;		// expa is larger than expb
+
+// ---------------------------------------------------------------------
+// Normalize
+
+assign expa_dn = !(|expa);			// opa denormalized
+assign expb_dn = !(|expb);			// opb denormalized
+
+// ---------------------------------------------------------------------
+// Calculate the difference between the smaller and larger exponent
+
+wire	[7:0]	exp_diff1, exp_diff1a, exp_diff2;
+
+assign exp_small  = expa_lt_expb ? expb : expa;
+assign exp_large  = expa_lt_expb ? expa : expb;
+assign exp_diff1  = exp_large - exp_small;
+assign exp_diff1a = exp_diff1-1;
+assign exp_diff2  = (expa_dn | expb_dn) ? exp_diff1a : exp_diff1;
+assign  exp_diff  = (expa_dn & expb_dn) ? 8'h0 : exp_diff2;
+
+always @(posedge clk)	// If numbers are equal we should return zero
+	exp_dn_out <= #1 (!add_d & expa==expb & fracta==fractb) ? 8'h0 : exp_large;
+
+// ---------------------------------------------------------------------
+// Adjust the smaller fraction
+
+
+assign op_dn	  = expa_lt_expb ? expb_dn : expa_dn;
+assign adj_op     = expa_lt_expb ? fractb : fracta;
+assign adj_op_tmp = { ~op_dn, adj_op, 3'b0 };	// recover hidden bit (op_dn) 
+
+// adj_op_out is 27 bits wide, so can only be shifted 27 bits to the right
+assign exp_lt_27	= exp_diff  > 8'd27;
+assign exp_diff_sft	= exp_lt_27 ? 5'd27 : exp_diff[4:0];
+assign adj_op_out_sft	= adj_op_tmp >> exp_diff_sft;
+assign adj_op_out	= {adj_op_out_sft[26:1], adj_op_out_sft[0] | sticky };
+
+// ---------------------------------------------------------------------
+// Get truncated portion (sticky bit)
+
+always @(exp_diff_sft or adj_op_tmp)
+   case(exp_diff_sft)		// synopsys full_case parallel_case
+	00: sticky = 1'h0;
+	01: sticky =  adj_op_tmp[0]; 
+	02: sticky = |adj_op_tmp[01:0];
+	03: sticky = |adj_op_tmp[02:0];
+	04: sticky = |adj_op_tmp[03:0];
+	05: sticky = |adj_op_tmp[04:0];
+	06: sticky = |adj_op_tmp[05:0];
+	07: sticky = |adj_op_tmp[06:0];
+	08: sticky = |adj_op_tmp[07:0];
+	09: sticky = |adj_op_tmp[08:0];
+	10: sticky = |adj_op_tmp[09:0];
+	11: sticky = |adj_op_tmp[10:0];
+	12: sticky = |adj_op_tmp[11:0];
+	13: sticky = |adj_op_tmp[12:0];
+	14: sticky = |adj_op_tmp[13:0];
+	15: sticky = |adj_op_tmp[14:0];
+	16: sticky = |adj_op_tmp[15:0];
+	17: sticky = |adj_op_tmp[16:0];
+	18: sticky = |adj_op_tmp[17:0];
+	19: sticky = |adj_op_tmp[18:0];
+	20: sticky = |adj_op_tmp[19:0];
+	21: sticky = |adj_op_tmp[20:0];
+	22: sticky = |adj_op_tmp[21:0];
+	23: sticky = |adj_op_tmp[22:0];
+	24: sticky = |adj_op_tmp[23:0];
+	25: sticky = |adj_op_tmp[24:0];
+	26: sticky = |adj_op_tmp[25:0];
+	27: sticky = |adj_op_tmp[26:0];
+   endcase
+
+// ---------------------------------------------------------------------
+// Select operands for add/sub (recover hidden bit)
+
+assign fracta_n = expa_lt_expb ? {~expa_dn, fracta, 3'b0} : adj_op_out;
+assign fractb_n = expa_lt_expb ? adj_op_out : {~expb_dn, fractb, 3'b0};
+
+// ---------------------------------------------------------------------
+// Sort operands (for sub only)
+
+assign fractb_lt_fracta = fractb_n > fracta_n;	// fractb is larger than fracta
+assign fracta_s = fractb_lt_fracta ? fractb_n : fracta_n;
+assign fractb_s = fractb_lt_fracta ? fracta_n : fractb_n;
+
+always @(posedge clk)
+	fracta_out <= #1 fracta_s;
+
+always @(posedge clk)
+	fractb_out <= #1 fractb_s;
+
+// ---------------------------------------------------------------------
+// Determine sign for the output
+
+// sign: 0=Positive Number; 1=Negative Number
+always @(signa or signb or add or fractb_lt_fracta)
+   case({signa, signb, add})		// synopsys full_case parallel_case
+
+   	// Add
+	3'b0_0_1: sign_d = 0;
+	3'b0_1_1: sign_d = fractb_lt_fracta;
+	3'b1_0_1: sign_d = !fractb_lt_fracta;
+	3'b1_1_1: sign_d = 1;
+
+	// Sub
+	3'b0_0_0: sign_d = fractb_lt_fracta;
+	3'b0_1_0: sign_d = 0;
+	3'b1_0_0: sign_d = 1;
+	3'b1_1_0: sign_d = !fractb_lt_fracta;
+   endcase
+
+always @(posedge clk)
+	sign <= #1 sign_d;
+
+// Fix sign for ZERO result
+always @(posedge clk)
+	signa_r <= #1 signa;
+
+always @(posedge clk)
+	signb_r <= #1 signb;
+
+always @(posedge clk)
+	add_r <= #1 add;
+
+always @(posedge clk)
+	result_zero_sign <= #1	( add_r &  signa_r &  signb_r) |
+				(!add_r &  signa_r & !signb_r) |
+				( add_r & (signa_r |  signb_r) & (rmode==3)) |
+				(!add_r & (signa_r == signb_r) & (rmode==3));
+
+// Fix sign for NAN result
+always @(posedge clk)
+	fracta_lt_fractb <= #1 fracta < fractb;
+
+always @(posedge clk)
+	fracta_eq_fractb <= #1 fracta == fractb;
+
+assign nan_sign1 = fracta_eq_fractb ? (signa_r & signb_r) : fracta_lt_fractb ? signb_r : signa_r;
+
+always @(posedge clk)
+	nan_sign <= #1 (opa_nan & opb_nan) ? nan_sign1 : opb_nan ? signb_r : signa_r;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Decode Add/Sub operation
+//
+
+// add: 1=Add; 0=Subtract
+always @(signa or signb or add)
+   case({signa, signb, add})		// synopsys full_case parallel_case
+   
+   	// Add
+	3'b0_0_1: add_d = 1;
+	3'b0_1_1: add_d = 0;
+	3'b1_0_1: add_d = 0;
+	3'b1_1_1: add_d = 1;
+	
+	// Sub
+	3'b0_0_0: add_d = 0;
+	3'b0_1_0: add_d = 1;
+	3'b1_0_0: add_d = 1;
+	3'b1_1_0: add_d = 0;
+   endcase
+
+always @(posedge clk)
+	fasu_op <= #1 add_d;
+
+endmodule
diff --git a/verilog/rtl/fpu/pre_norm_fmul.v b/verilog/rtl/fpu/pre_norm_fmul.v
new file mode 100644
index 0000000..26ddfeb
--- /dev/null
+++ b/verilog/rtl/fpu/pre_norm_fmul.v
@@ -0,0 +1,150 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Pre Normalize                                              ////
+////  Floating Point Pre Normalization Unit for FMUL             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+`timescale 1ns / 100ps
+
+module pre_norm_fmul(clk, fpu_op, opa, opb, fracta, fractb, exp_out, sign,
+		sign_exe, inf, exp_ovf, underflow);
+input		clk;
+input	[2:0]	fpu_op;
+input	[31:0]	opa, opb;
+output	[23:0]	fracta, fractb;
+output	[7:0]	exp_out;
+output		sign, sign_exe;
+output		inf;
+output	[1:0]	exp_ovf;
+output	[2:0]	underflow;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Local Wires and registers
+//
+
+reg	[7:0]	exp_out;
+wire		signa, signb;
+reg		sign, sign_d;
+reg		sign_exe;
+reg		inf;
+wire	[1:0]	exp_ovf_d;
+reg	[1:0]	exp_ovf;
+wire	[7:0]	expa, expb;
+wire	[7:0]	exp_tmp1, exp_tmp2;
+wire		co1, co2;
+wire		expa_dn, expb_dn;
+wire	[7:0]	exp_out_a;
+wire		opa_00, opb_00, fracta_00, fractb_00;
+wire	[7:0]	exp_tmp3, exp_tmp4, exp_tmp5;
+wire	[2:0]	underflow_d;
+reg	[2:0]	underflow;
+wire		op_div = (fpu_op == 3'b011);
+wire	[7:0]	exp_out_mul, exp_out_div;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Aliases
+//
+
+assign  signa = opa[31];
+assign  signb = opb[31];
+assign   expa = opa[30:23];
+assign   expb = opb[30:23];
+
+////////////////////////////////////////////////////////////////////////
+//
+// Calculate Exponenet
+//
+
+assign expa_dn   = !(|expa);
+assign expb_dn   = !(|expb);
+assign opa_00    = !(|opa[30:0]);
+assign opb_00    = !(|opb[30:0]);
+assign fracta_00 = !(|opa[22:0]);
+assign fractb_00 = !(|opb[22:0]);
+
+assign fracta = {!expa_dn,opa[22:0]};	// Recover hidden bit
+assign fractb = {!expb_dn,opb[22:0]};	// Recover hidden bit
+
+assign {co1,exp_tmp1} = op_div ? (expa - expb)            : (expa + expb);
+assign {co2,exp_tmp2} = op_div ? ({co1,exp_tmp1} + 8'h7f) : ({co1,exp_tmp1} - 8'h7f);
+
+assign exp_tmp3 = exp_tmp2 + 1;
+assign exp_tmp4 = 8'h7f - exp_tmp1;
+assign exp_tmp5 = op_div ? (exp_tmp4+1) : (exp_tmp4-1);
+
+
+always@(posedge clk)
+	exp_out <= #1 op_div ? exp_out_div : exp_out_mul;
+
+assign exp_out_div = (expa_dn | expb_dn) ? (co2 ? exp_tmp5 : exp_tmp3 ) : co2 ? exp_tmp4 : exp_tmp2;
+assign exp_out_mul = exp_ovf_d[1] ? exp_out_a : (expa_dn | expb_dn) ? exp_tmp3 : exp_tmp2;
+assign exp_out_a   = (expa_dn | expb_dn) ? exp_tmp5 : exp_tmp4;
+assign exp_ovf_d[0] = op_div ? (expa[7] & !expb[7]) : (co2 & expa[7] & expb[7]);
+assign exp_ovf_d[1] = op_div ? co2                  : ((!expa[7] & !expb[7] & exp_tmp2[7]) | co2);
+
+always @(posedge clk)
+	exp_ovf <= #1 exp_ovf_d;
+
+assign underflow_d[0] =	(exp_tmp1 < 8'h7f) & !co1 & !(opa_00 | opb_00 | expa_dn | expb_dn);
+assign underflow_d[1] =	((expa[7] | expb[7]) & !opa_00 & !opb_00) |
+			 (expa_dn & !fracta_00) | (expb_dn & !fractb_00);
+assign underflow_d[2] =	 !opa_00 & !opb_00 & (exp_tmp1 == 8'h7f);
+
+always @(posedge clk)
+	underflow <= #1 underflow_d;
+
+always @(posedge clk)
+	inf <= #1 op_div ? (expb_dn & !expa[7]) : ({co1,exp_tmp1} > 9'h17e) ;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Determine sign for the output
+//
+
+// sign: 0=Posetive Number; 1=Negative Number
+always @(signa or signb)
+   case({signa, signb})		// synopsys full_case parallel_case
+	2'b0_0: sign_d = 0;
+	2'b0_1: sign_d = 1;
+	2'b1_0: sign_d = 1;
+	2'b1_1: sign_d = 0;
+   endcase
+
+always @(posedge clk)
+	sign <= #1 sign_d;
+
+always @(posedge clk)
+	sign_exe <= #1 signa & signb;
+
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/fpu/primitives.v b/verilog/rtl/fpu/primitives.v
new file mode 100644
index 0000000..2e7f050
--- /dev/null
+++ b/verilog/rtl/fpu/primitives.v
@@ -0,0 +1,103 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  Primitives                                                 ////
+////  FPU Primitives                                             ////
+////                                                             ////
+////  Author: Rudolf Usselmann                                   ////
+////          rudi@asics.ws                                      ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2000 Rudolf Usselmann                         ////
+////                    rudi@asics.ws                            ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+
+`timescale 1ns / 100ps
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Add/Sub
+//
+
+module add_sub27(add, opa, opb, sum, co);
+input		add;
+input	[26:0]	opa, opb;
+output	[26:0]	sum;
+output		co;
+
+
+
+assign {co, sum} = add ? (opa + opb) : (opa - opb);
+
+endmodule
+
+////////////////////////////////////////////////////////////////////////
+//
+// Multiply
+//
+
+module mul_r2(clk, opa, opb, prod);
+input		clk;
+input	[23:0]	opa, opb;
+output	[47:0]	prod;
+
+reg	[47:0]	prod1, prod;
+
+always @(posedge clk)
+	prod1 <= #1 opa * opb;
+
+always @(posedge clk)
+	prod <= #1 prod1;
+
+endmodule
+
+////////////////////////////////////////////////////////////////////////
+//
+// Divide
+//
+
+module div_r2(clk, opa, opb, quo, rem);
+input		clk;
+input	[49:0]	opa;
+input	[23:0]	opb;
+output	[49:0]	quo, rem;
+
+reg	[49:0]	quo, rem, quo1, remainder;
+
+always @(posedge clk)
+	quo1 <= #1 opa / opb;
+
+always @(posedge clk)
+	quo <= #1 quo1;
+
+always @(posedge clk)
+	remainder <= #1 opa % opb;
+
+always @(posedge clk)
+	rem <= #1 remainder;
+
+endmodule
+
+
diff --git a/verilog/rtl/i2c/i2c_master_bit_ctrl.v b/verilog/rtl/i2c/i2c_master_bit_ctrl.v
new file mode 100644
index 0000000..fbca97e
--- /dev/null
+++ b/verilog/rtl/i2c/i2c_master_bit_ctrl.v
@@ -0,0 +1,572 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master bit-controller        ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+//// SPDX-License-Identifier: LGPL-2.1-or-later                  ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_bit_ctrl.v,v 1.14 2009-01-20 10:25:29 rherveille Exp $
+//
+//  $Date: 2009-01-20 10:25:29 $
+//  $Revision: 1.14 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: $
+//               Revision 1.14  2009/01/20 10:25:29  rherveille
+//               Added clock synchronization logic
+//               Fixed slave_wait signal
+//
+//               Revision 1.13  2009/01/19 20:29:26  rherveille
+//               Fixed cr[0] register width
+//               Fixed ! usage instead of ~
+//               Fixed bit controller parameter width to 18bits
+//
+//               Revision 1.12  2006/09/04 09:08:13  rherveille
+//               fixed short scl high pulse after clock stretch
+//               fixed slave model not returning correct '(n)ack' signal
+//
+//               Revision 1.11  2004/05/07 11:02:26  rherveille
+//               Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit.
+//
+//               Revision 1.10  2003/08/09 07:01:33  rherveille
+//               Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
+//               Fixed a potential bug in the byte controller's host-acknowledge generation.
+//
+//               Revision 1.9  2003/03/10 14:26:37  rherveille
+//               Fixed cmd_ack generation item (no bug).
+//
+//               Revision 1.8  2003/02/05 00:06:10  rherveille
+//               Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles.
+//
+//               Revision 1.7  2002/12/26 16:05:12  rherveille
+//               Small code simplifications
+//
+//               Revision 1.6  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.5  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.4  2002/10/30 18:10:07  rherveille
+//               Fixed some reported minor start/stop generation timing issuess.
+//
+//               Revision 1.3  2002/06/15 07:37:03  rherveille
+//               Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
+//
+//               Revision 1.2  2001/11/05 11:59:25  rherveille
+//               Fixed wb_ack_o generation bug.
+//               Fixed bug in the byte_controller statemachine.
+//               Added headers.
+//
+
+//
+/////////////////////////////////////
+// Bit controller section
+/////////////////////////////////////
+//
+// Translate simple commands into SCL/SDA transitions
+// Each command has 5 states, A/B/C/D/idle
+//
+// start:	SCL	~~~~~~~~~~\____
+//	SDA	~~~~~~~~\______
+//		 x | A | B | C | D | i
+//
+// repstart	SCL	____/~~~~\___
+//	SDA	__/~~~\______
+//		 x | A | B | C | D | i
+//
+// stop	SCL	____/~~~~~~~~
+//	SDA	==\____/~~~~~
+//		 x | A | B | C | D | i
+//
+//- write	SCL	____/~~~~\____
+//	SDA	==X=========X=
+//		 x | A | B | C | D | i
+//
+//- read	SCL	____/~~~~\____
+//	SDA	XXXX=====XXXX
+//		 x | A | B | C | D | i
+//
+
+// Timing:     Normal mode      Fast mode
+///////////////////////////////////////////////////////////////////////
+// Fscl        100KHz           400KHz
+// Th_scl      4.0us            0.6us   High period of SCL
+// Tl_scl      4.7us            1.3us   Low period of SCL
+// Tsu:sta     4.7us            0.6us   setup time for a repeated start condition
+// Tsu:sto     4.0us            0.6us   setup time for a stop conditon
+// Tbuf        4.7us            1.3us   Bus free time between a stop and start condition
+//
+
+
+`include "i2c_master_defines.v"
+
+module i2c_master_bit_ctrl (
+    input             clk,      // system clock
+    input             rst,      // synchronous active high reset
+    input             nReset,   // asynchronous active low reset
+    input             ena,      // core enable signal
+
+    input      [15:0] clk_cnt,  // clock prescale value
+
+    input      [ 3:0] cmd,      // command (from byte controller)
+    output reg        cmd_ack,  // command complete acknowledge
+    output reg        busy,     // i2c bus busy
+    output reg        al,       // i2c bus arbitration lost
+
+    input             din,
+    output reg        dout,
+
+    input             scl_i,    // i2c clock line input
+    output            scl_o,    // i2c clock line output
+    output reg        scl_oen,  // i2c clock line output enable (active low)
+    input             sda_i,    // i2c data line input
+    output            sda_o,    // i2c data line output
+    output reg        sda_oen   // i2c data line output enable (active low)
+);
+
+
+    //
+    // variable declarations
+    //
+
+    reg [ 1:0] cSCL, cSDA;      // capture SCL and SDA
+    reg [ 2:0] fSCL, fSDA;      // SCL and SDA filter inputs
+    reg        sSCL, sSDA;      // filtered and synchronized SCL and SDA inputs
+    reg        dSCL, dSDA;      // delayed versions of sSCL and sSDA
+    reg        dscl_oen;        // delayed scl_oen
+    reg        sda_chk;         // check SDA output (Multi-master arbitration)
+    reg        clk_en;          // clock generation signals
+    reg        slave_wait;      // slave inserts wait states
+    reg [15:0] cnt;             // clock divider counter (synthesis)
+    reg [13:0] filter_cnt;      // clock divider for filter
+
+
+    // state machine variable
+    reg [17:0] c_state; 
+
+    //
+    // module body
+    //
+
+    // whenever the slave is not ready it can delay the cycle by pulling SCL low
+    // delay scl_oen
+    always @(posedge clk)
+      dscl_oen <= #1 scl_oen;
+
+    // slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
+    // slave_wait remains asserted until the slave releases SCL
+    always @(posedge clk or negedge nReset)
+      if (!nReset) slave_wait <= 1'b0;
+      else         slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);
+
+    // master drives SCL high, but another master pulls it low
+    // master start counting down its low cycle now (clock synchronization)
+    wire scl_sync   = dSCL & ~sSCL & scl_oen;
+
+
+    // generate clk enable signal
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+      begin
+          cnt    <= #1 16'h0;
+          clk_en <= #1 1'b1;
+      end
+      else if (rst || ~|cnt || !ena || scl_sync)
+      begin
+          cnt    <= #1 clk_cnt;
+          clk_en <= #1 1'b1;
+      end
+      else if (slave_wait)
+      begin
+          cnt    <= #1 cnt;
+          clk_en <= #1 1'b0;    
+      end
+      else
+      begin
+          cnt    <= #1 cnt - 16'h1;
+          clk_en <= #1 1'b0;
+      end
+
+
+    // generate bus status controller
+
+    // capture SDA and SCL
+    // reduce metastability risk
+    always @(posedge clk or negedge nReset)
+      if (!nReset)
+      begin
+          cSCL <= #1 2'b00;
+          cSDA <= #1 2'b00;
+      end
+      else if (rst)
+      begin
+          cSCL <= #1 2'b00;
+          cSDA <= #1 2'b00;
+      end
+      else
+      begin
+          cSCL <= {cSCL[0],scl_i};
+          cSDA <= {cSDA[0],sda_i};
+      end
+
+
+    // filter SCL and SDA signals; (attempt to) remove glitches
+    always @(posedge clk or negedge nReset)
+      if      (!nReset     ) filter_cnt <= 14'h0;
+      else if (rst || !ena ) filter_cnt <= 14'h0;
+      else if (~|filter_cnt) filter_cnt <= clk_cnt >> 2; //16x I2C bus frequency
+      else                   filter_cnt <= filter_cnt -1;
+
+
+    always @(posedge clk or negedge nReset)
+      if (!nReset)
+      begin
+          fSCL <= 3'b111;
+          fSDA <= 3'b111;
+      end
+      else if (rst)
+      begin
+          fSCL <= 3'b111;
+          fSDA <= 3'b111;
+      end
+      else if (~|filter_cnt)
+      begin
+          fSCL <= {fSCL[1:0],cSCL[1]};
+          fSDA <= {fSDA[1:0],cSDA[1]};
+      end
+
+
+    // generate filtered SCL and SDA signals
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+      begin
+          sSCL <= #1 1'b1;
+          sSDA <= #1 1'b1;
+
+          dSCL <= #1 1'b1;
+          dSDA <= #1 1'b1;
+      end
+      else if (rst)
+      begin
+          sSCL <= #1 1'b1;
+          sSDA <= #1 1'b1;
+
+          dSCL <= #1 1'b1;
+          dSDA <= #1 1'b1;
+      end
+      else
+      begin
+          sSCL <= #1 &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]);
+          sSDA <= #1 &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]);
+
+          dSCL <= #1 sSCL;
+          dSDA <= #1 sSDA;
+      end
+
+    // detect start condition => detect falling edge on SDA while SCL is high
+    // detect stop condition => detect rising edge on SDA while SCL is high
+    reg sta_condition;
+    reg sto_condition;
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+      begin
+          sta_condition <= #1 1'b0;
+          sto_condition <= #1 1'b0;
+      end
+      else if (rst)
+      begin
+          sta_condition <= #1 1'b0;
+          sto_condition <= #1 1'b0;
+      end
+      else
+      begin
+          sta_condition <= #1 ~sSDA &  dSDA & sSCL;
+          sto_condition <= #1  sSDA & ~dSDA & sSCL;
+      end
+
+
+    // generate i2c bus busy signal
+    always @(posedge clk or negedge nReset)
+      if      (!nReset) busy <= #1 1'b0;
+      else if (rst    ) busy <= #1 1'b0;
+      else              busy <= #1 (sta_condition | busy) & ~sto_condition;
+
+
+    // generate arbitration lost signal
+    // aribitration lost when:
+    // 1) master drives SDA high, but the i2c bus is low
+    // 2) stop detected while not requested
+    reg cmd_stop;
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+          cmd_stop <= #1 1'b0;
+      else if (rst)
+          cmd_stop <= #1 1'b0;
+      else if (clk_en)
+          cmd_stop <= #1 cmd == `I2C_CMD_STOP;
+
+    always @(posedge clk or negedge nReset)
+      if (~nReset)
+          al <= #1 1'b0;
+      else if (rst)
+          al <= #1 1'b0;
+      else
+          al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop);
+
+
+    // generate dout signal (store SDA on rising edge of SCL)
+    always @(posedge clk)
+      if (sSCL & ~dSCL) dout <= #1 sSDA;
+
+
+    // generate statemachine
+
+    // nxt_state decoder
+    parameter [17:0] idle    = 18'b0_0000_0000_0000_0000;
+    parameter [17:0] start_a = 18'b0_0000_0000_0000_0001;
+    parameter [17:0] start_b = 18'b0_0000_0000_0000_0010;
+    parameter [17:0] start_c = 18'b0_0000_0000_0000_0100;
+    parameter [17:0] start_d = 18'b0_0000_0000_0000_1000;
+    parameter [17:0] start_e = 18'b0_0000_0000_0001_0000;
+    parameter [17:0] stop_a  = 18'b0_0000_0000_0010_0000;
+    parameter [17:0] stop_b  = 18'b0_0000_0000_0100_0000;
+    parameter [17:0] stop_c  = 18'b0_0000_0000_1000_0000;
+    parameter [17:0] stop_d  = 18'b0_0000_0001_0000_0000;
+    parameter [17:0] rd_a    = 18'b0_0000_0010_0000_0000;
+    parameter [17:0] rd_b    = 18'b0_0000_0100_0000_0000;
+    parameter [17:0] rd_c    = 18'b0_0000_1000_0000_0000;
+    parameter [17:0] rd_d    = 18'b0_0001_0000_0000_0000;
+    parameter [17:0] wr_a    = 18'b0_0010_0000_0000_0000;
+    parameter [17:0] wr_b    = 18'b0_0100_0000_0000_0000;
+    parameter [17:0] wr_c    = 18'b0_1000_0000_0000_0000;
+    parameter [17:0] wr_d    = 18'b1_0000_0000_0000_0000;
+
+    always @(posedge clk or negedge nReset)
+      if (!nReset)
+      begin
+          c_state <= #1 idle;
+          cmd_ack <= #1 1'b0;
+          scl_oen <= #1 1'b1;
+          sda_oen <= #1 1'b1;
+          sda_chk <= #1 1'b0;
+      end
+      else if (rst | al)
+      begin
+          c_state <= #1 idle;
+          cmd_ack <= #1 1'b0;
+          scl_oen <= #1 1'b1;
+          sda_oen <= #1 1'b1;
+          sda_chk <= #1 1'b0;
+      end
+      else
+      begin
+          cmd_ack   <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle
+
+          if (clk_en)
+              case (c_state) 
+                    // idle state
+                    idle:
+                    begin
+                        case (cmd) 
+                             `I2C_CMD_START: c_state <= #1 start_a;
+                             `I2C_CMD_STOP:  c_state <= #1 stop_a;
+                             `I2C_CMD_WRITE: c_state <= #1 wr_a;
+                             `I2C_CMD_READ:  c_state <= #1 rd_a;
+                             default:        c_state <= #1 idle;
+                        endcase
+
+                        scl_oen <= #1 scl_oen; // keep SCL in same state
+                        sda_oen <= #1 sda_oen; // keep SDA in same state
+                        sda_chk <= #1 1'b0;    // don't check SDA output
+                    end
+
+                    // start
+                    start_a:
+                    begin
+                        c_state <= #1 start_b;
+                        scl_oen <= #1 scl_oen; // keep SCL in same state
+                        sda_oen <= #1 1'b1;    // set SDA high
+                        sda_chk <= #1 1'b0;    // don't check SDA output
+                    end
+
+                    start_b:
+                    begin
+                        c_state <= #1 start_c;
+                        scl_oen <= #1 1'b1; // set SCL high
+                        sda_oen <= #1 1'b1; // keep SDA high
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    start_c:
+                    begin
+                        c_state <= #1 start_d;
+                        scl_oen <= #1 1'b1; // keep SCL high
+                        sda_oen <= #1 1'b0; // set SDA low
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    start_d:
+                    begin
+                        c_state <= #1 start_e;
+                        scl_oen <= #1 1'b1; // keep SCL high
+                        sda_oen <= #1 1'b0; // keep SDA low
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    start_e:
+                    begin
+                        c_state <= #1 idle;
+                        cmd_ack <= #1 1'b1;
+                        scl_oen <= #1 1'b0; // set SCL low
+                        sda_oen <= #1 1'b0; // keep SDA low
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    // stop
+                    stop_a:
+                    begin
+                        c_state <= #1 stop_b;
+                        scl_oen <= #1 1'b0; // keep SCL low
+                        sda_oen <= #1 1'b0; // set SDA low
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    stop_b:
+                    begin
+                        c_state <= #1 stop_c;
+                        scl_oen <= #1 1'b1; // set SCL high
+                        sda_oen <= #1 1'b0; // keep SDA low
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    stop_c:
+                    begin
+                        c_state <= #1 stop_d;
+                        scl_oen <= #1 1'b1; // keep SCL high
+                        sda_oen <= #1 1'b0; // keep SDA low
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    stop_d:
+                    begin
+                        c_state <= #1 idle;
+                        cmd_ack <= #1 1'b1;
+                        scl_oen <= #1 1'b1; // keep SCL high
+                        sda_oen <= #1 1'b1; // set SDA high
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    // read
+                    rd_a:
+                    begin
+                        c_state <= #1 rd_b;
+                        scl_oen <= #1 1'b0; // keep SCL low
+                        sda_oen <= #1 1'b1; // tri-state SDA
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    rd_b:
+                    begin
+                        c_state <= #1 rd_c;
+                        scl_oen <= #1 1'b1; // set SCL high
+                        sda_oen <= #1 1'b1; // keep SDA tri-stated
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    rd_c:
+                    begin
+                        c_state <= #1 rd_d;
+                        scl_oen <= #1 1'b1; // keep SCL high
+                        sda_oen <= #1 1'b1; // keep SDA tri-stated
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    rd_d:
+                    begin
+                        c_state <= #1 idle;
+                        cmd_ack <= #1 1'b1;
+                        scl_oen <= #1 1'b0; // set SCL low
+                        sda_oen <= #1 1'b1; // keep SDA tri-stated
+                        sda_chk <= #1 1'b0; // don't check SDA output
+                    end
+
+                    // write
+                    wr_a:
+                    begin
+                        c_state <= #1 wr_b;
+                        scl_oen <= #1 1'b0; // keep SCL low
+                        sda_oen <= #1 din;  // set SDA
+                        sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
+                    end
+
+                    wr_b:
+                    begin
+                        c_state <= #1 wr_c;
+                        scl_oen <= #1 1'b1; // set SCL high
+                        sda_oen <= #1 din;  // keep SDA
+                        sda_chk <= #1 1'b0; // don't check SDA output yet
+                                            // allow some time for SDA and SCL to settle
+                    end
+
+                    wr_c:
+                    begin
+                        c_state <= #1 wr_d;
+                        scl_oen <= #1 1'b1; // keep SCL high
+                        sda_oen <= #1 din;
+                        sda_chk <= #1 1'b1; // check SDA output
+                    end
+
+                    wr_d:
+                    begin
+                        c_state <= #1 idle;
+                        cmd_ack <= #1 1'b1;
+                        scl_oen <= #1 1'b0; // set SCL low
+                        sda_oen <= #1 din;
+                        sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
+                    end
+
+              endcase
+      end
+
+
+    // assign scl and sda output (always gnd)
+    assign scl_o = 1'b0;
+    assign sda_o = 1'b0;
+
+endmodule
diff --git a/verilog/rtl/i2c/i2c_master_byte_ctrl.v b/verilog/rtl/i2c/i2c_master_byte_ctrl.v
new file mode 100644
index 0000000..16dfb82
--- /dev/null
+++ b/verilog/rtl/i2c/i2c_master_byte_ctrl.v
@@ -0,0 +1,342 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master byte-controller       ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+//// SPDX-License-Identifier: LGPL-2.1-or-later                  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_byte_ctrl.v,v 1.8 2009-01-19 20:29:26 rherveille Exp $
+//
+//  $Date: 2009-01-19 20:29:26 $
+//  $Revision: 1.8 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: not supported by cvs2svn $
+//               Revision 1.7  2004/02/18 11:40:46  rherveille
+//               Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command.
+//
+//               Revision 1.6  2003/08/09 07:01:33  rherveille
+//               Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
+//               Fixed a potential bug in the byte controller's host-acknowledge generation.
+//
+//               Revision 1.5  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.4  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.3  2001/11/05 11:59:25  rherveille
+//               Fixed wb_ack_o generation bug.
+//               Fixed bug in the byte_controller statemachine.
+//               Added headers.
+//
+
+
+`include "i2c_master_defines.v"
+
+module i2c_master_byte_ctrl (
+	clk, rst, nReset, ena, clk_cnt, start, stop, read, write, ack_in, din,
+	cmd_ack, ack_out, dout, i2c_busy, i2c_al, scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen );
+
+	//
+	// inputs & outputs
+	//
+	input clk;     // master clock
+	input rst;     // synchronous active high reset
+	input nReset;  // asynchronous active low reset
+	input ena;     // core enable signal
+
+	input [15:0] clk_cnt; // 4x SCL
+
+	// control inputs
+	input       start;
+	input       stop;
+	input       read;
+	input       write;
+	input       ack_in;
+	input [7:0] din;
+
+	// status outputs
+	output       cmd_ack;
+	reg cmd_ack;
+	output       ack_out;
+	reg ack_out;
+	output       i2c_busy;
+	output       i2c_al;
+	output [7:0] dout;
+
+	// I2C signals
+	input  scl_i;
+	output scl_o;
+	output scl_oen;
+	input  sda_i;
+	output sda_o;
+	output sda_oen;
+
+
+	//
+	// Variable declarations
+	//
+
+	// statemachine
+	parameter [4:0] ST_IDLE  = 5'b0_0000;
+	parameter [4:0] ST_START = 5'b0_0001;
+	parameter [4:0] ST_READ  = 5'b0_0010;
+	parameter [4:0] ST_WRITE = 5'b0_0100;
+	parameter [4:0] ST_ACK   = 5'b0_1000;
+	parameter [4:0] ST_STOP  = 5'b1_0000;
+
+	// signals for bit_controller
+	reg  [3:0] core_cmd;
+	reg        core_txd;
+	wire       core_ack, core_rxd;
+
+	// signals for shift register
+	reg [7:0] sr; //8bit shift register
+	reg       shift, ld;
+
+	// signals for state machine
+	wire       go;
+	reg  [2:0] dcnt;
+	wire       cnt_done;
+
+	//
+	// Module body
+	//
+
+	// hookup bit_controller
+	i2c_master_bit_ctrl bit_controller (
+		.clk     ( clk      ),
+		.rst     ( rst      ),
+		.nReset  ( nReset   ),
+		.ena     ( ena      ),
+		.clk_cnt ( clk_cnt  ),
+		.cmd     ( core_cmd ),
+		.cmd_ack ( core_ack ),
+		.busy    ( i2c_busy ),
+		.al      ( i2c_al   ),
+		.din     ( core_txd ),
+		.dout    ( core_rxd ),
+		.scl_i   ( scl_i    ),
+		.scl_o   ( scl_o    ),
+		.scl_oen ( scl_oen  ),
+		.sda_i   ( sda_i    ),
+		.sda_o   ( sda_o    ),
+		.sda_oen ( sda_oen  )
+	);
+
+	// generate go-signal
+	assign go = (read | write | stop) & ~cmd_ack;
+
+	// assign dout output to shift-register
+	assign dout = sr;
+
+	// generate shift register
+	always @(posedge clk or negedge nReset)
+	  if (!nReset)
+	    sr <= #1 8'h0;
+	  else if (rst)
+	    sr <= #1 8'h0;
+	  else if (ld)
+	    sr <= #1 din;
+	  else if (shift)
+	    sr <= #1 {sr[6:0], core_rxd};
+
+	// generate counter
+	always @(posedge clk or negedge nReset)
+	  if (!nReset)
+	    dcnt <= #1 3'h0;
+	  else if (rst)
+	    dcnt <= #1 3'h0;
+	  else if (ld)
+	    dcnt <= #1 3'h7;
+	  else if (shift)
+	    dcnt <= #1 dcnt - 3'h1;
+
+	assign cnt_done = ~(|dcnt);
+
+	//
+	// state machine
+	//
+	reg [4:0] c_state; 
+
+	always @(posedge clk or negedge nReset)
+	  if (!nReset)
+	    begin
+	        core_cmd <= #1 `I2C_CMD_NOP;
+	        core_txd <= #1 1'b0;
+	        shift    <= #1 1'b0;
+	        ld       <= #1 1'b0;
+	        cmd_ack  <= #1 1'b0;
+	        c_state  <= #1 ST_IDLE;
+	        ack_out  <= #1 1'b0;
+	    end
+	  else if (rst | i2c_al)
+	   begin
+	       core_cmd <= #1 `I2C_CMD_NOP;
+	       core_txd <= #1 1'b0;
+	       shift    <= #1 1'b0;
+	       ld       <= #1 1'b0;
+	       cmd_ack  <= #1 1'b0;
+	       c_state  <= #1 ST_IDLE;
+	       ack_out  <= #1 1'b0;
+	   end
+	else
+	  begin
+	      // initially reset all signals
+	      core_txd <= #1 sr[7];
+	      shift    <= #1 1'b0;
+	      ld       <= #1 1'b0;
+	      cmd_ack  <= #1 1'b0;
+
+	      case (c_state) 
+	        ST_IDLE:
+	          if (go)
+	            begin
+	                if (start)
+	                  begin
+	                      c_state  <= #1 ST_START;
+	                      core_cmd <= #1 `I2C_CMD_START;
+	                  end
+	                else if (read)
+	                  begin
+	                      c_state  <= #1 ST_READ;
+	                      core_cmd <= #1 `I2C_CMD_READ;
+	                  end
+	                else if (write)
+	                  begin
+	                      c_state  <= #1 ST_WRITE;
+	                      core_cmd <= #1 `I2C_CMD_WRITE;
+	                  end
+	                else // stop
+	                  begin
+	                      c_state  <= #1 ST_STOP;
+	                      core_cmd <= #1 `I2C_CMD_STOP;
+	                  end
+
+	                ld <= #1 1'b1;
+	            end
+
+	        ST_START:
+	          if (core_ack)
+	            begin
+	                if (read)
+	                  begin
+	                      c_state  <= #1 ST_READ;
+	                      core_cmd <= #1 `I2C_CMD_READ;
+	                  end
+	                else
+	                  begin
+	                      c_state  <= #1 ST_WRITE;
+	                      core_cmd <= #1 `I2C_CMD_WRITE;
+	                  end
+
+	                ld <= #1 1'b1;
+	            end
+
+	        ST_WRITE:
+	          if (core_ack)
+	            if (cnt_done)
+	              begin
+	                  c_state  <= #1 ST_ACK;
+	                  core_cmd <= #1 `I2C_CMD_READ;
+	              end
+	            else
+	              begin
+	                  c_state  <= #1 ST_WRITE;       // stay in same state
+	                  core_cmd <= #1 `I2C_CMD_WRITE; // write next bit
+	                  shift    <= #1 1'b1;
+	              end
+
+	        ST_READ:
+	          if (core_ack)
+	            begin
+	                if (cnt_done)
+	                  begin
+	                      c_state  <= #1 ST_ACK;
+	                      core_cmd <= #1 `I2C_CMD_WRITE;
+	                  end
+	                else
+	                  begin
+	                      c_state  <= #1 ST_READ;       // stay in same state
+	                      core_cmd <= #1 `I2C_CMD_READ; // read next bit
+	                  end
+
+	                shift    <= #1 1'b1;
+	                core_txd <= #1 ack_in;
+	            end
+
+	        ST_ACK:
+	          if (core_ack)
+	            begin
+	               if (stop)
+	                 begin
+	                     c_state  <= #1 ST_STOP;
+	                     core_cmd <= #1 `I2C_CMD_STOP;
+	                 end
+	               else
+	                 begin
+	                     c_state  <= #1 ST_IDLE;
+	                     core_cmd <= #1 `I2C_CMD_NOP;
+
+	                     // generate command acknowledge signal
+	                     cmd_ack  <= #1 1'b1;
+	                 end
+
+	                 // assign ack_out output to bit_controller_rxd (contains last received bit)
+	                 ack_out <= #1 core_rxd;
+
+	                 core_txd <= #1 1'b1;
+	             end
+	           else
+	             core_txd <= #1 ack_in;
+
+	        ST_STOP:
+	          if (core_ack)
+	            begin
+	                c_state  <= #1 ST_IDLE;
+	                core_cmd <= #1 `I2C_CMD_NOP;
+
+	                // generate command acknowledge signal
+	                cmd_ack  <= #1 1'b1;
+	            end
+
+	      endcase
+	  end
+endmodule
diff --git a/verilog/rtl/i2c/i2c_master_defines.v b/verilog/rtl/i2c/i2c_master_defines.v
new file mode 100644
index 0000000..0338aa0
--- /dev/null
+++ b/verilog/rtl/i2c/i2c_master_defines.v
@@ -0,0 +1,60 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE rev.B2 compliant I2C Master controller defines    ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+//// SPDX-License-Identifier: LGPL-2.1-or-later                  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_defines.v,v 1.3 2001-11-05 11:59:25 rherveille Exp $
+//
+//  $Date: 2001-11-05 11:59:25 $
+//  $Revision: 1.3 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               $Log: not supported by cvs2svn $
+
+
+// I2C registers wishbone addresses
+
+// bitcontroller states
+`define I2C_CMD_NOP   4'b0000
+`define I2C_CMD_START 4'b0001
+`define I2C_CMD_STOP  4'b0010
+`define I2C_CMD_WRITE 4'b0100
+`define I2C_CMD_READ  4'b1000
diff --git a/verilog/rtl/i2c/i2c_master_top.v b/verilog/rtl/i2c/i2c_master_top.v
new file mode 100644
index 0000000..02c8884
--- /dev/null
+++ b/verilog/rtl/i2c/i2c_master_top.v
@@ -0,0 +1,299 @@
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+////  WISHBONE revB.2 compliant I2C Master controller Top-level  ////
+////                                                             ////
+////                                                             ////
+////  Author: Richard Herveille                                  ////
+////          richard@asics.ws                                   ////
+////          www.asics.ws                                       ////
+////                                                             ////
+////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+////                                                             ////
+//// Copyright (C) 2001 Richard Herveille                        ////
+////                    richard@asics.ws                         ////
+////                                                             ////
+//// This source file may be used and distributed without        ////
+//// restriction provided that this copyright statement is not   ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+////                                                             ////
+////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
+//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
+//// POSSIBILITY OF SUCH DAMAGE.                                 ////
+//// SPDX-License-Identifier: LGPL-2.1-or-later                  ////
+////                                                             ////
+/////////////////////////////////////////////////////////////////////
+
+//  CVS Log
+//
+//  $Id: i2c_master_top.v,v 1.12 2009-01-19 20:29:26 rherveille Exp $
+//
+//  $Date: 2009-01-19 20:29:26 $
+//  $Revision: 1.12 $
+//  $Author: rherveille $
+//  $Locker:  $
+//  $State: Exp $
+//
+// Change History:
+//               Revision 1.11  2005/02/27 09:26:24  rherveille
+//               Fixed register overwrite issue.
+//               Removed full_case pragma, replaced it by a default statement.
+//
+//               Revision 1.10  2003/09/01 10:34:38  rherveille
+//               Fix a blocking vs. non-blocking error in the wb_dat output mux.
+//
+//               Revision 1.9  2003/01/09 16:44:45  rherveille
+//               Fixed a bug in the Command Register declaration.
+//
+//               Revision 1.8  2002/12/26 16:05:12  rherveille
+//               Small code simplifications
+//
+//               Revision 1.7  2002/12/26 15:02:32  rherveille
+//               Core is now a Multimaster I2C controller
+//
+//               Revision 1.6  2002/11/30 22:24:40  rherveille
+//               Cleaned up code
+//
+//               Revision 1.5  2001/11/10 10:52:55  rherveille
+//               Changed PRER reset value from 0x0000 to 0xffff, conform specs.
+//
+
+
+`include "i2c_master_defines.v"
+
+module i2c_master_top(
+	wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o,
+	wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o,
+	scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o );
+
+	// parameters
+	parameter ARST_LVL = 1'b0; // asynchronous reset level
+
+	//
+	// inputs & outputs
+	//
+
+	// wishbone signals
+	input        wb_clk_i;     // master clock input
+	input        wb_rst_i;     // synchronous active high reset
+	input        arst_i;       // asynchronous reset
+	input  [2:0] wb_adr_i;     // lower address bits
+	input  [7:0] wb_dat_i;     // databus input
+	output [7:0] wb_dat_o;     // databus output
+	input        wb_we_i;      // write enable input
+	input        wb_stb_i;     // stobe/core select signal
+	input        wb_cyc_i;     // valid bus cycle input
+	output       wb_ack_o;     // bus cycle acknowledge output
+	output       wb_inta_o;    // interrupt request signal output
+
+	reg [7:0] wb_dat_o;
+	reg wb_ack_o;
+	reg wb_inta_o;
+
+	// I2C signals
+	// i2c clock line
+	input  scl_pad_i;       // SCL-line input
+	output scl_pad_o;       // SCL-line output (always 1'b0)
+	output scl_padoen_o;    // SCL-line output enable (active low)
+
+	// i2c data line
+	input  sda_pad_i;       // SDA-line input
+	output sda_pad_o;       // SDA-line output (always 1'b0)
+	output sda_padoen_o;    // SDA-line output enable (active low)
+
+
+	//
+	// variable declarations
+	//
+
+	// registers
+	reg  [15:0] prer; // clock prescale register
+	reg  [ 7:0] ctr;  // control register
+	reg  [ 7:0] txr;  // transmit register
+	wire [ 7:0] rxr;  // receive register
+	reg  [ 7:0] cr;   // command register
+	wire [ 7:0] sr;   // status register
+
+	// done signal: command completed, clear command register
+	wire done;
+
+	// core enable signal
+	wire core_en;
+	wire ien;
+
+	// status register signals
+	wire irxack;
+	reg  rxack;       // received aknowledge from slave
+	reg  tip;         // transfer in progress
+	reg  irq_flag;    // interrupt pending flag
+	wire i2c_busy;    // bus busy (start signal detected)
+	wire i2c_al;      // i2c bus arbitration lost
+	reg  al;          // status register arbitration lost bit
+
+	//
+	// module body
+	//
+
+	// generate internal reset
+	wire rst_i = arst_i ^ ARST_LVL;
+
+	// generate wishbone signals
+	//wire wb_wacc = wb_we_i & wb_ack_o;
+	wire wb_wacc = wb_we_i & wb_stb_i & wb_cyc_i ;
+
+	// generate acknowledge output signal
+	always @(posedge wb_clk_i)
+	  wb_ack_o <= #1 wb_cyc_i & wb_stb_i & ~wb_ack_o; // because timing is always honored
+
+	// assign DAT_O
+	always @(posedge wb_clk_i)
+	begin
+	  case (wb_adr_i) 
+	    3'b000: wb_dat_o <= #1 prer[ 7:0];
+	    3'b001: wb_dat_o <= #1 prer[15:8];
+	    3'b010: wb_dat_o <= #1 ctr;
+	    3'b011: wb_dat_o <= #1 rxr; // write is transmit register (txr)
+	    3'b100: wb_dat_o <= #1 sr;  // write is command register (cr)
+	    3'b101: wb_dat_o <= #1 txr;
+	    3'b110: wb_dat_o <= #1 cr;
+	    3'b111: wb_dat_o <= #1 0;   // reserved
+	  endcase
+	end
+
+	// generate registers
+	always @(posedge wb_clk_i or negedge rst_i)
+	  if (!rst_i)
+	    begin
+	        prer <= #1 16'hffff;
+	        ctr  <= #1  8'h0;
+	        txr  <= #1  8'h0;
+	    end
+	  else if (wb_rst_i)
+	    begin
+	        prer <= #1 16'hffff;
+	        ctr  <= #1  8'h0;
+	        txr  <= #1  8'h0;
+	    end
+	  else
+	    if (wb_wacc)
+	      case (wb_adr_i) 
+	         3'b000 : prer [ 7:0] <= #1 wb_dat_i;
+	         3'b001 : prer [15:8] <= #1 wb_dat_i;
+	         3'b010 : ctr         <= #1 wb_dat_i;
+	         3'b011 : txr         <= #1 wb_dat_i;
+	         default: ;
+	      endcase
+
+	// generate command register (special case)
+	always @(posedge wb_clk_i or negedge rst_i)
+	  if (!rst_i)
+	    cr <= #1 8'h0;
+	  else if (wb_rst_i)
+	    cr <= #1 8'h0;
+	  else if (wb_wacc)
+	    begin
+	        if (core_en & (wb_adr_i == 3'b100) )
+	          cr <= #1 wb_dat_i;
+	    end
+	  else
+	    begin
+	        if (done | i2c_al)
+	          cr[7:4] <= #1 4'h0;           // clear command bits when done
+	                                        // or when aribitration lost
+	        cr[2:1] <= #1 2'b0;             // reserved bits
+	        cr[0]   <= #1 1'b0;             // clear IRQ_ACK bit
+	    end
+
+
+	// decode command register
+	wire sta  = cr[7];
+	wire sto  = cr[6];
+	wire rd   = cr[5];
+	wire wr   = cr[4];
+	wire ack  = cr[3];
+	wire iack = cr[0];
+
+	// decode control register
+	assign core_en = ctr[7];
+	assign ien = ctr[6];
+
+	// hookup byte controller block
+	i2c_master_byte_ctrl byte_controller (
+		.clk      ( wb_clk_i     ),
+		.rst      ( wb_rst_i     ),
+		.nReset   ( rst_i        ),
+		.ena      ( core_en      ),
+		.clk_cnt  ( prer         ),
+		.start    ( sta          ),
+		.stop     ( sto          ),
+		.read     ( rd           ),
+		.write    ( wr           ),
+		.ack_in   ( ack          ),
+		.din      ( txr          ),
+		.cmd_ack  ( done         ),
+		.ack_out  ( irxack       ),
+		.dout     ( rxr          ),
+		.i2c_busy ( i2c_busy     ),
+		.i2c_al   ( i2c_al       ),
+		.scl_i    ( scl_pad_i    ),
+		.scl_o    ( scl_pad_o    ),
+		.scl_oen  ( scl_padoen_o ),
+		.sda_i    ( sda_pad_i    ),
+		.sda_o    ( sda_pad_o    ),
+		.sda_oen  ( sda_padoen_o )
+	);
+
+	// status register block + interrupt request signal
+	always @(posedge wb_clk_i or negedge rst_i)
+	  if (!rst_i)
+	    begin
+	        al       <= #1 1'b0;
+	        rxack    <= #1 1'b0;
+	        tip      <= #1 1'b0;
+	        irq_flag <= #1 1'b0;
+	    end
+	  else if (wb_rst_i)
+	    begin
+	        al       <= #1 1'b0;
+	        rxack    <= #1 1'b0;
+	        tip      <= #1 1'b0;
+	        irq_flag <= #1 1'b0;
+	    end
+	  else
+	    begin
+	        al       <= #1 i2c_al | (al & ~sta);
+	        rxack    <= #1 irxack;
+	        tip      <= #1 (rd | wr);
+	        irq_flag <= #1 (done | i2c_al | irq_flag) & ~iack; // interrupt request flag is always generated
+	    end
+
+	// generate interrupt request signals
+	always @(posedge wb_clk_i or negedge rst_i)
+	  if (!rst_i)
+	    wb_inta_o <= #1 1'b0;
+	  else if (wb_rst_i)
+	    wb_inta_o <= #1 1'b0;
+	  else
+	    wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set)
+
+	// assign status register bits
+	assign sr[7]   = rxack;
+	assign sr[6]   = i2c_busy;
+	assign sr[5]   = al;
+	assign sr[4:2] = 3'h0; // reserved
+	assign sr[1]   = tip;
+	assign sr[0]   = irq_flag;
+
+endmodule
diff --git a/verilog/rtl/i2c/timescale.v b/verilog/rtl/i2c/timescale.v
new file mode 100644
index 0000000..c2dae7a
--- /dev/null
+++ b/verilog/rtl/i2c/timescale.v
@@ -0,0 +1,3 @@
+//// SPDX-License-Identifier: LGPL-2.1-or-later                  ////
+`timescale 1ns / 10ps
+
diff --git a/verilog/rtl/ptc/ptc_defines.v b/verilog/rtl/ptc/ptc_defines.v
new file mode 100644
index 0000000..7e13f09
--- /dev/null
+++ b/verilog/rtl/ptc/ptc_defines.v
@@ -0,0 +1,164 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  WISHBONE PWM/Timer/Counter Definitions                      ////
+////                                                              ////
+////  This file is part of the PTC project                        ////
+////  http://www.opencores.org/cores/ptc/                         ////
+////                                                              ////
+////  Description                                                 ////
+////  PTC definitions.                                            ////
+////                                                              ////
+////  To Do:                                                      ////
+////   Nothing                                                    ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Damjan Lampret, lampret@opencores.org                 ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//// SPDX-License-Identifier: LGPL-2.1-or-later                   ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.2  2001/08/21 23:23:50  lampret
+// Changed directory structure, defines and port names.
+//
+// Revision 1.2  2001/07/17 00:18:08  lampret
+// Added new parameters however RTL still has some issues related to hrc_match and int_match
+//
+// Revision 1.1  2001/06/05 07:45:36  lampret
+// Added initial RTL and test benches. There are still some issues with these files.
+//
+//
+
+//
+// Width of the PTC counter
+//
+//
+`define PTC_CW	32
+
+//
+// Undefine this one if you don't want to remove PTC block from your design
+// but you also don't need it. When it is undefined, all PTC ports still
+// remain valid and the core can be synthesized however internally there is
+// no PTC funationality.
+//
+// Defined by default (duhh !).
+//
+`define PTC_IMPLEMENTED
+
+//
+// Undefine if you don't need to read PTC registers.
+// When it is undefined all reads of PTC registers return zero. This
+// is usually useful if you want really small area (for example when
+// implemented in FPGA).
+//
+// To follow PTC IP core specification document this one must be defined.
+// Also to successfully run the test bench it must be defined. By default
+// it is defined.
+//
+`define PTC_READREGS
+
+//
+// Full WISHBONE address decoding
+//
+// It is is undefined, partial WISHBONE address decoding is performed.
+// Undefine it if you need to save some area.
+//
+// By default it is defined.
+//
+`define PTC_FULL_DECODE
+
+//
+// Strict 32-bit WISHBONE access
+//
+// If this one is defined, all WISHBONE accesses must be 32-bit. If it is
+// not defined, err_o is asserted whenever 8- or 16-bit access is made.
+// Undefine it if you need to save some area.
+//
+// By default it is defined.
+//
+`define PTC_STRICT_32BIT_ACCESS
+
+//
+// WISHBONE address bits used for full decoding of PTC registers.
+//
+`define PTC_ADDRHH 15
+`define PTC_ADDRHL 5
+`define PTC_ADDRLH 1
+`define PTC_ADDRLL 0
+
+//
+// Bits of WISHBONE address used for partial decoding of PTC registers.
+//
+// Default 4:2.
+//
+`define PTC_OFS_BITS	`PTC_ADDRHL-1:`PTC_ADDRLH+1
+
+//
+// Addresses of PTC registers
+//
+// To comply with PTC IP core specification document they must go from
+// address 0 to address 0xC in the following order: RPTC_CNTR, RPTC_HRC,
+// RPTC_LRC and RPTC_CTRL
+//
+// If particular alarm/ctrl register is not needed, it's address definition
+// can be omitted and the register will not be implemented. Instead a fixed
+// default value will
+// be used.
+//
+`define PTC_RPTC_CNTR	2'h0	// Address 0x0
+`define PTC_RPTC_HRC	2'h1	// Address 0x4
+`define PTC_RPTC_LRC	2'h2	// Address 0x8
+`define PTC_RPTC_CTRL	2'h3	// Address 0xc
+
+//
+// Default values for unimplemented PTC registers
+//
+`define PTC_DEF_RPTC_CNTR	`PTC_CW'b0
+`define PTC_DEF_RPTC_HRC	`PTC_CW'b0
+`define PTC_DEF_RPTC_LRC	`PTC_CW'b0
+`define PTC_DEF_RPTC_CTRL	9'h01		// RPTC_CTRL[EN] = 1
+
+//
+// RPTC_CTRL bits
+//
+// To comply with the PTC IP core specification document they must go from
+// bit 0 to bit 8 in the following order: EN, ECLK, NEC, OE, SINGLE, INTE,
+// INT, CNTRRST, CAPTE
+//
+`define PTC_RPTC_CTRL_EN		0
+`define PTC_RPTC_CTRL_ECLK		1
+`define PTC_RPTC_CTRL_NEC		2
+`define PTC_RPTC_CTRL_OE		3
+`define PTC_RPTC_CTRL_SINGLE		4
+`define PTC_RPTC_CTRL_INTE		5
+`define PTC_RPTC_CTRL_INT		6
+`define PTC_RPTC_CTRL_CNTRRST		7
+`define PTC_RPTC_CTRL_CAPTE		8
+
diff --git a/verilog/rtl/ptc/ptc_top.v b/verilog/rtl/ptc/ptc_top.v
new file mode 100644
index 0000000..4b144f0
--- /dev/null
+++ b/verilog/rtl/ptc/ptc_top.v
@@ -0,0 +1,392 @@
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+////  WISHBONE PWM/Timer/Counter                                  ////
+////                                                              ////
+////  This file is part of the PTC project                        ////
+////  http://www.opencores.org/cores/ptc/                         ////
+////                                                              ////
+////  Description                                                 ////
+////  Implementation of PWM/Timer/Counter IP core according to    ////
+////  PTC IP core specification document.                         ////
+////                                                              ////
+////  To Do:                                                      ////
+////   Nothing                                                    ////
+////                                                              ////
+////  Author(s):                                                  ////
+////      - Damjan Lampret, lampret@opencores.org                 ////
+////                                                              ////
+//////////////////////////////////////////////////////////////////////
+////                                                              ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
+////                                                              ////
+//// This source file may be used and distributed without         ////
+//// restriction provided that this copyright statement is not    ////
+//// removed from the file and that any derivative work contains  ////
+//// the original copyright notice and the associated disclaimer. ////
+////                                                              ////
+//// This source file is free software; you can redistribute it   ////
+//// and/or modify it under the terms of the GNU Lesser General   ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any   ////
+//// later version.                                               ////
+////                                                              ////
+//// This source is distributed in the hope that it will be       ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
+//// PURPOSE.  See the GNU Lesser General Public License for more ////
+//// details.                                                     ////
+////                                                              ////
+//// You should have received a copy of the GNU Lesser General    ////
+//// Public License along with this source; if not, download it   ////
+//// from http://www.opencores.org/lgpl.shtml                     ////
+////                                                              ////
+//// SPDX-License-Identifier: LGPL-2.1-or-later                   ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.4  2001/09/18 18:48:29  lampret
+// Changed top level ptc into ptc_top. Changed defines.v into ptc_defines.v. Reset of the counter is now synchronous.
+//
+// Revision 1.3  2001/08/21 23:23:50  lampret
+// Changed directory structure, defines and port names.
+//
+// Revision 1.2  2001/07/17 00:18:10  lampret
+// Added new parameters however RTL still has some issues related to hrc_match and int_match
+//
+// Revision 1.1  2001/06/05 07:45:36  lampret
+// Added initial RTL and test benches. There are still some issues with these files.
+//
+//
+
+`include "ptc_defines.v"
+
+module ptc_top(
+	// WISHBONE Interface
+	wb_clk_i, wb_rst_i, wb_cyc_i, wb_adr_i, wb_dat_i, wb_sel_i, wb_we_i, wb_stb_i,
+	wb_dat_o, wb_ack_o, wb_err_o, wb_inta_o,
+
+	// External PTC Interface
+	gate_clk_pad_i, capt_pad_i, pwm_pad_o, oen_padoen_o
+);
+
+parameter dw = 32;
+parameter aw = `PTC_ADDRHH+1;
+parameter cw = `PTC_CW;
+
+//
+// WISHBONE Interface
+//
+input			wb_clk_i;	// Clock
+input			wb_rst_i;	// Reset
+input			wb_cyc_i;	// cycle valid input
+input 	[aw-1:0]	wb_adr_i;	// address bus inputs
+input	[dw-1:0]	wb_dat_i;	// input data bus
+input	[3:0]		wb_sel_i;	// byte select inputs
+input			wb_we_i;	// indicates write transfer
+input			wb_stb_i;	// strobe input
+output	[dw-1:0]	wb_dat_o;	// output data bus
+output			wb_ack_o;	// normal termination
+output			wb_err_o;	// termination w/ error
+output			wb_inta_o;	// Interrupt request output
+
+//
+// External PTC Interface
+//
+input		gate_clk_pad_i;	// EClk/Gate input
+input		capt_pad_i;	// Capture input
+output		pwm_pad_o;	// PWM output
+output		oen_padoen_o;	// PWM output driver enable
+
+`ifdef PTC_IMPLEMENTED
+
+//
+// PTC Main Counter Register (or no register)
+//
+`ifdef PTC_RPTC_CNTR
+reg	[cw-1:0]	rptc_cntr;	// RPTC_CNTR register
+`else
+wire	[cw-1:0]	rptc_cntr;	// No RPTC_CNTR register
+`endif
+
+//
+// PTC HI Reference/Capture Register (or no register)
+//
+`ifdef PTC_RPTC_HRC
+reg	[cw-1:0]	rptc_hrc;	// RPTC_HRC register
+`else
+wire	[cw-1:0]	rptc_hrc;	// No RPTC_HRC register
+`endif
+
+//
+// PTC LO Reference/Capture Register (or no register)
+//
+`ifdef PTC_RPTC_LRC
+reg	[cw-1:0]	rptc_lrc;	// RPTC_LRC register
+`else
+wire	[cw-1:0]	rptc_lrc;	// No RPTC_LRC register
+`endif
+
+//
+// PTC Control Register (or no register)
+//
+`ifdef PTC_RPTC_CTRL
+reg	[8:0]		rptc_ctrl;	// RPTC_CTRL register
+`else
+wire	[8:0]		rptc_ctrl;	// No RPTC_CTRL register
+`endif
+
+//
+// Internal wires & regs
+//
+wire			rptc_cntr_sel;	// RPTC_CNTR select
+wire			rptc_hrc_sel;	// RPTC_HRC select
+wire			rptc_lrc_sel;	// RPTC_LRC select
+wire			rptc_ctrl_sel;	// RPTC_CTRL select
+wire			hrc_match;	// RPTC_HRC matches RPTC_CNTR
+wire			lrc_match;	// RPTC_LRC matches RPTC_CNTR
+wire			restart;	// Restart counter when asserted
+wire			stop;		// Stop counter when asserted
+wire			cntr_clk;	// Counter clock
+wire			cntr_rst;	// Counter reset
+wire			hrc_clk;	// RPTC_HRC clock
+wire			lrc_clk;	// RPTC_LRC clock
+wire			eclk_gate;	// ptc_ecgt xored by RPTC_CTRL[NEC]
+wire			gate;		// Gate function of ptc_ecgt
+wire			pwm_rst;	// Reset of a PWM output
+reg	[dw-1:0]	wb_dat_o;	// Data out
+reg			pwm_pad_o;	// PWM output
+reg			intr_reg;		// Interrupt reg
+wire			int_match;	// Interrupt match
+wire			full_decoding;	// Full address decoding qualification
+
+//
+// All WISHBONE transfer terminations are successful except when:
+// a) full address decoding is enabled and address doesn't match
+//    any of the PTC registers
+// b) sel_i evaluation is enabled and one of the sel_i inputs is zero
+//
+assign wb_ack_o = wb_cyc_i & wb_stb_i & !wb_err_o;
+`ifdef PTC_FULL_DECODE
+`ifdef PTC_STRICT_32BIT_ACCESS
+assign wb_err_o = wb_cyc_i & wb_stb_i & (!full_decoding | (wb_sel_i != 4'b1111));
+`else
+assign wb_err_o = wb_cyc_i & wb_stb_i & !full_decoding;
+`endif
+`else
+`ifdef PTC_STRICT_32BIT_ACCESS
+assign wb_err_o = wb_cyc_i & wb_stb_i & (wb_sel_i != 4'b1111);
+`else
+assign wb_err_o = 1'b0;
+`endif
+`endif
+
+//
+// Counter clock is selected by RPTC_CTRL[ECLK]. When it is set,
+// external clock is used.
+//
+assign cntr_clk = rptc_ctrl[`PTC_RPTC_CTRL_ECLK] ? eclk_gate : wb_clk_i;
+
+//
+// Counter reset
+//
+assign cntr_rst = wb_rst_i;
+
+//
+// HRC clock is selected by RPTC_CTRL[CAPTE]. When it is set,
+// ptc_capt is used as a clock.
+//
+assign hrc_clk = rptc_ctrl[`PTC_RPTC_CTRL_CAPTE] ? capt_pad_i : wb_clk_i;
+
+//
+// LRC clock is selected by RPTC_CTRL[CAPTE]. When it is set,
+// inverted ptc_capt is used as a clock.
+//
+assign lrc_clk = rptc_ctrl[`PTC_RPTC_CTRL_CAPTE] ? ~capt_pad_i : wb_clk_i;
+
+//
+// PWM output driver enable is inverted RPTC_CTRL[OE]
+//
+assign oen_padoen_o = ~rptc_ctrl[`PTC_RPTC_CTRL_OE];
+
+//
+// Use RPTC_CTRL[NEC]
+//
+assign eclk_gate = gate_clk_pad_i ^ rptc_ctrl[`PTC_RPTC_CTRL_NEC];
+
+//
+// Gate function is active when RPTC_CTRL[ECLK] is cleared
+//
+assign gate = eclk_gate & ~rptc_ctrl[`PTC_RPTC_CTRL_ECLK];
+
+//
+// Full address decoder
+//
+`ifdef PTC_FULL_DECODE
+assign full_decoding = (wb_adr_i[`PTC_ADDRHH:`PTC_ADDRHL] == {`PTC_ADDRHH-`PTC_ADDRHL+1{1'b0}}) &
+			(wb_adr_i[`PTC_ADDRLH:`PTC_ADDRLL] == {`PTC_ADDRLH-`PTC_ADDRLL+1{1'b0}});
+`else
+assign full_decoding = 1'b1;
+`endif
+
+//
+// PTC registers address decoder
+//
+assign rptc_cntr_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`PTC_OFS_BITS] == `PTC_RPTC_CNTR) & full_decoding;
+assign rptc_hrc_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`PTC_OFS_BITS] == `PTC_RPTC_HRC) & full_decoding;
+assign rptc_lrc_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`PTC_OFS_BITS] == `PTC_RPTC_LRC) & full_decoding;
+assign rptc_ctrl_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`PTC_OFS_BITS] == `PTC_RPTC_CTRL) & full_decoding;
+
+//
+// Write to RPTC_CTRL or update of RPTC_CTRL[INT] bit
+//
+`ifdef PTC_RPTC_CTRL
+always @(posedge wb_clk_i or posedge wb_rst_i)
+	if (wb_rst_i)
+		rptc_ctrl <= #1 9'b0;
+	else if (rptc_ctrl_sel && wb_we_i)
+		rptc_ctrl <= #1 wb_dat_i[8:0];
+	else if (rptc_ctrl[`PTC_RPTC_CTRL_INTE])
+		rptc_ctrl[`PTC_RPTC_CTRL_INT] <= #1 rptc_ctrl[`PTC_RPTC_CTRL_INT] | intr_reg;
+`else
+assign rptc_ctrl = `PTC_DEF_RPTC_CTRL;
+`endif
+
+//
+// Write to RPTC_HRC
+//
+`ifdef PTC_RPTC_HRC
+always @(posedge hrc_clk or posedge wb_rst_i)
+	if (wb_rst_i)
+		rptc_hrc <= #1 {cw{1'b0}};
+	else if (rptc_hrc_sel && wb_we_i)
+		rptc_hrc <= #1 wb_dat_i[cw-1:0];
+	else if (rptc_ctrl[`PTC_RPTC_CTRL_CAPTE])
+		rptc_hrc <= #1 rptc_cntr;
+`else
+assign rptc_hrc = `DEF_RPTC_HRC;
+`endif
+
+//
+// Write to RPTC_LRC
+//
+`ifdef PTC_RPTC_LRC
+always @(posedge lrc_clk or posedge wb_rst_i)
+	if (wb_rst_i)
+		rptc_lrc <= #1 {cw{1'b0}};
+	else if (rptc_lrc_sel && wb_we_i)
+		rptc_lrc <= #1 wb_dat_i[cw-1:0];
+	else if (rptc_ctrl[`PTC_RPTC_CTRL_CAPTE])
+		rptc_lrc <= #1 rptc_cntr;
+`else
+assign rptc_lrc = `DEF_RPTC_LRC;
+`endif
+
+//
+// Write to or increment of RPTC_CNTR
+//
+`ifdef PTC_RPTC_CNTR
+always @(posedge cntr_clk or posedge cntr_rst)
+	if (cntr_rst)
+		rptc_cntr <= #1 {cw{1'b0}};
+	else if (rptc_cntr_sel && wb_we_i)
+		rptc_cntr <= #1 wb_dat_i[cw-1:0];
+	else if (restart)
+		rptc_cntr <= #1 {cw{1'b0}};
+	else if (!stop && rptc_ctrl[`PTC_RPTC_CTRL_EN] && !gate)
+		rptc_cntr <= #1 rptc_cntr + 1;
+`else
+assign rptc_cntr = `DEF_RPTC_CNTR;
+`endif
+
+//
+// Read PTC registers
+//
+always @(wb_adr_i or rptc_hrc or rptc_lrc or rptc_ctrl or rptc_cntr)
+	case (wb_adr_i[`PTC_OFS_BITS])	
+`ifdef PTC_READREGS
+		`PTC_RPTC_HRC: wb_dat_o[dw-1:0] = {{dw-cw{1'b0}}, rptc_hrc};
+		`PTC_RPTC_LRC: wb_dat_o[dw-1:0] = {{dw-cw{1'b0}}, rptc_lrc};
+		`PTC_RPTC_CTRL: wb_dat_o[dw-1:0] = {{dw-9{1'b0}}, rptc_ctrl};
+`endif
+		default: wb_dat_o[dw-1:0] = {{dw-cw{1'b0}}, rptc_cntr};
+	endcase
+
+//
+// A match when RPTC_HRC is equal to RPTC_CNTR
+//
+assign hrc_match = rptc_ctrl[`PTC_RPTC_CTRL_EN] & (rptc_cntr == rptc_hrc);
+
+//
+// A match when RPTC_LRC is equal to RPTC_CNTR
+//
+assign lrc_match = rptc_ctrl[`PTC_RPTC_CTRL_EN] & (rptc_cntr == rptc_lrc);
+
+//
+// Restart counter when lrc_match asserted and RPTC_CTRL[SINGLE] cleared
+// or when RPTC_CTRL[CNTRRST] is set
+//
+assign restart = lrc_match & ~rptc_ctrl[`PTC_RPTC_CTRL_SINGLE]
+	| rptc_ctrl[`PTC_RPTC_CTRL_CNTRRST];
+
+//
+// Stop counter when lrc_match and RPTC_CTRL[SINGLE] both asserted
+//
+assign stop = lrc_match & rptc_ctrl[`PTC_RPTC_CTRL_SINGLE];
+
+//
+// PWM reset when lrc_match or system reset
+//
+assign pwm_rst = lrc_match | wb_rst_i;
+
+//
+// PWM output
+//
+always @(posedge wb_clk_i)	// posedge pwm_rst or posedge hrc_match !!! Damjan
+	if (pwm_rst)
+		pwm_pad_o <= #1 1'b0;
+	else if (hrc_match)
+		pwm_pad_o <= #1 1'b1;
+
+//
+// Generate an interrupt request
+//
+assign int_match = (lrc_match | hrc_match) & rptc_ctrl[`PTC_RPTC_CTRL_INTE];
+
+// Register interrupt request
+always @(posedge wb_rst_i or posedge wb_clk_i) // posedge int_match (instead of wb_rst_i)
+	if (wb_rst_i)
+		intr_reg <= #1 1'b0;
+	else if (int_match)
+		intr_reg <= #1 1'b1;
+	else
+		intr_reg <= #1 1'b0;
+
+//
+// Alias
+//
+assign wb_inta_o = rptc_ctrl[`PTC_RPTC_CTRL_INT];
+
+`else
+
+//
+// When PTC is not implemented, drive all outputs as would when RPTC_CTRL
+// is cleared and WISHBONE transfers complete with errors
+//
+assign wb_inta_o = 1'b0;
+assign wb_ack_o = 1'b0;
+assign wb_err_o = cyc_i & stb_i;
+assign pwm_pad_o = 1'b0;
+assign oen_padoen_o = 1'b1;
+
+//
+// Read PTC registers
+//
+`ifdef PTC_READREGS
+assign wb_dat_o = {dw{1'b0}};
+`endif
+
+`endif
+
+endmodule
diff --git a/verilog/rtl/rtc/hexmap.v b/verilog/rtl/rtc/hexmap.v
new file mode 100644
index 0000000..15d4069
--- /dev/null
+++ b/verilog/rtl/rtc/hexmap.v
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	hexmap.v
+//		
+// Project:	A Real--time Clock Core
+//
+// Purpose:	Converts a 4'bit hexadecimal value to the seven bits needed
+//		by a seven segment display, specifying which bits are on and
+//		which are off.
+//
+//		The display I am working with, however, requires a separate
+//		controller.  This file only provides part of the input for that
+//		controller.  That controller deals with turning on each part
+//		of the display in a rotating fashion, since the hardware I have
+//		cannot display more than one character at a time.  So,
+//		buyer beware--this is not a complete seven segment display
+//		solution.
+//
+//
+//		The outputs of this routine are numbered as follows:
+//			o_map[7] turns on the bar at the top of the display
+//			o_map[6] turns on the top of the '1'
+//			o_map[5] turns on the bottom of a '1'
+//			o_map[4] turns on the bar at the bottom of the display
+//			o_map[3] turns on the vertical bar at the bottom left
+//			o_map[2] turns on the vertical bar at the top left, and
+//			o_map[1] turns on the bar in the middle of the display.
+//				The dash if you will.
+//		Bit zero, from elsewhere, would be the decimal point.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Tecnology, LLC
+//
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of  the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
+// target there if the PDF file isn't present.)  If not, see
+// <http://www.gnu.org/licenses/> for a copy.
+//
+// License:	GPL, v3, as defined and found on www.gnu.org,
+//		http://www.gnu.org/licenses/gpl.html
+//
+//// SPDX-License-Identifier: GPL-3.0-or-later 
+///////////////////////////////////////////////////////////////////////////
+module	hexmap(i_clk, i_hex, o_map);
+	input		i_clk;
+	input	[3:0]	i_hex;
+	output	reg	[7:1]	o_map;
+
+	always @(posedge i_clk)
+		case(i_hex)
+		4'h0:	o_map <= { 7'b1111110 };
+		4'h1:	o_map <= { 7'b0110000 };
+		4'h2:	o_map <= { 7'b1101101 };
+		4'h3:	o_map <= { 7'b1111001 };
+		4'h4:	o_map <= { 7'b0110011 };
+		4'h5:	o_map <= { 7'b1011011 };
+		4'h6:	o_map <= { 7'b1011111 };
+		4'h7:	o_map <= { 7'b1110000 };
+		4'h8:	o_map <= { 7'b1111111 };
+		4'h9:	o_map <= { 7'b1111011 };
+		4'ha:	o_map <= { 7'b1110111 };
+		4'hb:	o_map <= { 7'b0011111 }; // b
+		4'hc:	o_map <= { 7'b1001110 };
+		4'hd:	o_map <= { 7'b0111101 }; // d
+		4'he:	o_map <= { 7'b1001111 };
+		4'hf:	o_map <= { 7'b1000111 };
+		endcase
+endmodule
diff --git a/verilog/rtl/rtc/rtcclock.v b/verilog/rtl/rtc/rtcclock.v
new file mode 100644
index 0000000..31877db
--- /dev/null
+++ b/verilog/rtl/rtc/rtcclock.v
@@ -0,0 +1,504 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	rtcclock.v
+//		
+// Project:	A Wishbone Controlled Real--time Clock Core
+//
+// Purpose:	Implement a real time clock, including alarm, count--down
+//		timer, stopwatch, variable time frequency, and more.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of  the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
+// target there if the PDF file isn't present.)  If not, see
+// <http://www.gnu.org/licenses/> for a copy.
+//
+// License:	GPL, v3, as defined and found on www.gnu.org,
+//		http://www.gnu.org/licenses/gpl.html
+//
+//// SPDX-License-Identifier: GPL-3.0-or-later                  
+///////////////////////////////////////////////////////////////////////////
+module	rtcclock(i_clk, 
+		// Wishbone interface
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
+		//	o_wb_ack, o_wb_stb, o_wb_data, // no reads here
+		// // Button inputs
+		// i_btn,
+		// Output registers
+		o_data, // multiplexed based upon i_wb_addr
+		// Output controls
+		o_sseg, o_led, o_interrupt,
+		// A once-per-day strobe on the last clock of the day
+		o_ppd,
+		// Time setting hack(s)
+		i_hack);
+	parameter	DEFAULT_SPEED = 32'd2814750; //2af31e = 2^48 / 100e6 MHz
+	input	i_clk;
+	input	i_wb_cyc, i_wb_stb, i_wb_we;
+	input	[2:0]	i_wb_addr;
+	input	[31:0]	i_wb_data;
+	// input		i_btn;
+	output	reg	[31:0]	o_data;
+	output	reg	[31:0]	o_sseg;
+	output	wire	[15:0]	o_led;
+	output	wire		o_interrupt, o_ppd;
+	input			i_hack;
+
+	reg	[31:0]	stopwatch, ckspeed;
+	reg	[25:0]	clock, timer;
+	
+	wire	ck_sel, tm_sel, sw_sel, sp_sel, al_sel;
+	assign	ck_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b000));
+	assign	tm_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b001));
+	assign	sw_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b010));
+	assign	al_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b011));
+	assign	sp_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b100));
+
+	reg	[39:0]	ck_counter;
+	reg		ck_carry;
+	always @(posedge i_clk)
+		{ ck_carry, ck_counter } <= ck_counter + { 8'h00, ckspeed };
+
+	wire		ck_pps;
+	reg		ck_prepps, ck_ppm, ck_pph, ck_ppd;
+	reg	[7:0]	ck_sub;
+	initial	clock = 26'h000000;
+	assign	ck_pps = (ck_carry)&&(ck_prepps);
+	always @(posedge i_clk)
+	begin
+		if (ck_carry)
+			ck_sub <= ck_sub + 8'h1;
+		ck_prepps <= (ck_sub == 8'hff);
+
+		if (ck_pps)
+		begin // advance the seconds
+			if (clock[3:0] >= 4'h9)
+				clock[3:0] <= 4'h0;
+			else
+				clock[3:0] <= clock[3:0] + 4'h1;
+			if (clock[7:0] >= 8'h59)
+				clock[7:4] <= 4'h0;
+			else if (clock[3:0] >= 4'h9)
+				clock[7:4] <= clock[7:4] + 4'h1;
+		end
+		ck_ppm <= (clock[7:0] == 8'h59);
+
+		if ((ck_pps)&&(ck_ppm))
+		begin // advance the minutes
+			if (clock[11:8] >= 4'h9)
+				clock[11:8] <= 4'h0;
+			else
+				clock[11:8] <= clock[11:8] + 4'h1;
+			if (clock[15:8] >= 8'h59)
+				clock[15:12] <= 4'h0;
+			else if (clock[11:8] >= 4'h9)
+				clock[15:12] <= clock[15:12] + 4'h1;
+		end
+		ck_pph <= (clock[15:0] == 16'h5959);
+
+		if ((ck_pps)&&(ck_pph))
+		begin // advance the hours
+			if (clock[21:16] >= 6'h23)
+			begin
+				clock[19:16] <= 4'h0;
+				clock[21:20] <= 2'h0;
+			end else if (clock[19:16] >= 4'h9)
+			begin
+				clock[19:16] <= 4'h0;
+				clock[21:20] <= clock[21:20] + 2'h1;
+			end else begin
+				clock[19:16] <= clock[19:16] + 4'h1;
+			end
+		end
+		ck_ppd <= (clock[21:0] == 22'h235959);
+
+
+		if ((ck_sel)&&(i_wb_we))
+		begin
+			if (8'hff != i_wb_data[7:0])
+			begin
+				clock[7:0] <= i_wb_data[7:0];
+				ck_ppm <= (i_wb_data[7:0] == 8'h59);
+			end
+			if (8'hff != i_wb_data[15:8])
+			begin
+				clock[15:8] <= i_wb_data[15:8];
+				ck_pph <= (i_wb_data[15:8] == 8'h59);
+			end
+			if (6'h3f != i_wb_data[21:16])
+				clock[21:16] <= i_wb_data[21:16];
+			clock[25:22] <= i_wb_data[25:22];
+			if (8'h00 == i_wb_data[7:0])
+				ck_sub <= 8'h00;
+		end
+	end
+
+	// Clock updates take several clocks, so let's make sure we
+	// are only looking at a valid clock value before testing it.
+	reg	[21:0]		ck_last_clock;
+	always @(posedge i_clk)
+		ck_last_clock <= clock[21:0];
+		
+
+	reg	tm_pps, tm_ppm, tm_int;
+	wire	tm_stopped, tm_running, tm_alarm;
+	assign	tm_stopped = ~timer[24];
+	assign	tm_running =  timer[24];
+	assign	tm_alarm   =  timer[25];
+	reg	[23:0]		tm_start;
+	reg	[7:0]		tm_sub;
+	initial	tm_start = 24'h00;
+	initial	timer    = 26'h00;
+	initial	tm_int   = 1'b0;
+	initial	tm_pps   = 1'b0;
+	always @(posedge i_clk)
+	begin
+		if (ck_carry)
+		begin
+			tm_sub <= tm_sub + 8'h1;
+			tm_pps <= (tm_sub == 8'hff);
+		end else
+			tm_pps <= 1'b0;
+		
+		if ((~tm_alarm)&&(tm_running)&&(tm_pps))
+		begin // If we are running ...
+			timer[25] <= 1'b0;
+			if (timer[23:0] == 24'h00)
+				timer[25] <= 1'b1;
+			else if (timer[3:0] != 4'h0)
+				timer[3:0] <= timer[3:0]-4'h1;
+			else begin // last digit is a zero
+				timer[3:0] <= 4'h9;
+				if (timer[7:4] != 4'h0)
+					timer[7:4] <= timer[7:4]-4'h1;
+				else begin // last two digits are zero
+					timer[7:4] <= 4'h5;
+					if (timer[11:8] != 4'h0)
+						timer[11:8] <= timer[11:8]-4'h1;
+					else begin // last three digits are zero
+						timer[11:8] <= 4'h9;
+						if (timer[15:12] != 4'h0)
+							timer[15:12] <= timer[15:12]-4'h1;
+						else begin
+							timer[15:12] <= 4'h5;
+							if (timer[19:16] != 4'h0)
+								timer[19:16] <= timer[19:16]-4'h1;
+							else begin
+							//
+								timer[19:16] <= 4'h9;
+								timer[23:20] <= timer[23:20]-4'h1;
+							end
+						end
+					end
+				end
+			end
+		end
+
+		if((~tm_alarm)&&(tm_running))
+		begin
+			timer[25] <= (timer[23:0] == 24'h00);
+			tm_int <= (timer[23:0] == 24'h00);
+		end else tm_int <= 1'b0;
+		if (tm_alarm)
+			timer[24] <= 1'b0;
+
+		if ((tm_sel)&&(i_wb_we)&&(tm_running)) // Writes while running
+			// Only allowed to stop the timer, nothing more
+			timer[24] <= i_wb_data[24];
+		else if ((tm_sel)&&(i_wb_we)&&(tm_stopped)) // Writes while off
+		begin
+			timer[24] <= i_wb_data[24];
+			if ((timer[24])||(i_wb_data[24]))
+				timer[25] <= 1'b0;
+			if (i_wb_data[23:0] != 24'h0000)
+			begin
+				timer[23:0] <= i_wb_data[23:0];
+				tm_start <= i_wb_data[23:0];
+				tm_sub <= 8'h00;
+			end else if (timer[23:0] == 24'h00)
+			begin // Resetting timer to last valid timer start val
+				timer[23:0] <= tm_start;
+				tm_sub <= 8'h00;
+			end
+			// Any write clears the alarm
+			timer[25] <= 1'b0;
+		end
+	end
+
+	//
+	// Stopwatch functionality
+	//
+	// Setting bit '0' starts the stop watch, clearing it stops it.
+	// Writing to the register with bit '1' high will clear the stopwatch,
+	// and return it to zero provided that the stopwatch is stopped either
+	// before or after the write.  Hence, writing a '2' to the device
+	// will always stop and clear it, whereas writing a '3' to the device
+	// will only clear it if it was already stopped.
+	reg		sw_pps, sw_ppm, sw_pph;
+	reg	[7:0]	sw_sub;
+	wire	sw_running;
+	assign	sw_running = stopwatch[0];
+	initial	stopwatch = 32'h00000;
+	always @(posedge i_clk)
+	begin
+		sw_pps <= 1'b0;
+		if (sw_running)
+		begin
+			if (ck_carry)
+			begin
+				sw_sub <= sw_sub + 8'h1;
+				sw_pps <= (sw_sub == 8'hff);
+			end
+		end
+
+		stopwatch[7:1] <= sw_sub[7:1];
+
+		if (sw_pps)
+		begin // Second hand
+			if (stopwatch[11:8] >= 4'h9)
+				stopwatch[11:8] <= 4'h0;
+			else
+				stopwatch[11:8] <= stopwatch[11:8] + 4'h1;
+
+			if (stopwatch[15:8] >= 8'h59)
+				stopwatch[15:12] <= 4'h0;
+			else if (stopwatch[11:8] >= 4'h9)
+				stopwatch[15:12] <= stopwatch[15:12] + 4'h1;
+			sw_ppm <= (stopwatch[15:8] == 8'h59);
+		end else sw_ppm <= 1'b0;
+
+		if (sw_ppm)
+		begin // Minutes
+			if (stopwatch[19:16] >= 4'h9)
+				stopwatch[19:16] <= 4'h0;
+			else
+				stopwatch[19:16] <= stopwatch[19:16]+4'h1;
+
+			if (stopwatch[23:16] >= 8'h59)
+				stopwatch[23:20] <= 4'h0;
+			else if (stopwatch[19:16] >= 4'h9)
+				stopwatch[23:20] <= stopwatch[23:20]+4'h1;
+			sw_pph <= (stopwatch[23:16] == 8'h59);
+		end else sw_pph <= 1'b0;
+
+		if (sw_pph)
+		begin // And hours
+			if (stopwatch[27:24] >= 4'h9)
+				stopwatch[27:24] <= 4'h0;
+			else
+				stopwatch[27:24] <= stopwatch[27:24]+4'h1;
+
+			if((stopwatch[27:24] >= 4'h9)&&(stopwatch[31:28] < 4'hf))
+				stopwatch[31:28] <= stopwatch[27:24]+4'h1;
+		end
+
+		if ((sw_sel)&&(i_wb_we))
+		begin
+			stopwatch[0] <= i_wb_data[0];
+			if((i_wb_data[1])&&((~stopwatch[0])||(~i_wb_data[0])))
+			begin
+				stopwatch[31:1] <= 31'h00;
+				sw_sub <= 8'h00;
+				sw_pps <= 1'b0;
+				sw_ppm <= 1'b0;
+				sw_pph <= 1'b0;
+			end
+		end
+	end
+
+	//
+	// The alarm code
+	//
+	// Set the alarm register to the time you wish the board to "alarm".
+	// The "alarm" will take place once per day at that time.  At that
+	// time, the RTC code will generate a clock interrupt, and the CPU/host
+	// can come and see that the alarm tripped.
+	//
+	// 
+	reg	[21:0]		alarm_time;
+	reg			al_int,		// The alarm interrupt line
+				al_enabled,	// Whether the alarm is enabled
+				al_tripped;	// Whether the alarm has tripped
+	initial	al_enabled= 1'b0;
+	initial	al_tripped= 1'b0;
+	always @(posedge i_clk)
+	begin
+		if ((al_sel)&&(i_wb_we))
+		begin
+			// Only adjust the alarm hours if the requested hours
+			// are valid.  This allows writes to the register,
+			// without a prior read, to leave these configuration
+			// bits alone.
+			if (i_wb_data[21:16] != 6'h3f)
+				alarm_time[21:16] <= i_wb_data[21:16];
+			// Here's the same thing for the minutes: only adjust
+			// the alarm minutes if the new bits are not all 1's. 
+			if (i_wb_data[15:8] != 8'hff)
+				alarm_time[15:8] <= i_wb_data[15:8];
+			// Here's the same thing for the seconds: only adjust
+			// the alarm minutes if the new bits are not all 1's. 
+			if (i_wb_data[7:0] != 8'hff)
+				alarm_time[7:0] <= i_wb_data[7:0];
+			al_enabled <= i_wb_data[24];
+			// Reset the alarm if a '1' is written to the tripped
+			// register, or if the alarm is disabled.
+			if ((i_wb_data[25])||(~i_wb_data[24]))
+				al_tripped <= 1'b0;
+		end
+
+		al_int <= 1'b0;
+		if ((ck_last_clock != alarm_time)&&(clock[21:0] == alarm_time)
+			&&(al_enabled))
+		begin
+			al_tripped <= 1'b1;
+			al_int <= 1'b1;
+		end
+	end
+
+	//
+	// The ckspeed register is equal to 2^48 divded by the number of
+	// clock ticks you expect per second.  Adjust high for a slower
+	// clock, lower for a faster clock.  In this fashion, a single
+	// real time clock RTL file can handle tracking the clock in any
+	// device.  Further, because this is only the lower 32 bits of a 
+	// 48 bit counter per seconds, the clock jitter is kept below
+	// 1 part in 65 thousand.
+	//
+	initial	ckspeed = DEFAULT_SPEED;
+	// In the case of verilator, comment the above and uncomment the line
+	// below.  The clock constant below is "close" to simulation time,
+	// meaning that my verilator simulation is running about 300x slower
+	// than board time.
+	// initial	ckspeed = 32'd786432000;
+	always @(posedge i_clk)
+		if ((sp_sel)&&(i_wb_we))
+			ckspeed <= i_wb_data;
+
+	// 
+	// If you want very fine precision control over your clock, you need
+	// to be able to transfer time from one location to another.  This
+	// is the beginning of that means: by setting a wire, i_hack, high
+	// on a particular input, you can then read (later) what the clock
+	// time was on that input.
+	//
+	// What's missing from this high precision adjustment mechanism is a
+	// means of actually adjusting this time based upon the time 
+	// difference you measure here between the hack time and some time
+	// on another clock, but we'll get there.
+	//
+	reg		r_hack_carry;
+	reg	[29:0]	hack_time;
+	reg	[39:0]	hack_counter;
+	initial	hack_time    = 30'h0000;
+	initial	hack_counter = 40'h0000;
+	always @(posedge i_clk)
+		if (i_hack)
+		begin
+			hack_time <= { clock[21:0], ck_sub };
+			hack_counter <= ck_counter;
+			r_hack_carry <= ck_carry;
+			// if ck_carry is set, the clock register is in the
+			// middle of a two clock update.  In that case ....
+		end else if (r_hack_carry)
+		begin // update again on the next clock to get the correct
+			// hack time.
+			hack_time <= { clock[21:0], ck_sub };
+			r_hack_carry <= 1'b0;
+		end
+
+	reg	[15:0]	h_sseg;
+	reg	[3:1]	dmask;
+	always @(posedge i_clk)
+		case(clock[25:24])
+		2'h1: begin h_sseg <= timer[15:0];
+			if (tm_alarm) dmask <= 3'h7;
+			else begin
+				dmask[3] <= (12'h000 != timer[23:12]); // timer[15:12]
+				dmask[2] <= (16'h000 != timer[23: 8]); // timer[11: 8]
+				dmask[1] <= (20'h000 != timer[23: 4]); // timer[ 7: 4]
+				// dmask[0] <= 1'b1; // Always on
+			end end
+		2'h2: begin h_sseg <= stopwatch[19:4];
+				dmask[3] <= (12'h00  != stopwatch[27:16]);
+				dmask[2] <= (16'h000 != stopwatch[27:12]);
+				dmask[1] <= 1'b1; // Always on, stopwatch[11:8]
+				// dmask[0] <= 1'b1; // Always on, stopwatch[7:4]
+			end
+		2'h3: begin h_sseg <= ck_last_clock[15:0];
+				dmask[3:1] <= 3'h7;
+			end
+		default: begin // 4'h0
+			h_sseg <= { 2'b00, ck_last_clock[21:8] };
+			dmask[2:1] <= 2'b11;
+			dmask[3] <= (2'b00 != ck_last_clock[21:20]);
+			end
+		endcase
+
+	wire	[31:0]	w_sseg;
+	assign	w_sseg[ 0] =  (~ck_sub[7]);
+	assign	w_sseg[ 8] =  (clock[25:24] == 2'h2);
+	assign	w_sseg[16] = ((clock[25:24] == 2'h0)&&(~ck_sub[7]))||(clock[25:24] == 2'h3);
+	assign	w_sseg[24] = 1'b0;
+	hexmap	ha(i_clk, h_sseg[ 3: 0], w_sseg[ 7: 1]);
+	hexmap	hb(i_clk, h_sseg[ 7: 4], w_sseg[15: 9]);
+	hexmap	hc(i_clk, h_sseg[11: 8], w_sseg[23:17]);
+	hexmap	hd(i_clk, h_sseg[15:12], w_sseg[31:25]);
+
+	always @(posedge i_clk)
+		if ((tm_alarm || al_tripped)&&(ck_sub[7]))
+			o_sseg <= 32'h0000;
+		else
+			o_sseg <= { 
+				(dmask[3])?w_sseg[31:24]:8'h00,
+				(dmask[2])?w_sseg[23:16]:8'h00,
+				(dmask[1])?w_sseg[15: 8]:8'h00,
+				w_sseg[ 7: 0] };
+
+	reg	[17:0]	ledreg;
+	always @(posedge i_clk)
+		if ((ck_pps)&&(ck_ppm))
+			ledreg <= 18'h00;
+		else if (ck_carry)
+			ledreg <= ledreg + 18'h11;
+	assign	o_led = (tm_alarm||al_tripped)?{ (16){ck_sub[7]}}:
+				{ ledreg[17:10],
+				ledreg[10], ledreg[11], ledreg[12], ledreg[13],
+				ledreg[14], ledreg[15], ledreg[16], ledreg[17] };
+
+	assign	o_interrupt = tm_int || al_int;
+
+	// A once-per day strobe, on the last second of the day so that the
+	// the next clock is the first clock of the day.  This is useful for
+	// connecting this module to a year/month/date date/calendar module.
+	assign	o_ppd = (ck_ppd)&&(ck_pps);
+
+	always @(posedge i_clk)
+		case(i_wb_addr[2:0])
+		3'b000: o_data <= { 6'h00, clock[25:22], ck_last_clock };
+		3'b001: o_data <= { 6'h00, timer };
+		3'b010: o_data <= stopwatch;
+		3'b011: o_data <= { 6'h00, al_tripped, al_enabled, 2'b00, alarm_time };
+		3'b100: o_data <= ckspeed;
+		3'b101: o_data <= { 2'b00, hack_time };
+		3'b110: o_data <= hack_counter[39:8];
+		3'b111: o_data <= { hack_counter[7:0], 24'h00 };
+		endcase
+
+endmodule
diff --git a/verilog/rtl/rtc/rtcdate.v b/verilog/rtl/rtc/rtcdate.v
new file mode 100644
index 0000000..b41f9ae
--- /dev/null
+++ b/verilog/rtl/rtc/rtcdate.v
@@ -0,0 +1,188 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	rtcdate.v
+//		
+// Project:	A Wishbone Controlled Real--time Clock Core
+//
+// Purpose:
+//	This core provides a real-time date function that can be coupled with
+//	a real-time clock.  The date provided is in Binary Coded Decimal (bcd)
+//	form, and available for reading and writing over the Wishbone Bus.
+//
+// WARNING: Race conditions exist when updating the date across the Wishbone
+//	bus at or near midnight.  (This should be obvious, but it bears
+//	stating.)  Specifically, if the update command shows up at the same
+//	clock as the ppd clock, then the ppd clock will be ignored and the 
+//	new date will be the date of the day following midnight.  However,
+// 	if the update command shows up one clock before the ppd, then the date
+//	may be updated, but may have problems dealing with the last day of the
+//	month or year.  To avoid race conditions, update the date sometime
+//	after the stroke of midnight and before 5 clocks before the next
+// 	midnight.  If you are concerned that you might hit a race condition, 
+//	just read the clock again (5+ clocks later) to make certain you set 
+//	it correctly.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of  the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
+// target there if the PDF file isn't present.)  If not, see
+// <http://www.gnu.org/licenses/> for a copy.
+//
+// License:	GPL, v3, as defined and found on www.gnu.org,
+//		http://www.gnu.org/licenses/gpl.html
+//
+//// SPDX-License-Identifier: GPL-3.0-or-later 
+///////////////////////////////////////////////////////////////////////////
+module rtcdate(i_clk, i_ppd, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
+		o_wb_ack, o_wb_stall, o_wb_data);
+	input	i_clk;
+	// A one part per day signal, i.e. basically a clock enable line that
+	// controls when the beginning of the day happens.  This line should
+	// be high on the very last second of any day in order for the rtcdate
+	// module to always have the right date.
+	input	i_ppd;
+	// Wishbone inputs
+	input	i_wb_cyc, i_wb_stb, i_wb_we;
+	input	[31:0]	i_wb_data;
+	// Wishbone outputs
+	output	reg	o_wb_ack;
+	output	wire	o_wb_stall;
+	output	wire	[31:0]	o_wb_data;
+
+
+	reg	[5:0]	r_day;
+	reg	[4:0]	r_mon;
+	reg	[13:0]	r_year;
+
+	reg	last_day_of_month, last_day_of_year, is_leap_year;
+	always @(posedge i_clk)
+		last_day_of_year <= (last_day_of_month) && (r_mon == 5'h12);
+	always @(posedge i_clk)
+	begin
+		case(r_mon)
+		5'h01: last_day_of_month <= (r_day >= 6'h31); // Jan
+		5'h02: last_day_of_month <= (r_day >= 6'h29)
+				||((~is_leap_year)&&(r_day == 6'h28));
+		5'h03: last_day_of_month <= (r_day >= 6'h31); // March
+		5'h04: last_day_of_month <= (r_day >= 6'h30); // April
+		5'h05: last_day_of_month <= (r_day >= 6'h31); // May
+		5'h06: last_day_of_month <= (r_day >= 6'h30); // June
+		5'h07: last_day_of_month <= (r_day >= 6'h31); // July
+		5'h08: last_day_of_month <= (r_day >= 6'h31); // August
+		5'h09: last_day_of_month <= (r_day >= 6'h30); // Sept
+		5'h10: last_day_of_month <= (r_day >= 6'h31); // October
+		5'h11: last_day_of_month <= (r_day >= 6'h30); // November
+		5'h12: last_day_of_month <= (r_day >= 6'h31); // December
+		default: last_day_of_month <= 1'b0;
+		endcase
+	end
+
+	reg	year_divisible_by_four, century_year, four_century_year;
+	always @(posedge i_clk)
+		year_divisible_by_four<= ((~r_year[0])&&(r_year[4]==r_year[1]));
+	always @(posedge i_clk)
+		century_year <= (r_year[7:0] == 8'h00);
+	always @(posedge i_clk)
+		four_century_year <= ((~r_year[8])&&((r_year[12]==r_year[9])));
+	always @(posedge i_clk)
+		is_leap_year <= (year_divisible_by_four)&&((~century_year)
+			||((century_year)&&(four_century_year)));
+
+
+	// Adjust the day of month
+	initial	r_day = 6'h01;
+	always @(posedge i_clk)
+	begin
+		if ((r_day == 0)||(r_day > 6'h31)||(r_day[3:0] > 4'h9))
+			r_day <= 6'h01;
+		else if ((i_ppd)&&(last_day_of_month))
+			r_day <= 6'h01;
+		else if ((i_ppd)&&(r_day[3:0] != 4'h9))
+			r_day[3:0] <= r_day[3:0] + 4'h1;
+		else if (i_ppd)
+		begin
+			r_day[3:0] <= 4'h0;
+			r_day[5:4] <= r_day[5:4] + 2'h1;
+		end
+
+		if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)&&(i_wb_data[7:0]!=8'hff))
+			r_day <= i_wb_data[5:0];
+	end
+
+	// Adjust the month of the year
+	initial	r_mon = 5'h01;
+	always @(posedge i_clk)
+	begin
+		if ((r_mon == 0)||(r_mon > 5'h12)||(r_mon[3:0] > 4'h9))
+			r_mon <= 5'h01;
+		else if ((i_ppd)&&(last_day_of_year))
+			r_mon <= 5'h01;
+		else if ((i_ppd)&&(last_day_of_month)&&(r_mon[3:0] != 4'h9))
+			r_mon[3:0] <= r_mon[3:0] + 4'h1;
+		else if ((i_ppd)&&(last_day_of_month))
+		begin
+			r_mon[3:0] <= 4'h0;
+			r_mon[4] <= 1;
+		end
+
+		if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)&&(i_wb_data[15:8]!=8'hff))
+			r_mon <= i_wb_data[12:8];
+	end
+
+	// Adjust the year
+	initial	r_year = 14'h2000;
+	always @(posedge i_clk)
+	begin
+		// Deal with any out of bounds conditions
+		if (r_year[3:0] > 4'h9)
+			r_year[3:0] <= 4'h0;
+		if (r_year[7:4] > 4'h9)
+			r_year[7:4] <= 4'h0;
+		if (r_year[11:8] > 4'h9)
+			r_year[11:8] <= 4'h0;
+		if ((i_ppd)&&(last_day_of_year))
+		begin
+			if (r_year[3:0] != 4'h9)
+				r_year[3:0] <= r_year[3:0] + 4'h1;
+			else begin
+				r_year[3:0] <= 4'h0;
+				if (r_year[7:4] != 4'h9)
+					r_year[7:4] <= r_year[7:4] + 4'h1;
+				else begin
+					r_year[7:4] <= 4'h0;
+					if (r_year[11:8] != 4'h9)
+						r_year[11:8] <= r_year[11:8]+4'h1;
+					else begin
+						r_year[11:8] <= 4'h0;
+						r_year[13:12] <= r_year[13:12]+2'h1;
+					end
+				end
+			end
+		end
+
+		if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)&&(i_wb_data[31:16]!=16'hffff))
+			r_year <= i_wb_data[29:16];
+	end
+
+	always @(posedge i_clk)
+		o_wb_ack <= ((i_wb_cyc)&&(i_wb_stb));
+	assign	o_wb_stall = 1'b0;
+	assign	o_wb_data = { 2'h0, r_year, 3'h0, r_mon, 2'h0, r_day };
+endmodule
diff --git a/verilog/rtl/rtc/rtcgps.v b/verilog/rtl/rtc/rtcgps.v
new file mode 100644
index 0000000..3769ffc
--- /dev/null
+++ b/verilog/rtl/rtc/rtcgps.v
@@ -0,0 +1,498 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	rtcgps.v
+//		
+// Project:	A Wishbone Controlled Real--time Clock Core, w/ GPS synch
+//
+// Purpose:	Implement a real time clock, including alarm, count--down
+//		timer, stopwatch, variable time frequency, and more.
+//
+//	This particular version has hooks for a GPS 1PPS, as well as a 
+//	finely tracked clock speed output, to allow for fine clock precision
+//	and good freewheeling even if/when GPS is lost.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of  the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
+// target there if the PDF file isn't present.)  If not, see
+// <http://www.gnu.org/licenses/> for a copy.
+//
+// License:	GPL, v3, as defined and found on www.gnu.org,
+//		http://www.gnu.org/licenses/gpl.html
+//
+//// SPDX-License-Identifier: GPL-3.0-or-later 
+///////////////////////////////////////////////////////////////////////////
+module	rtcgps(i_clk, 
+		// Wishbone interface
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
+		//	o_wb_ack, o_wb_stb, o_wb_data, // no reads here
+		// // Button inputs
+		// i_btn,
+		// Output registers
+		o_data, // multiplexed based upon i_wb_addr
+		// Output controls
+		o_sseg, o_led, o_interrupt,
+		// A once-per-day strobe on the last clock of the day
+		o_ppd,
+		// GPS interface
+		i_gps_valid, i_gps_pps, i_gps_ckspeed,
+		// Our personal timing, for debug purposes
+		o_rtc_pps);
+	parameter	DEFAULT_SPEED = 32'd2814750; //2af31e = 2^48 / 100e6 MHz
+	input	i_clk;
+	input	i_wb_cyc, i_wb_stb, i_wb_we;
+	input	[1:0]	i_wb_addr;
+	input	[31:0]	i_wb_data;
+	// input		i_btn;
+	output	reg	[31:0]	o_data;
+	output	reg	[31:0]	o_sseg;
+	output	wire	[15:0]	o_led;
+	output	wire		o_interrupt, o_ppd;
+	// GPS interface
+	input			i_gps_valid, i_gps_pps;
+	input		[31:0]	i_gps_ckspeed;
+	// Personal PPS
+	output	wire		o_rtc_pps;
+
+	reg	[23:0]	clock;
+	reg	[31:0]	stopwatch, ckspeed;
+	reg	[25:0]	timer;
+	
+	wire	ck_sel, tm_sel, sw_sel, al_sel;
+	assign	ck_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr==2'b00));
+	assign	tm_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr==2'b01));
+	assign	sw_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr==2'b10));
+	assign	al_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr==2'b11));
+
+	reg	[39:0]	ck_counter;
+	reg		ck_carry;
+	always @(posedge i_clk)
+		if ((i_gps_valid)&&(i_gps_pps))
+		begin
+			ck_carry   <= 0;
+			// Start our counter 2 clocks into the future.
+			// Why?  Because if we hit the PPS, we'll be delayed
+			// one clock from true time.  This (hopefully) locks
+			// us back onto true time.  Further, if we end up
+			// off (i.e., go off before the GPS tick ...) then
+			// the GPS tick will put us back on track ... likewise
+			// we've got code following that should keep us from
+			// ever producing two PPS's per second.
+			ck_counter <= { 7'h00, ckspeed, 1'b0 };
+		end else
+			{ ck_carry, ck_counter }<=ck_counter+{ 8'h00, ckspeed };
+
+	reg		ck_pps;
+	reg		ck_ppm, ck_pph, ck_ppd;
+	reg	[7:0]	ck_sub;
+	initial	clock = 24'h00000000;
+	always @(posedge i_clk)
+		if ((i_gps_pps)&&(i_gps_valid)&&(ck_sub[7]))
+			ck_pps <= 1'b1;
+		else if ((ck_carry)&&(ck_sub == 8'hff))
+			ck_pps <= 1'b1;
+		else
+			ck_pps <= 1'b0;
+
+	assign	o_rtc_pps = ck_pps;
+	always @(posedge i_clk)
+	begin
+		if ((i_gps_valid)&&(i_gps_pps))
+			ck_sub <= 0;
+		else if (ck_carry)
+			ck_sub <= ck_sub + 1;
+
+		if (ck_pps)
+		begin // advance the seconds
+			if (clock[3:0] >= 4'h9)
+				clock[3:0] <= 4'h0;
+			else
+				clock[3:0] <= clock[3:0] + 4'h1;
+			if (clock[7:0] >= 8'h59)
+				clock[7:4] <= 4'h0;
+			else if (clock[3:0] >= 4'h9)
+				clock[7:4] <= clock[7:4] + 4'h1;
+		end
+		ck_ppm <= (clock[7:0] == 8'h59);
+
+		if ((ck_pps)&&(ck_ppm))
+		begin // advance the minutes
+			if (clock[11:8] >= 4'h9)
+				clock[11:8] <= 4'h0;
+			else
+				clock[11:8] <= clock[11:8] + 4'h1;
+			if (clock[15:8] >= 8'h59)
+				clock[15:12] <= 4'h0;
+			else if (clock[11:8] >= 4'h9)
+				clock[15:12] <= clock[15:12] + 4'h1;
+		end
+		ck_pph <= (clock[15:0] == 16'h5959);
+
+		if ((ck_pps)&&(ck_pph))
+		begin // advance the hours
+			if (clock[21:16] >= 6'h23)
+			begin
+				clock[19:16] <= 4'h0;
+				clock[21:20] <= 2'h0;
+			end else if (clock[19:16] >= 4'h9)
+			begin
+				clock[19:16] <= 4'h0;
+				clock[21:20] <= clock[21:20] + 2'h1;
+			end else begin
+				clock[19:16] <= clock[19:16] + 4'h1;
+			end
+		end
+		ck_ppd <= (clock[21:0] == 22'h235959);
+
+
+		if ((ck_sel)&&(i_wb_we))
+		begin
+			if (8'hff != i_wb_data[7:0])
+			begin
+				clock[7:0] <= i_wb_data[7:0];
+				ck_ppm <= (i_wb_data[7:0] == 8'h59);
+			end
+			if (8'hff != i_wb_data[15:8])
+			begin
+				clock[15:8] <= i_wb_data[15:8];
+				ck_pph <= (i_wb_data[15:8] == 8'h59);
+			end
+			if (6'h3f != i_wb_data[21:16])
+				clock[21:16] <= i_wb_data[21:16];
+			clock[23:22] <= i_wb_data[25:24];
+			if ((~i_gps_valid)&&(8'h00 == i_wb_data[7:0]))
+				ck_sub <= 8'h00;
+		end
+	end
+
+	reg	[21:0]	ck_last_clock;
+	always @(posedge i_clk)
+		ck_last_clock <= clock[21:0];
+
+	reg	tm_pps, tm_ppm, tm_int;
+	wire	tm_stopped, tm_running, tm_alarm;
+	assign	tm_stopped = ~timer[24];
+	assign	tm_running =  timer[24];
+	assign	tm_alarm   =  timer[25];
+	reg	[23:0]		tm_start;
+	reg	[7:0]		tm_sub;
+	initial	tm_start = 24'h00;
+	initial	timer    = 26'h00;
+	initial	tm_int   = 1'b0;
+	initial	tm_pps   = 1'b0;
+	always @(posedge i_clk)
+	begin
+		if (ck_carry)
+		begin
+			tm_sub <= tm_sub + 1;
+			tm_pps <= (tm_sub == 8'hff);
+		end else
+			tm_pps <= 1'b0;
+		
+		if ((~tm_alarm)&&(tm_running)&&(tm_pps))
+		begin // If we are running ...
+			timer[25] <= 1'b0;
+			if (timer[23:0] == 24'h00)
+				timer[25] <= 1'b1;
+			else if (timer[3:0] != 4'h0)
+				timer[3:0] <= timer[3:0]-4'h1;
+			else begin // last digit is a zero
+				timer[3:0] <= 4'h9;
+				if (timer[7:4] != 4'h0)
+					timer[7:4] <= timer[7:4]-4'h1;
+				else begin // last two digits are zero
+					timer[7:4] <= 4'h5;
+					if (timer[11:8] != 4'h0)
+						timer[11:8] <= timer[11:8]-4'h1;
+					else begin // last three digits are zero
+						timer[11:8] <= 4'h9;
+						if (timer[15:12] != 4'h0)
+							timer[15:12] <= timer[15:12]-4'h1;
+						else begin
+							timer[15:12] <= 4'h5;
+							if (timer[19:16] != 4'h0)
+								timer[19:16] <= timer[19:16]-4'h1;
+							else begin
+							//
+								timer[19:16] <= 4'h9;
+								timer[23:20] <= timer[23:20]-4'h1;
+							end
+						end
+					end
+				end
+			end
+		end
+
+		if((~tm_alarm)&&(tm_running))
+		begin
+			timer[25] <= (timer[23:0] == 24'h00);
+			tm_int <= (timer[23:0] == 24'h00);
+		end else tm_int <= 1'b0;
+		if (tm_alarm)
+			timer[24] <= 1'b0;
+
+		if ((tm_sel)&&(i_wb_we)&&(tm_running)) // Writes while running
+			// Only allowed to stop the timer, nothing more
+			timer[24] <= i_wb_data[24];
+		else if ((tm_sel)&&(i_wb_we)&&(tm_stopped)) // Writes while off
+		begin
+			timer[24] <= i_wb_data[24];
+			if ((timer[24])||(i_wb_data[24]))
+				timer[25] <= 1'b0;
+			if (i_wb_data[23:0] != 24'h0000)
+			begin
+				timer[23:0] <= i_wb_data[23:0];
+				tm_start <= i_wb_data[23:0];
+				tm_sub <= 8'h00;
+			end else if (timer[23:0] == 24'h00)
+			begin // Resetting timer to last valid timer start val
+				timer[23:0] <= tm_start;
+				tm_sub <= 8'h00;
+			end
+			// Any write clears the alarm
+			timer[25] <= 1'b0;
+		end
+	end
+
+	//
+	// Stopwatch functionality
+	//
+	// Setting bit '0' starts the stop watch, clearing it stops it.
+	// Writing to the register with bit '1' high will clear the stopwatch,
+	// and return it to zero provided that the stopwatch is stopped either
+	// before or after the write.  Hence, writing a '2' to the device
+	// will always stop and clear it, whereas writing a '3' to the device
+	// will only clear it if it was already stopped.
+	reg		sw_pps, sw_ppm, sw_pph;
+	reg	[7:0]	sw_sub;
+	wire	sw_running;
+	assign	sw_running = stopwatch[0];
+	initial	stopwatch = 32'h00000;
+	always @(posedge i_clk)
+	begin
+		sw_pps <= 1'b0;
+		if (sw_running)
+		begin
+			if (ck_carry)
+			begin
+				sw_sub <= sw_sub + 1;
+				sw_pps <= (sw_sub == 8'hff);
+			end
+		end
+
+		stopwatch[7:1] <= sw_sub[7:1];
+
+		if (sw_pps)
+		begin // Second hand
+			if (stopwatch[11:8] >= 4'h9)
+				stopwatch[11:8] <= 4'h0;
+			else
+				stopwatch[11:8] <= stopwatch[11:8] + 4'h1;
+
+			if (stopwatch[15:8] >= 8'h59)
+				stopwatch[15:12] <= 4'h0;
+			else if (stopwatch[11:8] >= 4'h9)
+				stopwatch[15:12] <= stopwatch[15:12] + 4'h1;
+			sw_ppm <= (stopwatch[15:8] == 8'h59);
+		end else sw_ppm <= 1'b0;
+
+		if (sw_ppm)
+		begin // Minutes
+			if (stopwatch[19:16] >= 4'h9)
+				stopwatch[19:16] <= 4'h0;
+			else
+				stopwatch[19:16] <= stopwatch[19:16]+4'h1;
+
+			if (stopwatch[23:16] >= 8'h59)
+				stopwatch[23:20] <= 4'h0;
+			else if (stopwatch[19:16] >= 4'h9)
+				stopwatch[23:20] <= stopwatch[23:20]+4'h1;
+			sw_pph <= (stopwatch[23:16] == 8'h59);
+		end else sw_pph <= 1'b0;
+
+		if (sw_pph)
+		begin // And hours
+			if (stopwatch[27:24] >= 4'h9)
+				stopwatch[27:24] <= 4'h0;
+			else
+				stopwatch[27:24] <= stopwatch[27:24]+4'h1;
+
+			if((stopwatch[27:24] >= 4'h9)&&(stopwatch[31:28] < 4'hf))
+				stopwatch[31:28] <= stopwatch[27:24]+4'h1;
+		end
+
+		if ((sw_sel)&&(i_wb_we))
+		begin
+			stopwatch[0] <= i_wb_data[0];
+			if((i_wb_data[1])&&((~stopwatch[0])||(~i_wb_data[0])))
+			begin
+				stopwatch[31:1] <= 31'h00;
+				sw_sub <= 8'h00;
+				sw_pps <= 1'b0;
+				sw_ppm <= 1'b0;
+				sw_pph <= 1'b0;
+			end
+		end
+	end
+
+	//
+	// The alarm code
+	//
+	// Set the alarm register to the time you wish the board to "alarm".
+	// The "alarm" will take place once per day at that time.  At that
+	// time, the RTC code will generate a clock interrupt, and the CPU/host
+	// can come and see that the alarm tripped.
+	//
+	// 
+	reg	[21:0]		alarm_time;
+	reg			al_int,		// The alarm interrupt line
+				al_enabled,	// Whether the alarm is enabled
+				al_tripped;	// Whether the alarm has tripped
+	initial	al_enabled= 1'b0;
+	initial	al_tripped= 1'b0;
+	always @(posedge i_clk)
+	begin
+		if ((al_sel)&&(i_wb_we))
+		begin
+			// Only adjust the alarm hours if the requested hours
+			// are valid.  This allows writes to the register,
+			// without a prior read, to leave these configuration
+			// bits alone.
+			if (i_wb_data[21:16] != 6'h3f)
+				alarm_time[21:16] <= i_wb_data[21:16];
+			// Here's the same thing for the minutes: only adjust
+			// the alarm minutes if the new bits are not all 1's. 
+			if (i_wb_data[15:8] != 8'hff)
+				alarm_time[15:8] <= i_wb_data[15:8];
+			// Here's the same thing for the seconds: only adjust
+			// the alarm minutes if the new bits are not all 1's. 
+			if (i_wb_data[7:0] != 8'hff)
+				alarm_time[7:0] <= i_wb_data[7:0];
+			al_enabled <= i_wb_data[24];
+			// Reset the alarm if a '1' is written to the tripped
+			// register, or if the alarm is disabled.
+			if ((i_wb_data[25])||(~i_wb_data[24]))
+				al_tripped <= 1'b0;
+		end
+
+		al_int <= 1'b0;
+		if ((ck_last_clock != alarm_time)&&(clock[21:0] == alarm_time)&&(al_enabled))
+		begin
+			al_tripped <= 1'b1;
+			al_int <= 1'b1;
+		end
+	end
+
+	//
+	// The ckspeed register is equal to 2^48 divded by the number of
+	// clock ticks you expect per second.  Adjust high for a slower
+	// clock, lower for a faster clock.  In this fashion, a single
+	// real time clock RTL file can handle tracking the clock in any
+	// device.  Further, because this is only the lower 32 bits of a 
+	// 48 bit counter per seconds, the clock jitter is kept below
+	// 1 part in 65 thousand.
+	//
+	initial	ckspeed = DEFAULT_SPEED;
+	// In the case of verilator, comment the above and uncomment the line
+	// below.  The clock constant below is "close" to simulation time,
+	// meaning that my verilator simulation is running about 300x slower
+	// than board time.
+	// initial	ckspeed = 32'd786432000;
+	always @(posedge i_clk)
+		if (i_gps_valid)
+			ckspeed <= i_gps_ckspeed;
+
+	reg	[15:0]	h_sseg;
+	reg	[3:1]	dmask;
+	always @(posedge i_clk)
+		case(clock[23:22])
+		2'h1: begin h_sseg <= timer[15:0];
+			if (tm_alarm) dmask <= 3'h7;
+			else begin
+				dmask[3] <= (12'h000 != timer[23:12]); // timer[15:12]
+				dmask[2] <= (16'h000 != timer[23: 8]); // timer[11: 8]
+				dmask[1] <= (20'h000 != timer[23: 4]); // timer[ 7: 4]
+				// dmask[0] <= 1'b1; // Always on
+			end end
+		2'h2: begin h_sseg <= stopwatch[19:4];
+				dmask[3] <= (12'h00  != stopwatch[27:16]);
+				dmask[2] <= (16'h000 != stopwatch[27:12]);
+				dmask[1] <= 1'b1; // Always on, stopwatch[11:8]
+				// dmask[0] <= 1'b1; // Always on, stopwatch[7:4]
+			end
+		2'h3: begin h_sseg <= clock[15:0];
+				dmask[3:1] <= 3'h7;
+			end
+		default: begin // 4'h0
+			h_sseg <= { 2'b00, clock[21:8] };
+			dmask[2:1] <= 2'b11;
+			dmask[3] <= (2'b00 != clock[21:20]);
+			end
+		endcase
+
+	wire	[31:0]	w_sseg;
+	assign	w_sseg[ 0] =  (i_gps_valid)?(ck_sub[7:5]==3'h0):(~ck_sub[0]);
+	assign	w_sseg[ 8] =  (i_gps_valid)?(ck_sub[7:5]==3'h0):(~ck_sub[0]);
+	assign	w_sseg[16] =  (i_gps_valid)?(ck_sub[7:5]==3'h0):(~ck_sub[0]);
+	// assign	w_sseg[ 8] =  w_sseg[0];
+	// assign	w_sseg[16] =  w_sseg[0];
+	assign	w_sseg[24] = 1'b0;
+	hexmap	ha(i_clk, h_sseg[ 3: 0], w_sseg[ 7: 1]);
+	hexmap	hb(i_clk, h_sseg[ 7: 4], w_sseg[15: 9]);
+	hexmap	hc(i_clk, h_sseg[11: 8], w_sseg[23:17]);
+	hexmap	hd(i_clk, h_sseg[15:12], w_sseg[31:25]);
+
+	always @(posedge i_clk)
+		if ((tm_alarm || al_tripped)&&(ck_sub[7]))
+			o_sseg <= 32'h0000;
+		else
+			o_sseg <= { 
+				(dmask[3])?w_sseg[31:24]:8'h00,
+				(dmask[2])?w_sseg[23:16]:8'h00,
+				(dmask[1])?w_sseg[15: 8]:8'h00,
+				w_sseg[ 7: 0] };
+
+	reg	[17:0]	ledreg;
+	always @(posedge i_clk)
+		if ((ck_pps)&&(ck_ppm))
+			ledreg <= 18'h00;
+		else if (ck_carry)
+			ledreg <= ledreg + 18'h11;
+	assign	o_led = (tm_alarm||al_tripped)?{ (16){ck_sub[7]}}:
+				{ ledreg[17:10],
+				ledreg[10], ledreg[11], ledreg[12], ledreg[13],
+				ledreg[14], ledreg[15], ledreg[16], ledreg[17] };
+
+	assign	o_interrupt = tm_int || al_int;
+
+	// A once-per day strobe, on the last second of the day so that the
+	// the next clock is the first clock of the day.  This is useful for
+	// connecting this module to a year/month/date date/calendar module.
+	assign	o_ppd = (ck_ppd)&&(ck_pps);
+
+	always @(posedge i_clk)
+		case(i_wb_addr)
+		2'b00: o_data <= { ~i_gps_valid, 5'h0, clock[23:22], 2'b00, clock[21:0] };
+		2'b01: o_data <= { 6'h00, timer };
+		2'b10: o_data <= stopwatch;
+		2'b11: o_data <= { 6'h00, al_tripped, al_enabled, 2'b00, alarm_time };
+		endcase
+
+endmodule
diff --git a/verilog/rtl/rtc/rtclight.v b/verilog/rtl/rtc/rtclight.v
new file mode 100644
index 0000000..2bcb669
--- /dev/null
+++ b/verilog/rtl/rtc/rtclight.v
@@ -0,0 +1,413 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	rtclight.v
+//		
+// Project:	A Wishbone Controlled Real--time Clock Core
+//
+// Purpose:	Implement a real time clock, including alarm, count--down
+//		timer, stopwatch, variable time frequency, and more.
+//
+//	This is a light-weight version of the RTC found in this directory.
+//	Unlike the full RTC, this version does not support time hacks, seven
+//	segment display outputs, or LED's.  It is an RTC for an internal core
+//	only.  (That's how I was using it on one of my projects anyway ...)
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of  the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
+// target there if the PDF file isn't present.)  If not, see
+// <http://www.gnu.org/licenses/> for a copy.
+//
+// License:	GPL, v3, as defined and found on www.gnu.org,
+//		http://www.gnu.org/licenses/gpl.html
+//
+//// SPDX-License-Identifier: GPL-3.0-or-later 
+///////////////////////////////////////////////////////////////////////////
+module	rtclight(i_clk, 
+		// Wishbone interface
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
+		//	o_wb_ack, o_wb_stb, o_wb_data, // no reads here
+		// // Button inputs
+		// i_btn,
+		// Output registers
+		o_data, // multiplexed based upon i_wb_addr
+		// Output controls
+		o_interrupt,
+		// A once-per-day strobe on the last clock of the day
+		o_ppd);
+	parameter	DEFAULT_SPEED = 32'd2814750;	// 100 Mhz
+	input	i_clk;
+	input	i_wb_cyc, i_wb_stb, i_wb_we;
+	input	[2:0]	i_wb_addr;
+	input	[31:0]	i_wb_data;
+	// input		i_btn;
+	output	reg	[31:0]	o_data;
+	output	wire		o_interrupt, o_ppd;
+
+	reg	[21:0]	clock;
+	reg	[31:0]	stopwatch, ckspeed;
+	reg	[25:0]	timer;
+	
+	wire	ck_sel, tm_sel, sw_sel, sp_sel, al_sel;
+	assign	ck_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b000));
+	assign	tm_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b001));
+	assign	sw_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b010));
+	assign	al_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b011));
+	assign	sp_sel = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr[2:0]==3'b100));
+
+	reg		ck_carry;
+	reg	[39:0]	ck_counter;
+	initial		ck_carry = 1'b0;
+	initial		ck_counter = 40'h00;
+	always @(posedge i_clk)
+		{ ck_carry, ck_counter } <= ck_counter + { 8'h00, ckspeed };
+
+	wire		ck_pps;
+	reg		ck_prepps, ck_ppm, ck_pph, ck_ppd;
+	reg	[7:0]	ck_sub;
+	initial	clock = 22'h00000;
+	assign	ck_pps = (ck_carry)&&(ck_prepps);
+	always @(posedge i_clk)
+	begin
+		if (ck_carry)
+			ck_sub <= ck_sub + 8'h1;
+		ck_prepps <= (ck_sub == 8'hff);
+
+		if (ck_pps)
+		begin // advance the seconds
+			if (clock[3:0] >= 4'h9)
+				clock[3:0] <= 4'h0;
+			else
+				clock[3:0] <= clock[3:0] + 4'h1;
+			if (clock[7:0] >= 8'h59)
+				clock[7:4] <= 4'h0;
+			else if (clock[3:0] >= 4'h9)
+				clock[7:4] <= clock[7:4] + 4'h1;
+		end
+		ck_ppm <= (clock[7:0] == 8'h59);
+
+		if ((ck_pps)&&(ck_ppm))
+		begin // advance the minutes
+			if (clock[11:8] >= 4'h9)
+				clock[11:8] <= 4'h0;
+			else
+				clock[11:8] <= clock[11:8] + 4'h1;
+			if (clock[15:8] >= 8'h59)
+				clock[15:12] <= 4'h0;
+			else if (clock[11:8] >= 4'h9)
+				clock[15:12] <= clock[15:12] + 4'h1;
+		end
+		ck_pph <= (clock[15:0] == 16'h5959);
+
+		if ((ck_pps)&&(ck_pph))
+		begin // advance the hours
+			if (clock[21:16] >= 6'h23)
+			begin
+				clock[19:16] <= 4'h0;
+				clock[21:20] <= 2'h0;
+			end else if (clock[19:16] >= 4'h9)
+			begin
+				clock[19:16] <= 4'h0;
+				clock[21:20] <= clock[21:20] + 2'h1;
+			end else begin
+				clock[19:16] <= clock[19:16] + 4'h1;
+			end
+		end
+		ck_ppd <= (clock[21:0] == 22'h235959);
+
+
+		if ((ck_sel)&&(i_wb_we))
+		begin
+			if (8'hff != i_wb_data[7:0])
+			begin
+				clock[7:0] <= i_wb_data[7:0];
+				ck_ppm <= (i_wb_data[7:0] == 8'h59);
+			end
+			if (8'hff != i_wb_data[15:8])
+			begin
+				clock[15:8] <= i_wb_data[15:8];
+				ck_pph <= (i_wb_data[15:8] == 8'h59);
+			end
+			if (6'h3f != i_wb_data[21:16])
+				clock[21:16] <= i_wb_data[21:16];
+			if (8'h00 == i_wb_data[7:0])
+				ck_sub <= 8'h00;
+		end
+	end
+
+	// Clock updates take several clocks, so let's make sure we
+	// are only looking at a valid clock value before testing it.
+	reg	[21:0]		ck_last_clock;
+	always @(posedge i_clk)
+		ck_last_clock <= clock[21:0];
+		
+
+	reg	tm_pps, tm_ppm, tm_int;
+	wire	tm_stopped, tm_running, tm_alarm;
+	assign	tm_stopped = ~timer[24];
+	assign	tm_running =  timer[24];
+	assign	tm_alarm   =  timer[25];
+	reg	[23:0]		tm_start;
+	reg	[7:0]		tm_sub;
+	initial	tm_start = 24'h00;
+	initial	timer    = 26'h00;
+	initial	tm_int   = 1'b0;
+	initial	tm_pps   = 1'b0;
+	always @(posedge i_clk)
+	begin
+		if (ck_carry)
+		begin
+			tm_sub <= tm_sub + 8'h1;
+			tm_pps <= (tm_sub == 8'hff);
+		end else
+			tm_pps <= 1'b0;
+		
+		if ((~tm_alarm)&&(tm_running)&&(tm_pps))
+		begin // If we are running ...
+			timer[25] <= 1'b0;
+			if (timer[23:0] == 24'h00)
+				timer[25] <= 1'b1;
+			else if (timer[3:0] != 4'h0)
+				timer[3:0] <= timer[3:0]-4'h1;
+			else begin // last digit is a zero
+				timer[3:0] <= 4'h9;
+				if (timer[7:4] != 4'h0)
+					timer[7:4] <= timer[7:4]-4'h1;
+				else begin // last two digits are zero
+					timer[7:4] <= 4'h5;
+					if (timer[11:8] != 4'h0)
+						timer[11:8] <= timer[11:8]-4'h1;
+					else begin // last three digits are zero
+						timer[11:8] <= 4'h9;
+						if (timer[15:12] != 4'h0)
+							timer[15:12] <= timer[15:12]-4'h1;
+						else begin
+							timer[15:12] <= 4'h5;
+							if (timer[19:16] != 4'h0)
+								timer[19:16] <= timer[19:16]-4'h1;
+							else begin
+							//
+								timer[19:16] <= 4'h9;
+								timer[23:20] <= timer[23:20]-4'h1;
+							end
+						end
+					end
+				end
+			end
+		end
+
+		if((~tm_alarm)&&(tm_running))
+		begin
+			timer[25] <= (timer[23:0] == 24'h00);
+			tm_int <= (timer[23:0] == 24'h00);
+		end else tm_int <= 1'b0;
+		if (tm_alarm)
+			timer[24] <= 1'b0;
+
+		if ((tm_sel)&&(i_wb_we)&&(tm_running)) // Writes while running
+			// Only allowed to stop the timer, nothing more
+			timer[24] <= i_wb_data[24];
+		else if ((tm_sel)&&(i_wb_we)&&(tm_stopped)) // Writes while off
+		begin
+			timer[24] <= i_wb_data[24];
+			if ((timer[24])||(i_wb_data[24]))
+				timer[25] <= 1'b0;
+			if (i_wb_data[23:0] != 24'h0000)
+			begin
+				timer[23:0] <= i_wb_data[23:0];
+				tm_start <= i_wb_data[23:0];
+				tm_sub <= 8'h00;
+			end else if (timer[23:0] == 24'h00)
+			begin // Resetting timer to last valid timer start val
+				timer[23:0] <= tm_start;
+				tm_sub <= 8'h00;
+			end
+			// Any write clears the alarm
+			timer[25] <= 1'b0;
+		end
+	end
+
+	//
+	// Stopwatch functionality
+	//
+	// Setting bit '0' starts the stop watch, clearing it stops it.
+	// Writing to the register with bit '1' high will clear the stopwatch,
+	// and return it to zero provided that the stopwatch is stopped either
+	// before or after the write.  Hence, writing a '2' to the device
+	// will always stop and clear it, whereas writing a '3' to the device
+	// will only clear it if it was already stopped.
+	reg		sw_pps, sw_ppm, sw_pph;
+	reg	[7:0]	sw_sub;
+	wire	sw_running;
+	assign	sw_running = stopwatch[0];
+	initial	stopwatch = 32'h00000;
+	always @(posedge i_clk)
+	begin
+		sw_pps <= 1'b0;
+		if (sw_running)
+		begin
+			if (ck_carry)
+			begin
+				sw_sub <= sw_sub + 8'h1;
+				sw_pps <= (sw_sub == 8'hff);
+			end
+		end
+
+		stopwatch[7:1] <= sw_sub[7:1];
+
+		if (sw_pps)
+		begin // Second hand
+			if (stopwatch[11:8] >= 4'h9)
+				stopwatch[11:8] <= 4'h0;
+			else
+				stopwatch[11:8] <= stopwatch[11:8] + 4'h1;
+
+			if (stopwatch[15:8] >= 8'h59)
+				stopwatch[15:12] <= 4'h0;
+			else if (stopwatch[11:8] >= 4'h9)
+				stopwatch[15:12] <= stopwatch[15:12] + 4'h1;
+			sw_ppm <= (stopwatch[15:8] == 8'h59);
+		end else sw_ppm <= 1'b0;
+
+		if (sw_ppm)
+		begin // Minutes
+			if (stopwatch[19:16] >= 4'h9)
+				stopwatch[19:16] <= 4'h0;
+			else
+				stopwatch[19:16] <= stopwatch[19:16]+4'h1;
+
+			if (stopwatch[23:16] >= 8'h59)
+				stopwatch[23:20] <= 4'h0;
+			else if (stopwatch[19:16] >= 4'h9)
+				stopwatch[23:20] <= stopwatch[23:20]+4'h1;
+			sw_pph <= (stopwatch[23:16] == 8'h59);
+		end else sw_pph <= 1'b0;
+
+		if (sw_pph)
+		begin // And hours
+			if (stopwatch[27:24] >= 4'h9)
+				stopwatch[27:24] <= 4'h0;
+			else
+				stopwatch[27:24] <= stopwatch[27:24]+4'h1;
+
+			if((stopwatch[27:24] >= 4'h9)&&(stopwatch[31:28] < 4'hf))
+				stopwatch[31:28] <= stopwatch[27:24]+4'h1;
+		end
+
+		if ((sw_sel)&&(i_wb_we))
+		begin
+			stopwatch[0] <= i_wb_data[0];
+			if((i_wb_data[1])&&((~stopwatch[0])||(~i_wb_data[0])))
+			begin
+				stopwatch[31:1] <= 31'h00;
+				sw_sub <= 8'h00;
+				sw_pps <= 1'b0;
+				sw_ppm <= 1'b0;
+				sw_pph <= 1'b0;
+			end
+		end
+	end
+
+	//
+	// The alarm code
+	//
+	// Set the alarm register to the time you wish the board to "alarm".
+	// The "alarm" will take place once per day at that time.  At that
+	// time, the RTC code will generate a clock interrupt, and the CPU/host
+	// can come and see that the alarm tripped.
+	//
+	// 
+	reg	[21:0]		alarm_time;
+	reg			al_int,		// The alarm interrupt line
+				al_enabled,	// Whether the alarm is enabled
+				al_tripped;	// Whether the alarm has tripped
+	initial	al_enabled= 1'b0;
+	initial	al_tripped= 1'b0;
+	always @(posedge i_clk)
+	begin
+		if ((al_sel)&&(i_wb_we))
+		begin
+			// Only adjust the alarm hours if the requested hours
+			// are valid.  This allows writes to the register,
+			// without a prior read, to leave these configuration
+			// bits alone.
+			if (i_wb_data[21:16] != 6'h3f)
+				alarm_time[21:16] <= i_wb_data[21:16];
+			// Here's the same thing for the minutes: only adjust
+			// the alarm minutes if the new bits are not all 1's. 
+			if (i_wb_data[15:8] != 8'hff)
+				alarm_time[15:8] <= i_wb_data[15:8];
+			// Here's the same thing for the seconds: only adjust
+			// the alarm minutes if the new bits are not all 1's. 
+			if (i_wb_data[7:0] != 8'hff)
+				alarm_time[7:0] <= i_wb_data[7:0];
+			al_enabled <= i_wb_data[24];
+			// Reset the alarm if a '1' is written to the tripped
+			// register, or if the alarm is disabled.
+			if ((i_wb_data[25])||(~i_wb_data[24]))
+				al_tripped <= 1'b0;
+		end
+
+		al_int <= 1'b0;
+		if ((ck_last_clock != alarm_time)&&(clock[21:0] == alarm_time)
+			&&(al_enabled))
+		begin
+			al_tripped <= 1'b1;
+			al_int <= 1'b1;
+		end
+	end
+
+	//
+	// The ckspeed register is equal to 2^48 divded by the number of
+	// clock ticks you expect per second.  Adjust high for a slower
+	// clock, lower for a faster clock.  In this fashion, a single
+	// real time clock RTL file can handle tracking the clock in any
+	// device.  Further, because this is only the lower 32 bits of a 
+	// 48 bit counter per seconds, the clock jitter is kept below
+	// 1 part in 65 thousand.
+	//
+	initial	ckspeed = DEFAULT_SPEED; // 2af31e = 2^48 / 100e6 MHz
+	// In the case of verilator, comment the above and uncomment the line
+	// below.  The clock constant below is "close" to simulation time,
+	// meaning that my verilator simulation is running about 300x slower
+	// than board time.
+	// initial	ckspeed = 32'd786432000;
+	always @(posedge i_clk)
+		if ((sp_sel)&&(i_wb_we))
+			ckspeed <= i_wb_data;
+
+	assign	o_interrupt = tm_int || al_int;
+
+	// A once-per day strobe, on the last second of the day so that the
+	// the next clock is the first clock of the day.  This is useful for
+	// connecting this module to a year/month/date date/calendar module.
+	assign	o_ppd = (ck_ppd)&&(ck_pps);
+
+	always @(posedge i_clk)
+		case(i_wb_addr[2:0])
+		3'b000: o_data <= { 10'h0, ck_last_clock };
+		3'b001: o_data <= { 6'h00, timer };
+		3'b010: o_data <= stopwatch;
+		3'b011: o_data <= { 6'h00, al_tripped, al_enabled, 2'b00, alarm_time };
+		3'b100: o_data <= ckspeed;
+		default: o_data <= 32'h000;
+		endcase
+
+endmodule
diff --git a/verilog/rtl/user_proj_example.v b/verilog/rtl/user_proj_example.v
index b33e032..7996cdc 100644
--- a/verilog/rtl/user_proj_example.v
+++ b/verilog/rtl/user_proj_example.v
@@ -1,5 +1,3 @@
-// SPDX-FileCopyrightText: 2020 Efabless Corporation
-//
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
@@ -14,6 +12,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 `default_nettype none
+
 /*
  *-------------------------------------------------------------
  *
@@ -58,8 +57,8 @@
     input [3:0] wbs_sel_i,
     input [31:0] wbs_dat_i,
     input [31:0] wbs_adr_i,
-    output wbs_ack_o,
-    output [31:0] wbs_dat_o,
+    output reg wbs_ack_o,
+    output reg [31:0] wbs_dat_o,
 
     // Logic Analyzer Signals
     input  [127:0] la_data_in,
@@ -76,11 +75,9 @@
 );
     wire clk;
     wire rst;
-
     wire [`MPRJ_IO_PADS-1:0] io_in;
     wire [`MPRJ_IO_PADS-1:0] io_out;
     wire [`MPRJ_IO_PADS-1:0] io_oeb;
-
     wire [31:0] rdata; 
     wire [31:0] wdata;
     wire [BITS-1:0] count;
@@ -89,83 +86,212 @@
     wire [3:0] wstrb;
     wire [31:0] la_write;
 
-    // WB MI A
-    assign valid = wbs_cyc_i && wbs_stb_i; 
-    assign wstrb = wbs_sel_i & {4{wbs_we_i}};
-    assign wbs_dat_o = rdata;
-    assign wdata = wbs_dat_i;
+    wire pwm1_select , pwm2_select , i2c_select , rtc_select , pid_select ;
+    wire pwm1_wbs_stb_i , pwm2_wbs_stb_i , i2c_wbs_stb_i , rtc_wbs_stb_i , pid_wbs_stb_i ;
+    wire pwm1_wbs_ack_o , pwm2_wbs_ack_o , i2c_wbs_ack_o , rtc_wbs_ack_o , pid_wbs_ack_o ; 
 
-    // IO
-    assign io_out = count;
-    assign io_oeb = {(`MPRJ_IO_PADS-1){rst}};
+    wire [31:0] pwm1_wbs_dat_o ;
+    wire [31:0] pwm2_wbs_dat_o ;
+    wire [7:0] i2c_wbs_dat_o ;
+    wire [31:0] rtc_wbs_dat_o ;
+    wire [31:0] pid_wbs_dat_o  ;
+
+    wire pwm_out1 , pwm_out2 ;
+    wire pwm_out1_oen , pwm_out2_oen ;
+    wire ptc1_intr , ptc2_intr , i2c_intr , rtc_intr ;
+    reg led1, led2, led3 ; 
+    wire ptc_clk1,ptc_clk2;
+    wire capt_in1,capt_in2;
+    wire i2c_scl_in, i2c_sda_in, scl_pad_o, scl_padoen_o, sda_pad_o, sda_padoen_o ; 
+
+    assign ptc_clk1 = io_in[0] ;                           // IO[0]
+    assign io_oeb[0]= 1'b1;
+
+    assign ptc_clk2 = io_in[1] ;                           // IO[1]
+    assign io_oeb[1]= 1'b1;
+
+    assign capt_in1 = io_in[2] ;                           // IO[2]
+    assign io_oeb[1]= 1'b1;
+
+    assign capt_in2 = io_in[3] ;                           // IO[3]
+    assign io_oeb[1]= 1'b1;
+
+    
+    assign io_out[5:4] = la_data_in[110:109] ;             // IO[5:4]
+    assign io_oeb[5:4] = la_oenb[110:109]    ;
+
+    assign io_out[7:6] = {pwm_out2,pwm_out1} ;             // IO[7:6]
+    assign io_oeb[7:6] = {pwm_out2_oen,pwm_out1_oen} ;
+
+    assign io_out[8] = scl_pad_o ;                         // IO[8]
+    assign io_oeb[8] = scl_padoen_o ;
+
+    assign i2c_scl_in = io_in[9] ;                         // IO[9]
+    assign io_oeb[9]= 1'b1;
+
+    assign io_out[10] = sda_pad_o ;                        // IO[10]
+    assign io_oeb[10] = sda_padoen_o;
+
+    assign i2c_sda_in = io_in[11] ;                        // IO[11]
+    assign io_oeb[11]= 1'b1;
+
+    // Inputs
 
     // IRQ
-    assign irq = 3'b000;	// Unused
+    assign irq = {rtc_intr , i2c_intr , {ptc2_intr || ptc1_intr} };	
 
     // LA
-    assign la_data_out = {{(127-BITS){1'b0}}, count};
-    // Assuming LA probes [63:32] are for controlling the count register  
-    assign la_write = ~la_oenb[63:32] & ~{BITS{valid}};
-    // Assuming LA probes [65:64] are for controlling the count clk & reset  
-    assign clk = (~la_oenb[64]) ? la_data_in[64]: wb_clk_i;
-    assign rst = (~la_oenb[65]) ? la_data_in[65]: wb_rst_i;
+   assign clk = wb_clk_i ;
+   assign rst = wb_rst_i ;
 
-    counter #(
-        .BITS(BITS)
-    ) counter(
-        .clk(clk),
-        .reset(rst),
-        .ready(wbs_ack_o),
-        .valid(valid),
-        .rdata(rdata),
-        .wdata(wbs_dat_i),
-        .wstrb(wstrb),
-        .la_write(la_write),
-        .la_input(la_data_in[63:32]),
-        .count(count)
-    );
+   // Module Address Select Logic
+   assign pwm1_select = (wbs_adr_i[31:12] == 20'h30001) ;
+   assign pwm2_select = (wbs_adr_i[31:12] == 20'h30002) ;
+   assign i2c_select  = (wbs_adr_i[31:12] == 20'h30003) ;
+   assign rtc_select  = (wbs_adr_i[31:12] == 20'h30004) ;
+   assign pid_select  = (wbs_adr_i[31:12] == 20'h30005) ;
+  
+   // Module STROBE Select based on Address Range
+   assign pwm1_wbs_stb_i = (wbs_stb_i && pwm1_select) ;
+   assign pwm2_wbs_stb_i = (wbs_stb_i && pwm2_select) ;
+   assign i2c_wbs_stb_i  = (wbs_stb_i && i2c_select)  ;
+   assign rtc_wbs_stb_i  = (wbs_stb_i && rtc_select)  ;
+   assign pid_wbs_stb_i  = (wbs_stb_i && pid_select)  ;
 
-endmodule
 
-module counter #(
-    parameter BITS = 32
-)(
-    input clk,
-    input reset,
-    input valid,
-    input [3:0] wstrb,
-    input [BITS-1:0] wdata,
-    input [BITS-1:0] la_write,
-    input [BITS-1:0] la_input,
-    output ready,
-    output [BITS-1:0] rdata,
-    output [BITS-1:0] count
-);
-    reg ready;
-    reg [BITS-1:0] count;
-    reg [BITS-1:0] rdata;
+   // Slave Acknowledge Response 
+   always @(posedge clk)
+	   wbs_ack_o <= (pwm1_wbs_ack_o || pwm2_wbs_ack_o || i2c_wbs_ack_o || rtc_wbs_ack_o || pid_wbs_ack_o) ;
 
-    always @(posedge clk) begin
-        if (reset) begin
-            count <= 0;
-            ready <= 0;
-        end else begin
-            ready <= 1'b0;
-            if (~|la_write) begin
-                count <= count + 1;
-            end
-            if (valid && !ready) begin
-                ready <= 1'b1;
-                rdata <= count;
-                if (wstrb[0]) count[7:0]   <= wdata[7:0];
-                if (wstrb[1]) count[15:8]  <= wdata[15:8];
-                if (wstrb[2]) count[23:16] <= wdata[23:16];
-                if (wstrb[3]) count[31:24] <= wdata[31:24];
-            end else if (|la_write) begin
-                count <= la_write & la_input;
-            end
-        end
-    end
+   // Slave Return Data
+   always @(posedge clk)
+	   if (pwm1_wbs_ack_o)
+		   wbs_dat_o <= pwm1_wbs_dat_o ;
+	   else if (pwm2_wbs_ack_o)
+		   wbs_dat_o <= pwm2_wbs_dat_o ;
+	   else if (i2c_wbs_ack_o)
+		   wbs_dat_o <= {24'b0,i2c_wbs_dat_o} ;
+	   else if (rtc_wbs_ack_o)
+		   wbs_dat_o <= rtc_wbs_dat_o ;
+	   else if (pid_wbs_ack_o)
+		   wbs_dat_o <= pid_wbs_dat_o ;
+	   else
+		   wbs_dat_o <= 32'h0 ;
+
+
+	   
+   // PTC1 Module instantiations 
+   ptc_top ptc1_i (
+	   .wb_clk_i (clk),
+	   .wb_rst_i (rst),
+	   .wb_cyc_i (wbs_cyc_i),
+	   .wb_adr_i ({8'h0,wbs_adr_i[7:0]}), // 16-bit address
+	   .wb_dat_i (wbs_dat_i),    
+	   .wb_sel_i (wbs_sel_i),
+	   .wb_we_i  (wbs_we_i),
+	   .wb_stb_i (pwm1_wbs_stb_i),
+	   .wb_dat_o (pwm1_wbs_dat_o),
+	   .wb_ack_o (pwm1_wbs_ack_o),
+	   .wb_err_o ( ),
+	   .wb_inta_o (ptc1_intr),
+	   .gate_clk_pad_i (ptc_clk1),
+	   .capt_pad_i (capt_in1),
+	   .pwm_pad_o (pwm_out1), 
+	   .oen_padoen_o (pwm_out1_oen)
+   ); 
+
+   // PTC2 Module instantiations 
+
+ ptc_top ptc2_i (
+	   .wb_clk_i (clk),
+	   .wb_rst_i (rst),
+	   .wb_cyc_i (wbs_cyc_i),
+	   .wb_adr_i ({8'h0,wbs_adr_i[7:0]}), // 16-bit address
+	   .wb_dat_i (wbs_dat_i),    
+	   .wb_sel_i (wbs_sel_i),
+	   .wb_we_i  (wbs_we_i),
+	   .wb_stb_i (pwm2_wbs_stb_i),
+	   .wb_dat_o (pwm2_wbs_dat_o),
+	   .wb_ack_o (pwm2_wbs_ack_o),
+	   .wb_err_o ( ),
+	   .wb_inta_o (ptc2_intr),
+	   .gate_clk_pad_i (ptc_clk2),
+	   .capt_pad_i (capt_in2),
+	   .pwm_pad_o (pwm_out2), 
+	   .oen_padoen_o (pwm_out2_oen)
+   );
+
+   // I2C Module Instanciation 
+ i2c_master_top i2c_i (
+	   .wb_clk_i (clk),
+	   .wb_rst_i (rst),
+	   .arst_i   (1'b1),
+	   .wb_adr_i (wbs_adr_i[4:2]), // 3-bit address
+	   .wb_dat_i (wbs_dat_i[7:0]), // 8-bit data    
+	   .wb_dat_o (i2c_wbs_dat_o),  // 8-bit data
+	   .wb_we_i  (wbs_we_i),
+	   .wb_stb_i (i2c_wbs_stb_i ),
+	   .wb_cyc_i (wbs_cyc_i),
+	   .wb_ack_o (i2c_wbs_ack_o),
+	   .wb_inta_o (i2c_intr),
+	   .scl_pad_i (i2c_scl_in),
+	   .scl_pad_o (scl_pad_o),
+	   .scl_padoen_o (scl_padoen_o),
+	   .sda_pad_i (i2c_sda_in),
+	   .sda_pad_o (sda_pad_o),
+	   .sda_padoen_o (sda_padoen_o)
+   );
+
+   // RTC Module Instanciation
+
+  rtcdate rtc_date_i (
+	  .i_clk (clk),
+	  .i_ppd (la_data_in[111]),
+	  .i_wb_cyc (wbs_cyc_i),
+	  .i_wb_stb (rtc_wbs_stb_i),
+	  .i_wb_we (wbs_we_i),
+	  .i_wb_data (wbs_dat_i),
+	  .o_wb_ack (rtc_wbs_ack_o),
+	  .o_wb_data (rtc_wbs_dat_o)
+  );
+
+/*
+   // PID Module Instantiation 
+  PID pid (
+	  .i_clk (clk),
+	  .i_rst (rst),
+	  .i_wb_cyc (wbs_cyc_i),
+	  .i_wb_stb (pid_wbs_stb_i),
+	  .i_wb_we (wbs_we_i),
+	  .i_wb_adr ({8'h0,wbs_adr_i[7:0]}), // 16-bit address
+	  .i_wb_data (wbs_dat_i),
+	  .o_wb_ack (pid_wbs_ack_o),
+	  .o_wb_data (pid_wbs_dat_o),
+	  .o_un (),
+	  .o_valid ()
+  ); 
+
+
+   // FPU Instanciation
+   fpu fpu_i (
+
+	   .clk 	(clk),
+	   .rmode 	(la_data_in[105:104]), 	// 2-bit
+	   .fpu_op 	(la_data_in[108:106]), 	// 3-bit
+	   .opa 	(la_data_in[31:0]),	// 32-bit
+	   .opb		(la_data_in[63:32]),	// 32-bit
+	   .out		(la_data_in[95:64]), 	// 32-bit
+	   .inf		(la_data_out[96]),
+	   .snan	(la_data_out[97]),
+	   .qnan	(la_data_out[98]),
+	   .ine		(la_data_out[99]),
+	   .overflow	(la_data_out[100]),
+	   .underflow	(la_data_out[101]),
+	   .zero	(la_data_out[102]),
+	   .div_by_zero	(la_data_out[103]),
+
+   );
+*/
 
 endmodule
 `default_nettype wire