OpenCores
URL https://opencores.org/ocsvn/common/common/trunk

Subversion Repositories common

[/] [common/] [trunk/] [LPM_arithmetic.v] - Rev 48

Compare with Previous | Blame | View Log

//------------------------------------------------------------------------
//   This Verilog file was developed by Altera Corporation.  It may be
// freely copied and/or distributed at no cost.  Any persons using this
// file for any purpose do so at their own risk, and are responsible for
// the results of such use.  Altera Corporation does not guarantee that
// this file is complete, correct, or fit for any particular purpose.
// NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED.  This notice must
// accompany any copy of this file.
//
//------------------------------------------------------------------------
// Imported to Opencores directory.   Date Sept 10, 2001
// Split related modules into separate files, as the manual splits them.
// Added example instantiations to the beginning of each file.
//
/* EXAMPLE INSTANTIATIONS:
 
lpm_add_sub
#( 1,                         // lpm_width (width of input vector)
   "UNUSED",                  // lpm_direction, optional, {ADD, SUB}
   "UNSIGNED",                // lpm_representation, optional, {UNSIGNED, SIGNED}
   0                          // lpm_pipeline, optional, {0, 1}
 ) lpm_add_sub_example (
  .result                     (data_out[lpm_width-1:0]),
  .cout                       (carry_out_indicates_unsigned_result_too_big),  // OPTIONAL
  .overflow                   (overflow_indicates_MSB_sign_bit_wrong),  // OPTIONAL
  .dataa                      (data_in[lpm_width-1:0]),
  .datab                      (data_pl_mi_in[lpm_width-1:0]),
  .cin                        (add_1_if_HIGH_sub_1_if_LOW),      // OPTIONAL
  .add_sub                    (add_if_HIGH_must_set_HIGH_if_using_lpm_direction),  // OPTIONAL
  .clock                      (clock_if_pipelined),              // OPTIONAL
  .clken                      (clock_enable_HIGH_if_pipelined),  // OPTIONAL
  .aclr                       (async_clear_if_pipelined)         // OPTIONAL
);
 
lpm_compare
#( 1,                         // lpm_width (width of input vector)
   "UNSIGNED",                // lpm_representation, optional, {UNSIGNED, SIGNED}
   0                          // lpm_pipeline, optional, {0, 1}
 ) lpm_compare_example (
  .agb                        (a_greater_than_b),
  .ageb                       (a_greater_or_equil_to_b),
  .aeb                        (a_equil_to_b),
  .aleb                       (a_less_or_equil_to_b),
  .alb                        (a_less_than_b),
  .aneb                       (a_not_equil_b),
  .dataa                      (data_in_a[lpm_width-1:0]),
  .datab                      (data_in_a[lpm_width-1:0]),
  .clock                      (clock_if_pipelined),              // OPTIONAL
  .clken                      (clock_enable_HIGH_if_pipelined),  // OPTIONAL
  .aclr                       (async_clear_if_pipelined)         // OPTIONAL
);
 
module lpm_mult (
#( 1,                         // lpm_widtha (width of input vector)
   1,                         // lpm_widthb (width of input vector)
   1,                         // lpm_widths (width of partial sum vector)
   1,                         // lpm_widthp (width of product vector)
   "UNSIGNED",                // lpm_representation, optional, {UNSIGNED, SIGNED}
   0                          // lpm_pipeline, optional, {0, 1}
 ) lpm_mult_example (
  .result                     (data_out[lpm_widthp-1:0]),
  .sum                        (partial_sum_in[lpm_widths-1:0]),  // OPTIONAL
  .dataa                      (multiplicand_a_in[lpm_widtha-1:0]),
  .datab                      (multiplicand_b_in[lpm_widthb-1:0]),
  .clock                      (clock_if_pipelined),              // OPTIONAL
  .clken                      (clock_enable_HIGH_if_pipelined),  // OPTIONAL
  .aclr                       (async_clear_if_pipelined)         // OPTIONAL
);
 
lpm_divide
#( 1,                         // lpm_widthn (width of numerator)
   1,                         // lpm_widthn (width of denominator)
   "UNSIGNED",                // lpm_nrepresentation, optional, {UNSIGNED, SIGNED}
   "UNSIGNED",                // lpm_drepresentation, optional, {UNSIGNED, SIGNED}
   0                          // lpm_pipeline, optional, {0, 1}
 ) lpm_divide_example (
  .quotient                   (data_out[lpm_widthn-1:0]),  // CHOICE
  .remain                     (data_out[lpm_widthd-1:0]),  // CHOICE
  .numer                      (data_out[lpm_widthn-1:0]),
  .denom                      (data_out[lpm_widthd-1:0]),
  .clock                      (clock_if_pipelined),              // OPTIONAL
  .clken                      (clock_enable_HIGH_if_pipelined),  // OPTIONAL
  .aclr                       (async_clear_if_pipelined)         // OPTIONAL
);
 
lpm_abs
#( 1                          // lpm_width (width of input)
 ) lpm_abs_example (
  .result                     (data_out[lpm_width-1:0]),
  .overflow                   (overflow_because_negative_number_was_max),  // OPTIONAL
  .data                       (data_in[lpm_width-1:0])
);
 
module lpm_counter (
#( 1,                         // lpm_width (width of input)
   0,                         // lpm_modulus (max count plus 1)
   "UNUSED",                  // lpm_direction, optional, {UNUSED, UP, DOWN}
   "UNUSED",                  // lpm_avalue, value to load if ASET active
   "UNUSED",                  // lpm_svalue, value to load if SSET active
   "UNUSED",                  // lpm_pvalue, value to load at powerup
   "lpm_counter",             // lpm_type, optional, must be "lpm_counter if lpm_hint used
   "UNUSED"                   // lpm_hint, optional, {UNSIGNED, SIGNED, BCD, GRAY_CODE, JOHNSON, LFSR}
 ) lpm_counter_example (
  .cout                       (max_value_reached),                       // CHOICE
  .q                          (counter_out[lpm_width-1:0]),              // CHOICE
  .data                       (sync_data_in[lpm_width-1:0]),             // OPTIONAL
  .sload                      (load_counter_with_data_next_clock),       // OPTIONAL
  .sset                       (set_counter_to_max_or_lpm_svalue_next_clock),  // OPTIONAL
  .sclr                       (clear_counter_next_clock),                // OPTIONAL
  .cnt_en                     (enable_counting_when_HIGH),               // OPTIONAL
  .cin                        (carry_in_to_enable_counter),              // OPTIONAL
  .updown                     (inc_if_HIGH_must_set_LOW_if_using_lpm_direction),  // OPTIONAL
  .clock                      (clock_if_pipelined),
  .clk_en                     (enable_all_sync_activity_when_HIGH),      // OPTIONAL
  .aload                      (async_load_counter_with_data),            // OPTIONAL
  .aset                       (async_set_counter_to_max_or_lpm_avalue),  // OPTIONAL
  .aclr                       (async_clear_if_pipelined)                 // OPTIONAL
);
*/
 
