#!/usr/bin/perl -w # usage ../make-clocks [ ...] -Dmclock=khz -Dsclock=khz use strict qw(vars); use POSIX; sub p ($) { print $_[0] or die $!; } our (%defs); p("; autogenerated - do not edit\n"); p("; $0 @ARGV\n"); while ($ARGV[$#ARGV] =~ m/^\-/) { $_ = pop @ARGV; last if m/^\-\-$/; die unless m/^\-D(\w+)\=(\w+)$/; $defs{$1}= $2; } our ($name,$ms,$interval,$msclock); # $interval is in seconds # mclock or sclock is in kHz # ourtimerclock is mclock or sclock * 250 (for Fosc/4) # call 250 foscscale # basically interval = cycles / clock # adjusted for units interval = cycles * prescale / (foscscale * msclock) # ie cycles = interval * foscscale * msclock / prescale # or msclock = cycles * prescale / (foscscale * interval) sub scaleable ($$$$$$) { my ($width, $foscscale, $scalebitnums, $scales, $deadcycles, $overflowp) = @_; my ($maxcycles, $scalespec, $scalebits); my ($cycles, $cyequ, @scalebits); my ($prescale); $maxcycles = (1 << $width) - $deadcycles; foreach $scalespec (@$scales) { $scalespec =~ m/^0*(\d+)\-([01]+)$/; ($prescale,$scalebits) = ($1,$2); length($scalebits) == @$scalebitnums or die "$scalespec @$scalebitnums"; $cycles= $interval * $foscscale * $msclock / $prescale; next if $cycles > $maxcycles; if (length($scalebits)) { p("${name}scale equ "); @scalebits = (map { "(1<<$_)" } grep { $scalebits =~ s/^.// or die; $&; } @$scalebitnums); push @scalebits, '0' unless @scalebits; p(join '|', @scalebits); p("; $prescale:1\n"); } $cyequ= "${name}cycles"; p(sprintf "%s equ %d\n", $cyequ, $cycles); if ($overflowp) { p("${name}init equ ".(1<<$width)." - $cyequ\n"); if ($width == 16) { p("${name}inith equ ${name}init / 256\n"); p("${name}initl equ ${name}init & 255\n"); } } return; } warn "clock speed too high for $name\n"; } sub do_T2period { my (@scales, $pre, $prex, $prebits, $posti, $this); for $pre (qw(1-00 4-01 16-10)) { $pre =~ m/^(\d+)\-([01]+)$/; ($prex,$prebits) = ($1,$2); for ($posti=0; $posti<15; $posti++) { $this= sprintf "%03d-%s%04b", $prex * ($posti+1), $prebits, $posti; push @scales, $this; } } local ($name) = "${name}_t2"; scaleable(8, 250.0, [qw(T2CKPS1 T2CKPS0 TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0)], [ sort @scales ], 0, 0); } sub do_T13ov ($) { my ($n) = @_; local ($name) = "${name}_t${n}"; scaleable(16, 250.0, ["T${n}CKPS1","T${n}CKPS0"], [qw(1-00 2-01 4-10 8-11)], 1, 1); } sub do_T0ov ($) { my ($w) = @_; local ($name) = "${name}_t0"; scaleable($w, 250.0, ["PSA","T0PS2","T0PS1","T0PS0"], [qw(1-1000 2-0000 4-0001 8-0010 16-0011 32-0100 64-0101 128-0110 256-0111)], 1, 1); } sub do_T0ov8 { do_T0ov(8); } sub do_T0ov16 { do_T0ov(16); } sub do_T1ov { do_T13ov(1); } sub do_T3ov { do_T13ov(3); } sub provide_interval ($$$$) { my ($iname, $thisval, $unitname, $unitval) = @_; my ($inthisunit, $inthisunitint); $inthisunit= $thisval / $unitval; return if $inthisunit > 256000000.0; $inthisunitint= sprintf "%d", $inthisunit; return if abs(($inthisunitint - $inthisunit) / $inthisunit) > 0.001; p("${iname}_${unitname} equ $inthisunitint\n"); } sub doline () { my ($orgname,$mswant,$specd,$unit,$cy,$how,$baseinterval); chomp; s/\s*[;\#].*//; return unless m/^\S/; die "$_ ?" unless m/^(\w+)\s+([MST]+)\s+(\w+)\s+([0-9.]+)(s|ms|us|ns|Hz|kHz|MHz)((?:[-+][0-9.]+cy)?)$/; ($orgname,$mswant,$how,$baseinterval,$unit,$cy) = ($1,$2,$3,$4,$5,$6,$7); $specd= $baseinterval.$unit.$cy; if ($unit =~ m/M/) { $baseinterval *= 1.e6; } if ($unit =~ m/k/) { $baseinterval *= 1.e3; } if ($unit =~ m/m/) { $baseinterval *= 1.e-3; } if ($unit =~ m/u/) { $baseinterval *= 1.e-6; } if ($unit =~ m/n/) { $baseinterval *= 1.e-9; } if ($unit =~ s/Hz//) { $baseinterval = 1.0 / $baseinterval; } if ($cy =~ s/cy$//) { $cy *= 4.0; } elsif ($cy = m//) { $cy = 0.0; } else { die "$cy ?"; } p("\n"); p(";========== $orgname ($specd: ${baseinterval}s, ${cy}cy) ==========\n"); if ($mswant =~ m/T/) { provide_interval($orgname, $baseinterval, 'us', 1.e-6); provide_interval($orgname, $baseinterval, 'ms', 1.e-3); provide_interval($orgname, $baseinterval, 's', 1.0); } foreach $ms (qw(m s)) { next unless $mswant =~ m/$ms/i; $msclock= "${ms}clock"; die $msclock unless exists $defs{$msclock}; $msclock= $defs{$msclock}; $interval= $baseinterval + $cy / ($msclock * 1000.0); p(";---------- $orgname, ${interval}s, ${msclock}kHz ----------\n"); $name = $orgname.'_'.($ms eq 'm' ? 'master' : 'slave'); &{ "do_$how" }; } } while (<>) { doline(); }