chiark / gitweb /
put tick marks in the right places
[trains.git] / detpic / make-clocks
1 #!/usr/bin/perl -w
2 # usage   ../make-clocks [<input-file> ...] -Dmclock=khz -Dsclock=khz
3
4 use strict qw(vars);
5 use POSIX;
6
7 sub p ($) { print $_[0] or die $!; }
8
9 our (%defs);
10
11 p("; autogenerated - do not edit\n");
12 p("; $0 @ARGV\n");
13 while ($ARGV[$#ARGV] =~ m/^\-/) {
14     $_ = pop @ARGV;
15     last if m/^\-\-$/;
16     die unless m/^\-D(\w+)\=(\w+)$/;
17     $defs{$1}= $2;
18 }
19
20 our ($name,$ms,$interval,$msclock);
21 # $interval is in seconds
22 # mclock or sclock is in kHz
23 # ourtimerclock is mclock or sclock * 250 (for Fosc/4)
24 # call 250 foscscale
25 # basically interval = cycles / clock
26 # adjusted for units  interval = cycles * prescale / (foscscale * msclock)
27 #                 ie  cycles = interval * foscscale * msclock / prescale
28 #                 or  msclock = cycles * prescale / (foscscale * interval)
29
30 sub scaleable ($$$$$$) {
31     my ($width, $foscscale, $scalebitnums, $scales,
32         $deadcycles, $overflowp) = @_;
33     my ($maxcycles, $scalespec, $scalebits);
34     my ($cycles, $cyequ, @scalebits);
35     my ($prescale);
36     $maxcycles = (1 << $width) - $deadcycles;
37     foreach $scalespec (@$scales) {
38         $scalespec =~ m/^0*(\d+)\-([01]+)$/;
39         ($prescale,$scalebits) = ($1,$2);
40         length($scalebits) == @$scalebitnums
41             or die "$scalespec @$scalebitnums";
42
43         $cycles= $interval * $foscscale * $msclock / $prescale;
44         next if $cycles > $maxcycles;
45
46         if (length($scalebits)) {
47             p("${name}scale equ ");
48             @scalebits = (map { "(1<<$_)" }
49                           grep { $scalebits =~ s/^.// or die; $&; }
50                           @$scalebitnums);
51             push @scalebits, '0' unless @scalebits;
52             p(join '|', @scalebits);
53             p("; $prescale:1\n");
54         }
55
56         $cyequ= "${name}cycles";
57         p(sprintf "%s equ %d\n", $cyequ, $cycles);
58         if ($overflowp) {
59             p("${name}init equ ".(1<<$width)." - $cyequ\n");
60             if ($width == 16) {
61                 p("${name}inith equ ${name}init / 256\n");
62                 p("${name}initl equ ${name}init & 255\n");
63             }
64         }
65         return;
66     }
67     warn "clock speed too high for $name\n";
68 }
69
70 sub do_T2period {
71     my (@scales, $pre, $prex, $prebits, $posti, $this);
72     for $pre (qw(1-00 4-01 16-10)) {
73         $pre =~ m/^(\d+)\-([01]+)$/;
74         ($prex,$prebits) = ($1,$2);
75         for ($posti=0; $posti<15; $posti++) {
76             $this= sprintf "%03d-%s%04b", $prex * ($posti+1), $prebits, $posti;
77             push @scales, $this;
78         }
79     }
80     local ($name) = "${name}_t2";
81     scaleable(8, 250.0, [qw(T2CKPS1 T2CKPS0 TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0)],
82               [ sort @scales ], 0, 0);
83 }
84
85 sub do_T13ov ($) {
86     my ($n) = @_;
87     local ($name) = "${name}_t${n}";
88     scaleable(16, 250.0, ["T${n}CKPS1","T${n}CKPS0"],
89               [qw(1-00 2-01 4-10 8-11)], 1, 1);
90 }
91
92 sub do_T0ov ($) {
93     my ($w) = @_;
94     local ($name) = "${name}_t0";
95     scaleable($w, 250.0, ["PSA","T0PS2","T0PS1","T0PS0"],
96               [qw(1-1000 2-0000 4-0001 8-0010 16-0011
97                 32-0100 64-0101 128-0110 256-0111)], 1, 1);
98 }
99
100 sub do_T0ov8  { do_T0ov(8);  }
101 sub do_T0ov16 { do_T0ov(16); }
102 sub do_T1ov { do_T13ov(1); }
103 sub do_T3ov { do_T13ov(3); }
104
105 sub provide_interval ($$$$) {
106     my ($iname, $thisval, $unitname, $unitval) = @_;
107     my ($inthisunit, $inthisunitint);
108     $inthisunit= $thisval / $unitval;
109     return if $inthisunit > 256000000.0;
110     $inthisunitint= sprintf "%d", $inthisunit;
111     return if abs(($inthisunitint - $inthisunit) / $inthisunit) > 0.001;
112     p("${iname}_${unitname} equ $inthisunitint\n");
113 }
114
115 sub doline () {
116     my ($orgname,$mswant,$specd,$unit,$cy,$how,$baseinterval);
117     chomp;
118     s/\s*[;\#].*//;
119     return unless m/^\S/;
120     die "$_ ?" unless
121         m/^(\w+)\s+([MST]+)\s+(\w+)\s+([0-9.]+)(s|ms|us|ns|Hz|kHz|MHz)((?:[-+][0-9.]+cy)?)$/;
122     ($orgname,$mswant,$how,$baseinterval,$unit,$cy) = ($1,$2,$3,$4,$5,$6,$7);
123     $specd= $baseinterval.$unit.$cy;
124     if ($unit =~ m/M/) { $baseinterval *= 1.e6; }
125     if ($unit =~ m/k/) { $baseinterval *= 1.e3; }
126     if ($unit =~ m/m/) { $baseinterval *= 1.e-3; }
127     if ($unit =~ m/u/) { $baseinterval *= 1.e-6; }
128     if ($unit =~ m/n/) { $baseinterval *= 1.e-9; }
129     if ($unit =~ s/Hz//) { $baseinterval = 1.0 / $baseinterval; }
130     if ($cy =~ s/cy$//) { $cy *= 4.0; }
131     elsif ($cy = m//) { $cy = 0.0; }
132     else { die "$cy ?"; }
133     p("\n");
134     p(";========== $orgname ($specd: ${baseinterval}s, ${cy}cy) ==========\n");
135     if ($mswant =~ m/T/) {
136         provide_interval($orgname, $baseinterval, 'us', 1.e-6);
137         provide_interval($orgname, $baseinterval, 'ms', 1.e-3);
138         provide_interval($orgname, $baseinterval, 's', 1.0);
139     }
140     foreach $ms (qw(m s)) {
141         next unless $mswant =~ m/$ms/i;
142         $msclock= "${ms}clock";
143         die $msclock unless exists $defs{$msclock};
144         $msclock= $defs{$msclock};
145         $interval= $baseinterval + $cy / ($msclock * 1000.0);
146         p(";---------- $orgname, ${interval}s, ${msclock}kHz ----------\n");
147         $name = $orgname.'_'.($ms eq 'm' ? 'master' : 'slave');
148         &{ "do_$how" };
149     }
150 }
151
152 while (<>) {
153     doline();
154 }