//------------------------------------------------------------------------
// LPM Synthesizable Models
//------------------------------------------------------------------------
// Version 1.5 (lpm 220)      Date 12/17/99
//
// Modified LPM_ADD_SUB and LPM_MULT to accomodate LPM_WIDTH = 1.
//   Default values for LPM_WIDTH* are changed back to 1.
// Added LPM_HINT to LPM_DIVIDE.
// Rewritten LPM_FIFO_DC to output correctly.
// Modified LPM_FIFO to output 0s before first read, output correct
//   values after aclr and sclr, and output LPM_NUMWORDS mod
//   exp(2, LPM_WIDTHU) when FIFO is full.
//
//------------------------------------------------------------------------
// Version 1.4.1 (lpm 220)    Date 10/29/99
//
// Default values for LPM_WIDTH* of LPM_ADD_SUB and LPM_MULT are changed
//   from 1 to 2.
//
//------------------------------------------------------------------------
// Version 1.4 (lpm 220)      Date 10/18/99
//
// Default values for each optional inputs for ALL modules are added.
// Some LPM_PVALUE implementations were missing, and now implemented.
//
//------------------------------------------------------------------------
// Version 1.3 (lpm 220)      Date 06/23/99
//
// Corrected LPM_FIFO and LPM_FIFO_DC cout and empty/full flags.
// Implemented LPM_COUNTER cin/cout, and LPM_MODULUS is now working.
//
//------------------------------------------------------------------------
// Version 1.2 (lpm 220)      Date 06/16/99
//
// Added LPM_RAM_DP, LPM_RAM_DQ, LPM_IO, LPM_ROM, LPM_FIFO, LPM_FIFO_DC.
// Parameters and ports are added/discarded according to the spec.
//
//------------------------------------------------------------------------
// Version 1.1 (lpm 220)      Date 02/05/99
//
// Added LPM_DIVIDE module.
//
//------------------------------------------------------------------------
// Version 1.0                Date 07/09/97
//
//------------------------------------------------------------------------
// Excluded Functions:
//
//  LPM_FSM and LPM_TTABLE.
//
//------------------------------------------------------------------------
// Assumptions:
//
// 1. LPM_SVALUE, LPM_AVALUE, LPM_MODULUS, and LPM_NUMWORDS,
//    LPM_STRENGTH, LPM_DIRECTION, and LPM_PVALUE  default value is
//    string UNUSED.
//
//------------------------------------------------------------------------
// Verilog Language Issues:
//
// Two dimensional ports are not supported. Modules with two dimensional
// ports are implemented as one dimensional signal of (LPM_SIZE * LPM_WIDTH)
// bits wide.
//
//------------------------------------------------------------------------
// Synthesis Issues:
// 
// 1. LPM_COUNTER 
//
// Currently synthesis tools do not allow mixing of level and edge
// sensetive signals. To overcome that problem the "data" signal is
// removed from the clock always block of lpm_counter, however the
// synthesis result is accurate. For correct simulation add the "data"
// pin to the sensetivity list as follows:
//
//  always @(posedge clock or posedge aclr or posedge aset or 
//           posedge aload or data)
//------------------------------------------------------------------------
 
