#!/usr/bin/perl # Binary Logic? use strict; use warnings 'all'; ++$|; ################################ # Combinational Blocks sub inv($) { 0+(!$_[0]) } sub nand($$) { inv ($_[0] && $_[1]) } sub mux_2x1 { my $select = shift; ($select && $_[0]) || (inv $select && $_[1]) } ################################ # Counter Functions # BCD - 0-9 my $r_a = sub { ( $_[0] && inv $_[2] && inv $_[3] ) || ( $_[1] && $_[2] && $_[3] ) }; my $r_b = sub { ( $_[1] && inv $_[2] ) || ( $_[1] && $_[2] && inv $_[3] ) || ( inv $_[1] && $_[2] && $_[3] ) }; my $r_c = sub { ( $_[2] && inv $_[3] ) || ( inv $_[0] && inv $_[2] && $_[3] ) }; # 0-5 my $l_b = sub { ( inv $_[0] && $_[2] && $_[3] ) || ( $_[1] && inv $_[2] && inv $_[3] ) }; my $l_c = sub { ( $_[2] && inv $_[3] ) || ( inv $_[1] && inv $_[2] && $_[3] ) }; # 0-12 my $h_a = sub { ( $_[0] && inv $_[2] ) || ( $_[0] && inv $_[3] ) || ( $_[1] && $_[2] && $_[3] ) }; my $h_b = sub { ( $_[1] && inv $_[2] ) || ( $_[1] && $_[2] && inv $_[3] ) || ( inv $_[0] && inv $_[1] && $_[2] && $_[3] ) }; my $h_c = sub { $_[2] xor $_[3] }; # Flip my $d = sub { inv $_[3] }; ################################ # clock functions my $on_next = sub { inv $_[0] && $_[1] }; my $ground = sub { 0 }; my $voltage = sub { 1 }; ################################ # Sequential Blocks sub mk_sr_latch() { my $s = 0; return sub { my $clock_state = shift; $s = inv (nand nand($clock_state, $_[1]), nand(nand($clock_state, $_[0]), inv $s)); $s # We don't use R. } } sub mk_d_flipflop() { my $sr = mk_sr_latch; return sub { $sr->($voltage->(), $_[0], inv $_[0]); # We don't use Q' either. } } sub mk_counter(@) { my $clock = shift; my ($f1,$f2,$f3,$f4) = splice @_,0,4; my ($a,$b,$c,$d) = splice @_,0,4; my @dff = (mk_d_flipflop)x4; return sub { my $clock_state = $clock->(@_); my ($ta,$tb,$tc,$td) = ($a,$b,$c,$d); $a = mux_2x1($clock_state, $dff[0]->(0+$f1->($ta,$tb,$tc,$td)), $a); $b = mux_2x1($clock_state, $dff[1]->(0+$f2->($ta,$tb,$tc,$td)), $b); $c = mux_2x1($clock_state, $dff[2]->(0+$f3->($ta,$tb,$tc,$td)), $c); $d = mux_2x1($clock_state, $dff[3]->(0+$f4->($ta,$tb,$tc,$td)), $d); return ($a,$b,$c,$d); } } sub mk_output_reg() { my $space_count = mk_counter $voltage, $ground, $ground, $h_c, $d; my ($c1,$c2,$c3,$c4); my ($dff_3,$dff_4)=(mk_d_flipflop)x2; return sub { print chr mux_2x1($_[0],4,45); # If output is garbled, change to: # print chr mux_2x1($_[0],120,45); print mux_2x1($c3 && $c4," ",""); ($c1,$c2,$c3,$c4) = $space_count->(); $c3 = $dff_3->($c3); $c4 = $dff_4->($c4); } } ################################ # Use "pure perl" to intitialize # counters my (@i_sec1,@i_sec2,@i_min1,@i_min2,@i_hour,@i_ampm); my @sec = ((split//,sprintf("%04b",substr(sprintf("%02d",(localtime)[0]),0,1))), (split//,sprintf("%04b",substr(sprintf("%02d",(localtime)[0]),1,1)))); my @min = ((split//,sprintf("%04b",substr(sprintf("%02d",(localtime)[1]),0,1))), (split//,sprintf("%04b",substr(sprintf("%02d",(localtime)[1]),1,1)))); my @hr = split//,sprintf("%08b",(localtime)[2]-12) if (localtime)[2] > 11; @hr = split//,sprintf("%08b",(localtime)[2]) if (localtime)[2] < 12; @i_sec1 = @sec[4..7]; @i_sec2 = @sec[0..3]; @i_min1 = @min[4..7]; @i_min2 = @min[0..3]; @i_hour = @hr [4..7]; @i_ampm = (0,0,0,0+((localtime)[2]>11)); ################################ # Create our blocks my $sec1 = mk_counter $voltage, $r_a, $r_b, $r_c, $d, @i_sec1; my $sec2 = mk_counter $on_next, $ground, $l_b, $l_c, $d, @i_sec2; my $min1 = mk_counter $on_next, $r_a, $r_b, $r_c, $d, @i_min1; my $min2 = mk_counter $on_next, $ground, $l_b, $l_c, $d, @i_min2; my $hour = mk_counter $on_next, $h_a, $h_b, $h_c, $d, @i_hour; my $ampm = mk_counter $on_next, $ground, $ground, $ground, $d, @i_ampm; my ($ls1,$ls2,$lm1,$lm2,$lh1); my ($dff_s1,$dff_s2,$dff_m1,$dff_m2,$dff_h1) = (mk_d_flipflop)x5; my $output_reg = mk_output_reg; ################################ # Turn on while (1) { my ($s_b3,$s_b2,$s_b1,$s_b0) = $sec1->(); my ($s_b7,$s_b6,$s_b5,$s_b4) = $sec2->($s_b3,$ls1); my ($m_b3,$m_b2,$m_b1,$m_b0) = $min1->($s_b6,$ls2); my ($m_b7,$m_b6,$m_b5,$m_b4) = $min2->($m_b3,$lm1); my ($h_b3,$h_b2,$h_b1,$h_b0) = $hour->($m_b6,$lm2); my $am = $ampm->($h_b3,$lh1); print chr mux_2x1($am,17,16); # If output is garbled, change to: # print mux_2x1($am,'p','a'); print " "; # Cross wires and output # Abstracted with a loop to save 25 # lines of identical code foreach ($h_b3,$h_b2,$h_b1,$h_b0, $m_b7,$m_b6,$m_b5,$m_b4, $m_b3,$m_b2,$m_b1,$m_b0, $s_b7,$s_b6,$s_b5,$s_b4, $s_b3,$s_b2,$s_b1,$s_b0) { $output_reg->($_); } $ls1 = $dff_s1->($s_b3); $ls2 = $dff_s2->($s_b6); $lm1 = $dff_m1->($m_b3); $lm2 = $dff_m2->($m_b6); $lh1 = $dff_h1->($h_b3); sleep 1; # Separate output however you'd like. # print "\n"; # $^O !~ /win/i && system('clear'); $^O =~ /win/i && system('cls'); }