--- /dev/null
+#!/usr/bin/perl -w
+
+use strict qw(vars);
+use POSIX;
+
+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 p ($) { print $_[0] or die $!; }
+
+sub scaleable ($$$$$) {
+ my ($width, $foscscale, $scalebitnums, $scales, $deadcycles) = @_;
+ my ($maxcycles, $scalespec, $scalebits, $maxmsclock);
+ my ($lastmaxmsclock, $cycles_per_msclock, $cyclesexpr, @scalebits);
+ my ($prescale, $shift);
+ $maxcycles = (1 << $width) - $deadcycles;
+ foreach $scalespec (@$scales) {
+ $scalespec =~ m/^(\d+)\:([01]+)$/;
+ ($prescale,$scalebits) = ($1,$2);
+ length($scalebits) == @$scalebitnums
+ or die "$scalespec @$scalebitnums";
+ $maxmsclock= floor($maxcycles * $prescale / ($foscscale * $interval));
+ p(" if");
+ p(" $msclock > $lastmaxmsclock &&") if defined $lastmaxmsclock;
+ p(" $msclock <= $maxmsclock\n");
+ 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");
+ }
+ $cycles_per_msclock = $interval * $foscscale / $prescale;
+ $shift = 31 - ceil(log($maxmsclock * $cycles_per_msclock) / log(2.0));
+ p(sprintf "%scycles equ (%s * %d) >> %d\n",
+ $name, $msclock, $cycles_per_msclock * (1<<$shift), $shift);
+ $cyclesexpr= sprintf("(%d - %scycles)",
+ (1<<$width) - $deadcycles, $name);
+ if ($width == 16) {
+ p("${name}inith equ $cyclesexpr / 256\n");
+ p("${name}initl equ $cyclesexpr & 255\n");
+ } elsif ($width == 8) {
+ p("${name}init equ $cyclesexpr\n");
+ } else {
+ die "$width";
+ }
+ p(" endif\n");
+ $lastmaxmsclock= $maxmsclock;
+ }
+ p(" if $msclock > $lastmaxmsclock\n");
+ p(" error \"clock speed too high for $name\"\n");
+ p(" endif\n");
+}
+
+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);
+}
+
+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);
+}
+
+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 doline () {
+ my ($orgname,$mswant,$unit,$how);
+ chomp;
+ s/[;\#].*//;
+ return unless m/^\S/;
+ die "$_ ?" unless
+ m/^(\w+)\s+(M|S|MS)\s+(\w+)\s+([0-9.]+)(s|ms|us|ns|Hz|kHz|MHz)$/;
+ ($orgname,$mswant,$how,$interval,$unit) = ($1,$2,$3,$4,$5);
+ if ($unit =~ m/M/) { $interval *= 1.e6; }
+ if ($unit =~ m/k/) { $interval *= 1.e3; }
+ if ($unit =~ m/m/) { $interval *= 1.e-3; }
+ if ($unit =~ m/u/) { $interval *= 1.e-6; }
+ if ($unit =~ m/n/) { $interval *= 1.e-9; }
+ if ($unit =~ s/Hz//) { $interval = 1.0 / $interval; }
+ foreach $ms (qw(m s)) {
+ next unless $mswant =~ m/$ms/i;
+ $msclock= "${ms}clock";
+ $name = $orgname.'_'.($ms eq 'm' ? 'master' : 'slave');
+ p(";---------- $name ----------\n");
+ &{ "do_$how" };
+ }
+}
+
+while (<>) {
+ doline();
+}