module lpm_add_sub ( result, cout, overflow,
					 add_sub, cin, dataa, datab, clock, clken, aclr );
 
// NOTE: Parameters must be declared in the same order as the Properties
//       are specified in the Cell Specification document.
	parameter lpm_width = 1;
	parameter lpm_direction  = "UNUSED";
	parameter lpm_representation = "UNSIGNED";
	parameter lpm_pipeline = 0;
	parameter lpm_type = "lpm_add_sub";
	parameter lpm_hint = "UNUSED";
	parameter lpm_source_version = "lpm 220 version 1.6";
 
	input  [lpm_width-1:0] dataa, datab;
	input  add_sub, cin;
	input  clock;
	input  clken;
	input  aclr;
	output [lpm_width-1:0] result;
	output cout, overflow;
 
	reg  [lpm_width-1:0] tmp_result;
	reg  [lpm_width-1:0] tmp_result2 [lpm_pipeline:0];
	reg  [lpm_pipeline:0] tmp_cout2;
	reg  [lpm_pipeline:0] tmp_overflow2;
	reg  tmp_cout;
	reg  tmp_overflow;
	reg  [lpm_width-1:0] tmp_a, tmp_b;
	integer i, j, k, n;
	integer dataa_int, datab_int, result_int, compare, borrow; 
 
	tri0 aclr;
	tri0 clock;
	tri1 clken;
	tri0 cin;
	tri1 add_sub;
 
	buf (i_aclr, aclr);
	buf (i_clock, clock);
	buf (i_clken, clken);
	buf (i_cin, cin);
	buf (i_add_sub, add_sub);
 
 
	always @(i_cin or dataa or datab or i_add_sub)
	begin
		borrow = i_cin ? 0 : 1;
		// cout is the same for both signed and unsign representation.  
		if (lpm_direction == "ADD" || i_add_sub == 1) 
		begin
			{tmp_cout,tmp_result} = dataa + datab + i_cin;
			tmp_overflow = tmp_cout;
		end
		else if (lpm_direction == "SUB" || i_add_sub == 0) 
		begin
			// subtraction
			{tmp_overflow, tmp_result} = dataa - datab - borrow;
			tmp_cout = (dataa >= (datab+borrow))?1:0;
		end
 
		if (lpm_representation == "SIGNED")
		begin
			// convert to negative integer
			if (dataa[lpm_width-1] == 1)
			begin
				for (j = 0; j < lpm_width; j = j + 1)
					tmp_a[j] = dataa[j] ^ 1;
				dataa_int = (tmp_a) * (-1) - 1;
			end
			else
				dataa_int = dataa;
 
			// convert to negative integer
			if (datab[lpm_width-1] == 1)
			begin
				for (k = 0; k < lpm_width; k = k + 1)
					tmp_b[k] = datab[k] ^ 1;
				datab_int = (tmp_b) * (-1) - 1;
			end
			else
				datab_int = datab;
 
			// perform the addtion or subtraction operation
			if (lpm_direction == "ADD" || i_add_sub == 1)
				result_int = dataa_int + datab_int + i_cin;
			else if (lpm_direction == "SUB" || i_add_sub == 0)
				result_int = dataa_int - datab_int - borrow;
			tmp_result = result_int;
 
			// set the overflow
			compare = 1 << (lpm_width -1);
			if ((result_int > (compare - 1)) || (result_int < (-1)*(compare)))
				tmp_overflow = 1;
			else
				tmp_overflow = 0;
		end
	end
 
 
	always @(posedge i_clock or posedge i_aclr)
	begin
		if (i_aclr)
		begin
			for (i = 0; i <= lpm_pipeline; i = i + 1)
			begin
				tmp_result2[i] = 'b0;
				tmp_cout2[i] = 1'b0;
				tmp_overflow2[i] = 1'b0;
			end
		end
		else if (i_clken == 1)
		begin
			tmp_result2[lpm_pipeline] = tmp_result;
			tmp_cout2[lpm_pipeline] = tmp_cout;
			tmp_overflow2[lpm_pipeline] = tmp_overflow;
			for (n = 0; n < lpm_pipeline; n = n + 1)
			begin
				tmp_result2[n] = tmp_result2[n+1];
				tmp_cout2[n] = tmp_cout2[n+1];
				tmp_overflow2[n] = tmp_overflow2[n+1];
			end
		end
	end
 
 
	assign result = (lpm_pipeline >0) ? tmp_result2[0]:tmp_result;
	assign cout = (lpm_pipeline >0) ? tmp_cout2[0]  : tmp_cout;
	assign overflow = (lpm_pipeline >0) ? tmp_overflow2[0] : tmp_overflow;
 
