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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [bench/] [formal/] [abs_div.v] - Rev 209

Compare with Previous | Blame | View Log

////////////////////////////////////////////////////////////////////////////////
//
// Filename:	abs_div.v
//
// Project:	Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose:	The original divide module provides an Integer divide
//		capability to the Zip CPU.  This module is an abstract
//	divide module.  It *might* produce a valid integer divide, either signed
//	or unsigned, result.  It might instead do somethin else.  It is designed
//	to be easier for the formal tools to work with.
//
// Steps:
//	i_reset	The DIVide unit starts in idle.  It can also be placed into an
//	idle by asserting the reset input.
//
//	i_wr	When i_reset is asserted, a divide begins.  On the next clock:
//
//	  o_busy is set high so everyone else knows we are at work and they can
//		wait for us to complete.
//
//	  pre_sign is set to true if we need to do a signed divide.  In this
//		case, we take a clock cycle to turn the divide into an unsigned
//		divide.
//
//	  o_quotient, a place to store our result, is initialized to all zeros.
//
//	  r_dividend is set to the numerator
//
//	  r_divisor is set to 2^31 * the denominator (shift left by 31, or add
//		31 zeros to the right of the number.
//
//	pre_sign When true (clock cycle after i_wr), a clock cycle is used
//		to take the absolute value of the various arguments (r_dividend
//		and r_divisor), and to calculate what sign the output result
//		should be.
//
//
//	At this point, the divide is has started.  The divide works by walking
//	through every shift of the
//
//		    DIVIDEND	over the
//		DIVISOR
//
//	If the DIVISOR is bigger than the dividend, the divisor is shifted
//	right, and nothing is done to the output quotient.
//
//		    DIVIDEND
//		 DIVISOR
//
//	This repeats, until DIVISOR is less than or equal to the divident, as in
//
//		DIVIDEND
//		DIVISOR
//
//	At this point, if the DIVISOR is less than the dividend, the
//	divisor is subtracted from the dividend, and the DIVISOR is again
//	shifted to the right.  Further, a '1' bit gets set in the output
//	quotient.
//
//	Once we've done this for 32 clocks, we've accumulated our answer into
//	the output quotient, and we can proceed to the next step.  If the
//	result will be signed, the next step negates the quotient, otherwise
//	it returns the result.
//
//	On the clock when we are done, o_busy is set to false, and o_valid set
//	to true.  (It is a violation of the ZipCPU internal protocol for both
//	busy and valid to ever be true on the same clock.  It is also a
//	violation for busy to be false with valid true thereafter.)
//
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2019, 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype	none
//
module	abs_div(i_clk, i_reset, i_wr, i_signed, i_numerator, i_denominator,
		o_busy, o_valid, o_err, o_quotient, o_flags);
	parameter		BW=32, LGBW = 5;
	parameter	[4:0]	MAXDELAY = 3;
	input	wire		i_clk, i_reset;
	// Input parameters
	input	wire		i_wr, i_signed;
	input	wire [(BW-1):0]	i_numerator, i_denominator;
	// Output parameters
	output	wire		o_busy;
	output	reg		o_valid, o_err;
	output	reg [(BW-1):0]	o_quotient;
	output	wire	[3:0]	o_flags;
 
	(* anyseq *)	reg			any_err;
	(* anyseq *)	reg	[(BW-1):0]	any_quotient;
	(* anyseq *)	reg	[5:0]		wait_time;
 
	always @(*)
		o_err      = any_err;
	always @(*)
		o_quotient = any_quotient;
 
	reg	[5:0]	r_busy_counter;
 
	always @(*)
		assume(wait_time > 5'h1);
 
	always @(*)
		assume((MAXDELAY == 0)||(wait_time < MAXDELAY));
 
	initial	r_busy_counter = 0;
	always @(posedge i_clk)
	if (i_reset)
		r_busy_counter <= 0;
	else if ((i_wr)&&(!o_busy))
		r_busy_counter <= wait_time;
	else if (r_busy_counter > 0)
		r_busy_counter <= r_busy_counter - 1'b1;
 
	always @(*)
	assert((MAXDELAY == 0)||(r_busy_counter < MAXDELAY));
 
	assign	o_busy = (r_busy_counter != 0);
 
	initial	o_valid = 1'b0;
	always @(posedge i_clk)
	if (i_reset)
		o_valid <= 1'b0;
	else
		o_valid <= (r_busy_counter == 1);
 
	(* anyseq *)	reg	[3:0]	any_flags;
 
	assign o_flags    = (o_valid) ? 
			{ 1'b0, o_quotient[31], any_flags[1],
					(o_quotient == 0) } : any_flags;
 
`ifdef	FORMAL
	reg	f_past_valid;
	initial	f_past_valid = 0;
	always @(posedge i_clk)
		f_past_valid <= 1'b1;
	always @(posedge i_clk)
	if (!f_past_valid)
		assert((!o_busy)&&(!o_valid));
 
`define	ASSUME	assert
 
	initial	`ASSUME(i_reset);
	always @(*)
	if (!f_past_valid)
		`ASSUME(i_reset);
 
	always @(posedge i_clk)
	if ((!f_past_valid)||($past(i_reset)))
		`ASSUME(!i_wr);
 
	always @(*)
	if (o_busy)
		`ASSUME(!i_wr);
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(i_reset))&&($past(o_busy))&&(!o_busy))
		assume(o_valid);
 
	always @(*)
	if (o_err)
		assume(o_valid);
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wr)))
		assert(o_busy);
 
	always @(posedge i_clk)
	if ((f_past_valid)&&($past(o_valid)))
		assume(!o_valid);
 
	always @(*)
	if ((o_valid)&&(!o_err))
		assume(o_flags[3] == ((o_quotient == 0)? 1'b1:1'b0));
 
	always @(*)
	if ((o_valid)&&(!o_err))
		assume(o_flags[1] == o_quotient[BW-1]);
 
	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(o_busy))&&(!$past(i_wr)))
		assume(!o_busy);
 
	always @(posedge i_clk)
		assume((!o_busy)||(!o_valid));
 
`endif
endmodule
 

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.