/*****************************************************************************

    74123 monoflop emulator - see 74123.h for pin out and truth table

    Formulas came from the TI datasheet revised on March 1998

 *****************************************************************************/

#include "driver.h"
#include "machine/74123.h"
#include "rescap.h"


#define	LOG		(0)


typedef struct _TTL74123_state TTL74123_state;

struct _TTL74123_state
{
	const TTL74123_interface *intf;
	int which;

	UINT8 A;			/* pin 1/9 */
	UINT8 B;			/* pin 2/10 */
	UINT8 clear;		/* pin 3/11 */
	mame_timer *timer;
};

static TTL74123_state chips[MAX_TTL74123];


static mame_time compute_duration(TTL74123_state *chip)
{
	double duration;

	switch (chip->intf->connection_type)
	{
	case TTL74123_NOT_GROUNDED_NO_DIODE:
		duration = 0.28 * chip->intf->res * chip->intf->cap * (1.0 + (0.7 / chip->intf->res));
		break;

	case TTL74123_NOT_GROUNDED_DIODE:
		duration = 0.25 * chip->intf->res * chip->intf->cap * (1.0 + (0.7 / chip->intf->res));
		break;

	case TTL74123_GROUNDED:
	default:
		if (chip->intf->cap < CAP_U(0.1))
			/* this is really a curve - a very flat one in the 0.1uF-.01uF range */
			duration = 0.32 * chip->intf->res * chip->intf->cap;
		else
			duration = 0.33 * chip->intf->res * chip->intf->cap;
		break;
	}

	return double_to_mame_time(TIME_IN_SEC(duration));
}


static int timer_running(TTL74123_state *chip)
{
	return (compare_mame_times(mame_timer_timeleft(chip->timer), time_zero) > 0) &&
		   (compare_mame_times(mame_timer_timeleft(chip->timer), time_never) != 0);
}


static void set_output(TTL74123_state *chip)
{
	int output = timer_running(chip);

	chip->intf->output_changed_cb(output);

	if (LOG) logerror("74123 #%d:  Output: %d\n", chip->which, output);
}


static void clear_callback(void *param)
{
	TTL74123_state *chip = (TTL74123_state *)param;

	set_output(chip);
}


void TTL74123_config(int which, const TTL74123_interface *intf)
{
	TTL74123_state *chip;

	assert_always(which < MAX_TTL74123, "Exceeded maximum number of 74123 chips");
	assert_always(intf, "No interface specified");
	assert_always((intf->connection_type == TTL74123_GROUNDED) && (intf->cap >= CAP_U(0.01)), "Only capacitors >= 0.01uF supported for GROUNDED type");
	assert_always(intf->cap >= CAP_P(1000), "Only capacitors >= 1000pF supported ");

	chip = &chips[which];

	chip->intf = intf;
	chip->which = which;
	chip->timer = mame_timer_alloc_ptr(clear_callback, chip);

	/* start with the defaults */
	chip->A = intf->A;
    chip->B = intf->B;
	chip->clear = intf->clear;

	/* register for state saving */
	state_save_register_item("TTL74123", which, chip->A);
	state_save_register_item("TTL74123", which, chip->B);
	state_save_register_item("TTL74123", which, chip->clear);
}


void TTL74123_reset(int which)
{
	TTL74123_state *chip = &chips[which];

	set_output(chip);
}


static void start_pulse(TTL74123_state *chip)
{
	mame_time duration = compute_duration(chip);

	if (timer_running(chip))
	{
		/* retriggering, but not if we are called to quickly */
		mame_time delay_time = double_to_mame_time(TIME_IN_NSEC(0.22 * (chip->intf->cap / 1e-12)));

		if (compare_mame_times(mame_timer_timeelapsed(chip->timer), delay_time) >= 0)
		{
			mame_timer_adjust_ptr(chip->timer, duration, time_never);

			if (LOG) logerror("74123 #%d:  Retriggering pulse.  Duration: %f\n", chip->which, mame_time_to_double(duration));
		}
		else
		{
			if (LOG) logerror("74123 #%d:  Retriggering failed.\n", chip->which);
		}
	}
	else
	{
		/* starting */
		mame_timer_adjust_ptr(chip->timer, duration, time_never);

		set_output(chip);

		if (LOG) logerror("74123 #%d:  Starting pulse.  Duration: %f\n", chip->which, mame_time_to_double(duration));
	}
}


void TTL74123_A_w(int which, int data)
{
	TTL74123_state *chip = &chips[which];

	/* start/regtrigger pulse if B=HI and falling edge on A (while clear is HI) */
	if (!data && chip->A && chip->B && chip->clear)
		start_pulse(chip);

	chip->A = data;
}


void TTL74123_B_w(int which, int data)
{
	TTL74123_state *chip = &chips[which];

	/* start/regtrigger pulse if A=LO and rising edge on B (while clear is HI) */
	if (data && !chip->B && !chip->A && chip->clear)
		start_pulse(chip);

	chip->B = data;
}


void TTL74123_clear_w(int which, int data)
{
	TTL74123_state *chip = &chips[which];

	/* clear the output if A=LO, B=HI and falling edge on clear */
	if (!data && chip->clear && chip->B && !chip->A && !chip->clear)
	{
		mame_timer_adjust_ptr(chip->timer, time_zero, time_never);

		if (LOG) logerror("74123 #%d:  Cleared\n", which);
	}

	chip->clear = data;
}