// Check for previous Parameter declaration order
initial if ((lpm_width === "lpm_add_sub") || (lpm_type !== "lpm_add_sub"))
  begin
    $display ("LPM 220 Version 1.6 Parameter Order changed; update instantiation");
    $finish;
  end
endmodule // lpm_add_sub
 
//------------------------------------------------------------------------
 
module lpm_compare ( alb, aeb, agb, aleb, aneb, ageb, dataa, datab,
					 clock, clken, aclr );
 
// NOTE: Parameters must be declared in the same order as the Properties
//       are specified in the Cell Specification document.
	parameter lpm_width = 1;
	parameter lpm_representation = "UNSIGNED";
	parameter lpm_pipeline = 0;
	parameter lpm_type = "lpm_compare";
	parameter lpm_hint = "UNUSED";
	parameter lpm_source_version = "lpm 220 version 1.6";
 
	input  [lpm_width-1:0] dataa, datab;
	input  clock;
	input  clken;
	input  aclr;
	output alb, aeb, agb, aleb, aneb, ageb;
 
	reg    tmp_alb, tmp_aeb, tmp_agb;
	reg    tmp_aleb, tmp_aneb, tmp_ageb;
	reg    [lpm_pipeline:0] tmp_alb2, tmp_aeb2, tmp_agb2;
	reg    [lpm_pipeline:0] tmp_aleb2, tmp_aneb2, tmp_ageb2;
	reg    [lpm_width-1:0] a_int;
	integer i, j, k, l, m, n, o, p, u, dataa_int, datab_int;
 
	tri0 aclr;
	tri0 clock;
	tri1 clken;
 
	buf (i_aclr, aclr);
	buf (i_clock, clock);
	buf (i_clken, clken);
 
 
	always @(dataa or datab)
	begin
		if (lpm_representation == "UNSIGNED") 
		begin
			dataa_int = dataa[lpm_width-1:0];
			datab_int = datab[lpm_width-1:0];
		end
		else if (lpm_representation == "SIGNED")
		begin
			// convert to negative integer
			if (dataa[lpm_width-1] == 1)
			begin
				for (j = 0; j < lpm_width; j = j + 1)
					a_int[j] = dataa[j] ^ 1;
				dataa_int = (a_int) * (-1) - 1;
			end
			else
				dataa_int = dataa;
 
			// convert to negative integer
			if (datab[lpm_width-1] == 1)
			begin
				for (j = 0; j < lpm_width; j = j + 1)
					a_int[j] = datab[j] ^ 1;
				datab_int = (a_int) * (-1) - 1;
			end
			else
				datab_int = datab;
		end
 
		tmp_alb = (dataa_int < datab_int);
		tmp_aeb = (dataa_int == datab_int);
		tmp_agb = (dataa_int > datab_int);
		tmp_aleb = (dataa_int <= datab_int);
		tmp_aneb = (dataa_int != datab_int);
		tmp_ageb = (dataa_int >= datab_int);
	end
 
	always @(posedge i_clock or posedge i_aclr)
	begin
		if (i_aclr)
		begin 
			for (u = 0; u <= lpm_pipeline; u = u +1)
			begin
				tmp_aeb2[u] = 'b0;
				tmp_agb2[u] = 'b0;
				tmp_alb2[u] = 'b0;
				tmp_aleb2[u] = 'b0;
				tmp_aneb2[u] = 'b0;
				tmp_ageb2[u] = 'b0;
			end
		end
		else if (i_clken == 1)
		begin
			// Assign results to registers
			tmp_alb2[lpm_pipeline] = tmp_alb;
			tmp_aeb2[lpm_pipeline] = tmp_aeb;
			tmp_agb2[lpm_pipeline] = tmp_agb;
			tmp_aleb2[lpm_pipeline] = tmp_aleb;
			tmp_aneb2[lpm_pipeline] = tmp_aneb;
			tmp_ageb2[lpm_pipeline] = tmp_ageb;
 
			for (k = 0; k < lpm_pipeline; k = k +1)
				tmp_alb2[k] = tmp_alb2[k+1];
			for (l = 0; l < lpm_pipeline; l = l +1)
				tmp_aeb2[l] = tmp_aeb2[l+1];
			for (m = 0; m < lpm_pipeline; m = m +1)
				tmp_agb2[m] = tmp_agb2[m+1];
			for (n = 0; n < lpm_pipeline; n = n +1)
				tmp_aleb2[n] = tmp_aleb2[n+1];
			for (o = 0; o < lpm_pipeline; o = o +1)
				tmp_aneb2[o] = tmp_aneb2[o+1];
			for (p = 0; p < lpm_pipeline; p = p +1)
				tmp_ageb2[p] = tmp_ageb2[p+1];
		end
	end
 
	assign alb = (lpm_pipeline > 0) ? tmp_alb2[0] : tmp_alb;
	assign aeb = (lpm_pipeline > 0) ? tmp_aeb2[0] : tmp_aeb;
	assign agb = (lpm_pipeline > 0) ? tmp_agb2[0] : tmp_agb;
	assign aleb = (lpm_pipeline > 0) ? tmp_aleb2[0] : tmp_aleb;
	assign aneb = (lpm_pipeline > 0) ? tmp_aneb2[0] : tmp_aneb;
	assign ageb = (lpm_pipeline > 0) ? tmp_ageb2[0] : tmp_ageb;
 
