The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# vim: ts=2 sw=2 noexpandtab

# D flip-flop.
#
# Six tri-input NAND gates don't translate to ASCII art very well.
# The working version comes from Don Lancaster's _TTL Cookbook_.

package Ttl::FlipFlop::D;
use Moose;
extends 'Reflex::Base';
use Ttl::TriNand;

use Reflex::Trait::EmitsOnChange qw(emits);
use Reflex::Trait::Watched qw(watches);

emits clear  => ( isa => 'Bool' );
emits clock  => ( isa => 'Bool' );
emits d      => ( isa => 'Bool' );
emits preset => ( isa => 'Bool' );
emits q      => ( isa => 'Bool' );
emits not_q  => ( isa => 'Bool' );

sub BUILD {
	my $self = shift;

	$self->tri1( Ttl::TriNand->new() );
	$self->tri2( Ttl::TriNand->new() );
	$self->tri3( Ttl::TriNand->new() );
	$self->tri4( Ttl::TriNand->new() );
	$self->tri5( Ttl::TriNand->new() );
	$self->tri6( Ttl::TriNand->new() );

	# Toggle clear low/high to clear output.
	$self->preset(1);
	$self->clear(1);
	$self->clock(1);
	$self->d(0);
}

sub on_my_clear {
	my ($self, $args) = @_;
	my $value = $args->{value};
	$self->tri2->b($value);
	$self->tri4->b($value);
	$self->tri6->b($value);
}

sub on_my_clock {
	my ($self, $args) = @_;
	my $value = $args->{value};
	$self->tri2->c($value);
	$self->tri3->b($value);
}

sub on_my_d {
	my ($self, $args) = @_;
	$self->tri4->c($args->{value});
}

sub on_my_preset {
	my ($self, $args) = @_;
	my $value = $args->{value};
	$self->tri1->a($value);
	$self->tri5->a($value);
}

sub on_tri1_out {
	my ($self, $args) = @_;
	$self->tri2->a($args->{value});
}

sub on_tri2_out {
	my ($self, $args) = @_;
	$self->tri1->c($args->{value});
	$self->tri3->a($args->{value});
	$self->tri5->b($args->{value});
}

sub on_tri3_out {
	my ($self, $args) = @_;
	$self->tri4->a($args->{value});
	$self->tri6->c($args->{value});
}

sub on_tri4_out {
	my ($self, $args) = @_;
	$self->tri1->b($args->{value});
	$self->tri3->c($args->{value});
}

sub on_tri5_out {
	my ($self, $args) = @_;
	$self->q($args->{value});
	$self->tri6->a($args->{value});
}

sub on_tri6_out {
	my ($self, $args) = @_;
	$self->not_q($args->{value});
	$self->tri5->c($args->{value});
}

watches tri1 => ( isa => 'Ttl::TriNand' );
watches tri2 => ( isa => 'Ttl::TriNand' );
watches tri3 => ( isa => 'Ttl::TriNand' );
watches tri4 => ( isa => 'Ttl::TriNand' );
watches tri5 => ( isa => 'Ttl::TriNand' );
watches tri6 => ( isa => 'Ttl::TriNand' );

1;