// Check for previous Parameter declaration order
initial if ((lpm_width === "lpm_compare") || (lpm_type !== "lpm_compare"))
  begin
    $display ("LPM 220 Version 1.6 Parameter Order changed; update instantiation");
    $finish;
  end
endmodule // lpm_compare
 
//------------------------------------------------------------------------
 
module lpm_mult ( result, dataa, datab, sum, clock, clken, aclr );
 
// NOTE: Parameters must be declared in the same order as the Properties
//       are specified in the Cell Specification document.
	parameter lpm_widtha = 1;
	parameter lpm_widthb = 1;
	parameter lpm_widths = 1;
	parameter lpm_widthp = 1;
	parameter lpm_representation  = "UNSIGNED";
	parameter lpm_pipeline  = 0;
	parameter lpm_type = "lpm_mult";
	parameter lpm_hint = "UNUSED";
	parameter lpm_source_version = "lpm 220 version 1.6";
 
	input  clock;
	input  clken;
	input  aclr;
	input  [lpm_widtha-1:0] dataa;
	input  [lpm_widthb-1:0] datab;
	input  [lpm_widths-1:0] sum;
	output [lpm_widthp-1:0] result;
 
	// inernal reg
	reg   [lpm_widthp-1:0] tmp_result;
	reg   [lpm_widthp-1:0] tmp_result2 [lpm_pipeline:0];
	reg   [lpm_widtha-1:0] a_int;
	reg   [lpm_widthb-1:0] b_int;
	reg   [lpm_widths-1:0] s_int;
	reg   [lpm_widthp-1:0] p_reg;
	integer p_int;
	integer i, j, k, m, n, p, maxs_mn;
	integer int_dataa, int_datab, int_sum, int_result;
 
	tri0 aclr;
	tri0 clock;
	tri1 clken;
 
	buf (i_aclr, aclr);
	buf (i_clock, clock);
	buf (i_clken, clken);
 
 
	always @(dataa or datab or sum)
	begin
		if (lpm_representation == "UNSIGNED")
		begin
			int_dataa = dataa;
			int_datab = datab;
			int_sum = sum;
		end
		else if (lpm_representation == "SIGNED")
		begin
			// convert signed dataa
			if (dataa[lpm_widtha-1] == 1)
			begin
				for (i = 0; i < lpm_widtha; i = i + 1)
					a_int[i] = dataa[i] ^ 1;
				int_dataa = (a_int) * (-1) - 1;
			end
			else
				int_dataa = dataa;
 
			// convert signed datab
			if (datab[lpm_widthb-1] == 1)
			begin
				for (j = 0; j < lpm_widthb; j = j + 1)
					b_int[j] = datab[j] ^ 1;
				int_datab = (b_int) * (-1) - 1;
			end
			else
				int_datab = datab;
 
			// convert signed sum
			if (sum[lpm_widths-1] == 1)
			begin
				for (k = 0; k < lpm_widths; k = k + 1)
					s_int[k] = sum[k] ^ 1;
				int_sum = (s_int) * (-1) - 1;
			end
			else
				int_sum = sum;
		end
		else 
		begin
			int_dataa = {lpm_widtha{1'bx}};
			int_datab = {lpm_widthb{1'bx}};
			int_sum   = {lpm_widths{1'bx}};
		end
 
		p_int = int_dataa * int_datab + int_sum;
		maxs_mn = ((lpm_widtha+lpm_widthb)>lpm_widths)?lpm_widtha+lpm_widthb:lpm_widths;
		if (lpm_widthp >= maxs_mn)
			tmp_result = p_int;
		else
		begin
			p_reg = p_int;
			for (m = 0; m < lpm_widthp; m = m + 1)
				tmp_result[lpm_widthp-1-m] = p_reg[maxs_mn-1-m];
		end 
	end
 
	always @(posedge i_clock or posedge i_aclr)
	begin
	  if (i_aclr)
		begin
			for (p = 0; p <= lpm_pipeline; p = p + 1)
				tmp_result2[p] = 'b0;
		end
	  else if (i_clken == 1)
	  begin :syn_block
		tmp_result2[lpm_pipeline] = tmp_result;
		for (n = 0; n < lpm_pipeline; n = n +1)
			tmp_result2[n] = tmp_result2[n+1];
	  end
	end
 
  assign result = (lpm_pipeline > 0) ? tmp_result2[0] : tmp_result;
 
// Check for previous Parameter declaration order
initial if ((lpm_widtha === "lpm_mult") || (lpm_type !== "lpm_mult"))
  begin
    $display ("LPM 220 Version 1.6 Parameter Order changed; update instantiation");
    $finish;
  end
endmodule // lpm_mult
 
//------------------------------------------------------------------------
 
module lpm_divide ( quotient,remain, numer, denom, clock, clken, aclr );
 
// NOTE: Parameters must be declared in the same order as the Properties
//       are specified in the Cell Specification document.
	parameter lpm_widthn = 1;
	parameter lpm_widthd = 1;
	//parameter lpm_widthq = 1;
	//parameter lpm_widthr = 1;
	parameter lpm_nrepresentation = "UNSIGNED";
	parameter lpm_drepresentation = "UNSIGNED";
	parameter lpm_pipeline = 0;
	parameter lpm_type = "lpm_divide";
	parameter lpm_hint = "UNUSED";
	parameter lpm_source_version = "lpm 220 version 1.6";
 
	input  clock;
	input  clken;
	input  aclr;
	input  [lpm_widthn-1:0] numer;
	input  [lpm_widthd-1:0] denom;
	output [lpm_widthn-1:0] quotient;
	output [lpm_widthd-1:0] remain;
 
	// inernal reg
	reg   [lpm_widthn-1:0] tmp_quotient [lpm_pipeline:0];
	reg   [lpm_widthd-1:0] tmp_remain [lpm_pipeline:0];
	reg   [lpm_widthn-1:0] ONES, ZEROS, UNKNOWN, HiZ;
	reg   [lpm_widthd-1:0] DZEROS, DUNKNOWN;
	reg   [lpm_widthn-1:0] NUNKNOWN;
	reg   [lpm_widthd-1:0] RZEROS ;
	integer i;
	integer int_numer, int_denom, int_quotient, int_remain;
 
	tri0 aclr;
	tri0 clock;
	tri1 clken;
 
	buf (i_aclr, aclr);
	buf (i_clock, clock);
	buf (i_clken, clken);
 
 
	initial
	begin
 
	// check if lpm_widthn > 0
	if (lpm_widthn <= 0)
		$display("%t: Error! LPM_WIDTHN must be greater than 0.\n", $time);
	// check if lpm_widthd > 0
	if (lpm_widthd <= 0)
		$display("%t: Error! LPM_WIDTHD must be greater than 0.\n", $time);
	// check if lpm_widthn > 0
		//if (lpm_widthq <= 0)
		//    $display("%t: Error! LPM_WIDTHQ must be greater than 0.\n", $time);
	// check if lpm_widthR > 0
		//if (lpm_widthr <= 0)
		//    $display("%t: Error! LPM_WIDTHR must be greater than 0.\n", $time);
	// check for valid lpm_nrep value
	if ((lpm_nrepresentation !== "SIGNED") && (lpm_nrepresentation !== "UNSIGNED"))
		$display("%t: Error! LPM_NREPRESENTATION value must be \"SIGNED\" or \"UNSIGNED\".", $time);
 
	// check for valid lpm_drep value
	if ((lpm_drepresentation !== "SIGNED") && (lpm_drepresentation !== "UNSIGNED"))
		$display("%t: Error! LPM_DREPRESENTATION value must be \"SIGNED\" or \"UNSIGNED\".", $time);
 
	// check if lpm_pipeline is > 1 and clock is not used
	if ((lpm_pipeline >=1) && (clock === 1'bz))
		$display("%t: Error! The clock pin is requied if lpm_pipeline is used\n", $time);
	else if ((lpm_pipeline == 0) && (clock !== 1'bz))
		$display("%t: Error! If the clock pin is used, lpm_pipeline must be greater than 0.\n", $time);
 
	for (i=0; i < lpm_widthn; i=i+1)
	begin
		ONES[i] = 1'b1;
		ZEROS[i] = 1'b0;
		UNKNOWN[i] = 1'bx;
		HiZ[i] = 1'bz;
	end
 
	for (i=0; i < lpm_widthd; i=i+1)
		DUNKNOWN[i] = 1'bx;
 
	for (i=0; i < lpm_widthn; i=i+1)
		NUNKNOWN[i] = 1'bx;
 
	for (i=0; i < lpm_widthd; i=i+1)
		RZEROS[i] = 1'b0;
 
	end
 
	always @(numer or denom)
	begin
		if (lpm_nrepresentation == "UNSIGNED")
			int_numer = numer;
		else if (lpm_nrepresentation == "SIGNED")
		begin
			// convert signed numer
			if (numer[lpm_widthn-1] == 1)
			begin
				int_numer = 0;
				for (i = 0; i < lpm_widthn - 1; i = i + 1)
					int_numer[i] = numer[i] ^ 1;
				int_numer = -(int_numer + 1);
			end
			else
				int_numer = numer;
		end
		else 
			int_numer = NUNKNOWN;
 
		if (lpm_drepresentation == "UNSIGNED")
			int_denom = denom;
		else if (lpm_drepresentation == "SIGNED")
		begin
			// convert signed denom
			if (denom[lpm_widthd-1] == 1)
			begin
				int_denom = 0;
				for (i = 0; i < lpm_widthd - 1; i = i + 1)
					int_denom[i] = denom[i] ^ 1;
				int_denom = -(int_denom + 1);
			end
			else
				int_denom = denom;
		end
		else 
			int_denom = DUNKNOWN;
 
		int_quotient = int_numer / int_denom;
		int_remain = int_numer % int_denom;
 
		tmp_quotient[lpm_pipeline] = int_quotient;
		tmp_remain[lpm_pipeline] = int_remain;
	end
 
	always @(posedge i_clock or i_aclr)
	begin :syn_block
		if (i_aclr)
		begin
			disable syn_block;
			for (i = 0; i <= lpm_pipeline; i = i + 1)
				tmp_quotient[i] = ZEROS;
			tmp_remain[i] = RZEROS;
		end
		else if (i_clken)
			for (i = 0; i < lpm_pipeline; i = i +1)
			begin
				tmp_quotient[i] = tmp_quotient[i+1];
				tmp_remain[i] = tmp_remain[i+1];
			end
	end
 
	assign quotient = tmp_quotient[0];
	assign remain = tmp_remain[0];
 
// Check for previous Parameter declaration order
initial if ((lpm_widthn === "lpm_divide") || (lpm_type !== "lpm_divide"))
  begin
    $display ("LPM 220 Version 1.6 Parameter Order changed; update instantiation");
    $finish;
  end
endmodule // lpm_divide
 
//------------------------------------------------------------------------
 
module lpm_abs ( result, overflow, data );
 
// NOTE: Parameters must be declared in the same order as the Properties
//       are specified in the Cell Specification document.
	parameter lpm_width = 1;
	parameter lpm_type = "lpm_abs";
	parameter lpm_hint = "UNUSED";
	parameter lpm_source_version = "lpm 220 version 1.6";
 
	input  [lpm_width-1:0] data;
	output [lpm_width-1:0] result;
	output overflow;
 
	reg    [lpm_width-1:0] a_int;
	reg    [lpm_width-1:0] result;
	reg    overflow;
	integer i;
 
	always @(data)
	begin
		overflow = 0;
		if (data[lpm_width-1] == 1)
		begin
			for (i = 0; i < lpm_width; i = i + 1)
				a_int[i] = data[i] ^ 1;
			result = (a_int + 1);
			overflow = (result == ( 1<<(lpm_width -1)));
		end
		else
			result = data;
	end
 
// Check for previous Parameter declaration order
initial if ((lpm_width === "lpm_abs") || (lpm_type !== "lpm_abs"))
  begin
    $display ("LPM 220 Version 1.6 Parameter Order changed; update instantiation");
    $finish;
  end
endmodule // lpm_abs
 
//------------------------------------------------------------------------
 
module lpm_counter ( q, data, clock, cin, cout,clk_en, cnt_en, updown,
					 aset, aclr, aload, sset, sclr, sload );
 
// NOTE: Parameters must be declared in the same order as the Properties
//       are specified in the Cell Specification document.
	parameter lpm_width = 1;
	parameter lpm_modulus = 0;
	parameter lpm_direction = "UNUSED";
	parameter lpm_avalue = "UNUSED";
	parameter lpm_svalue = "UNUSED";
	parameter lpm_pvalue = "UNUSED";
	parameter lpm_type = "lpm_counter";
	parameter lpm_hint = "UNUSED";
	parameter lpm_source_version = "lpm 220 version 1.6";
 
	output [lpm_width-1:0] q;
	//output [lpm_modulus-1:0] eq;
	output cout;
	input  cin;
	input  [lpm_width-1:0] data;
	input  clock, clk_en, cnt_en, updown;
	input  aset, aclr, aload;
	input  sset, sclr, sload;
 
	reg  [lpm_width-1:0] tmp_count;
	reg  tmp_updown;
	integer tmp_modulus;
 
	tri1 clk_en;
	tri1 cnt_en;
	tri1 updown;
	tri0 sload;
	tri0 sset;
	tri0 sclr;
	tri0 aload;
	tri0 aset;
	tri0 aclr;
	tri0 cin;
 
	buf (i_clk_en, clk_en);
	buf (i_cnt_en, cnt_en);
	buf (i_updown, updown);
	buf (i_sload, sload);
	buf (i_sset, sset);
	buf (i_sclr, sclr);
	buf (i_aload, aload);
	buf (i_aset, aset);
	buf (i_aclr, aclr);
	buf (i_cin, cin);
 
 
//---------------------------------------------------------------//
	function [lpm_width-1:0] NextBin;
		input [lpm_width-1:0] count;
 
		//reg  [lpm_width-1:0] re_start;
		//reg  [lpm_width-1:0] tmp_nextbin;
		//integer up_limit;
 
		begin 
			if (tmp_updown == 1)
			begin
				if (i_cin == 1 && count == tmp_modulus-2)
					NextBin = 0;
				else
					NextBin = (count >= tmp_modulus-1) ? i_cin : count+1+i_cin;
			end
			else
			begin
				if (i_cin == 1 && count == 1)
					NextBin = tmp_modulus - 1;
				else
					NextBin = (count <= 0) ? tmp_modulus-1-i_cin : count-1-i_cin;
			end
		end 
	endfunction
 
//---------------------------------------------------------------//
//  function [(1<<lpm_width)-1:0] CountDecode;
//---------------------------------------------------------------//
//  function [lpm_modulus:0] CountDecode;
//      input [lpm_width-1:0] count;
//
//      integer eq_index;
//
//      begin
//          CountDecode = 0;
//          eq_index = 0;
//          if (count < lpm_modulus)
//          begin
//              eq_index = count;
//              CountDecode[eq_index] = 1'b1;
//          end
//      end
//  endfunction
 
//---------------------------------------------------------------//
//  function integer str_to_int;
//---------------------------------------------------------------//
	function integer str_to_int;
		input  [8*16:1] s; 
 
		reg [8*16:1] reg_s;
		reg [8:1] digit;
		reg [8:1] tmp;
		integer m, ivalue;
 
		begin
			ivalue = 0;
			reg_s = s;
			for (m=1; m<=16; m=m+1)
			begin 
				tmp = reg_s[128:121];
				digit = tmp & 8'b00001111;
				reg_s = reg_s << 8; 
				ivalue = ivalue * 10 + digit; 
			end
			str_to_int = ivalue;
		end
	endfunction
 
//---------------------------------------------------------------//
 
	initial
	begin
		// check if lpm_modulus < 0
		if (lpm_modulus < 0)
			$display("%t: Error! LPM_MODULUS must be greater than 0.\n", $time);
		// check if lpm_modulus > 1<<lpm_width
		if (lpm_modulus > 1<<lpm_width)
			$display("%t: Error! LPM_MODULUS must be less than or equal to 1<<LPM_WIDTH.\n", $time);
 
		if (lpm_direction == "UNUSED")
			tmp_updown = (i_updown == 0) ? 0 : 1;
		else
			tmp_updown = (lpm_direction == "DOWN") ? 0 : 1;
 
		tmp_modulus = (lpm_modulus == 0) ? (1 << lpm_width) : lpm_modulus;
		tmp_count = (lpm_pvalue == "UNUSED") ? 0 : str_to_int(lpm_pvalue);
	end
 
	always @(i_updown)
	begin
		if (lpm_direction == "UNUSED")
			tmp_updown = (i_updown == 0) ? 0 : 1;
		else
			$display("%t: Error! LPM_DIRECTION and UPDOWN cannot be used at the same time.\n", $time);
	end
 
	always @(posedge clock or posedge i_aclr or posedge i_aset or
			  posedge i_aload)
	begin :asyn_block
		if (i_aclr)
			tmp_count = 0;
		else if (i_aset)
			tmp_count = (lpm_avalue == "UNUSED") ? {lpm_width{1'b1}}
												 : str_to_int(lpm_avalue);
		else if (i_aload)
			tmp_count = data;
		else
		begin :syn_block
			if (i_clk_en)
			begin
				if (i_sclr)
					tmp_count = 0;
				else if (i_sset)
					tmp_count = (lpm_svalue == "UNUSED") ? {lpm_width{1'b1}}
														 : str_to_int(lpm_svalue);
				else if (i_sload)
					tmp_count = data;
				else if (i_cnt_en)
					tmp_count = NextBin(tmp_count);
			end
		end
	end 
 
	assign q =  tmp_count;
	//assign eq = CountDecode(tmp_count);
	assign cout = (((tmp_count >= tmp_modulus-1-i_cin) && tmp_updown)
				  || ((tmp_count <= i_cin) && !tmp_updown)) ? 1 : 0;
 
// Check for previous Parameter declaration order
initial if ((lpm_width === "lpm_counter") || (lpm_type !== "lpm_counter"))
  begin
    $display ("LPM 220 Version 1.6 Parameter Order changed; update instantiation");
    $finish;
  end
endmodule // lpm_counter
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.