chiark / gitweb /
622ba7a82dfbe3cb8e8804710464c4d2f97a2171
[trains.git] / cebpic / morse-generator
1 #!/usr/bin/perl
2 # Converts morse.messages to *+morse.asm or morse+auto.inc.
3 # morse-auto.asm specifies some flash contents, as follows:
4 #
5 # Each message XY produces a symbol
6 #   morse_XY
7 # which is in the flash between morse_messages_start and
8 # morse_messages_end, and which is guaranteed to be aligned to a
9 # multiple of 4 bytes.
10 #
11 # At that symbol will be a message in the following format:
12 #       RAAAMMMM        header byte, contents as follows:
13 #                        M (4 bits) number of bytes of morse pattern
14 #                        R reserved bit, always zero
15 #                        A (3 bits) number of bytes of addresses
16 #       M bytes         morse pattern, as bit string of LED on/off
17 #                        values (1=on) for equal-length periods
18 #                        (1 period = 1 morse dot), MS bit first
19 #                        trailing zeroes in last byte are probably
20 #                        best elided
21 #       A bytes         zero or more addresses which should be read
22 #                        and the corresponding value shown in binary.
23 #                        Addresses are only one byte each, interpreted
24 #                        like an access bank reference.
25 #
26 # morse_messages_start and morse_messages_end should be defined in
27 # morse-defs.inc, and should also be 4-byte aligned.  morse-defs.inc
28 # should also arrange to define any symbolic addresse referred to
29 # in morse-auto.messages, eg by including the pXXXX.inc.
30 #
31 # *+morse.asm contains the actual source and morse+auto.inc
32 # contains `equ' definitions for the addresses morse_XY.
33
34 use IO::File;
35 use IO::Handle;
36
37 sub badusage () {
38     die ("usages:\n".
39          " morse-generator <input>... asm\n".
40          " morse-generator <input>... [<file>.map] inc\n");
41 }
42
43 @ARGV or badusage();
44
45 $includefile= 'morse-defs.inc';
46 if ($ARGV[$#ARGV] =~ s/^\-I//) {
47     $includefile= pop @ARGV;
48 }
49
50 $which= pop @ARGV;
51 $which eq 'asm' or $which eq 'inc' or badusage();
52
53 while (<DATA>) {
54     ($let,$morse) = (m/^([0-9A-Z])\s+([-.]+)$/) or die;
55     $morse =~ s/\./10/g;
56     $morse =~ s/\-/1110/g;
57     $morse =~ s/0$//;
58     $morse{$let}= $morse;
59 }
60
61 sub oops ($) { die "morse-generator: $ARGV:$.: $_[0]\n"; }
62
63 $mapfile= $ARGV[$#ARGV];
64
65 if ($mapfile =~ m/\.map$/) {
66     pop @ARGV;
67     $maph= new IO::File "$mapfile", 'r' or die "$0: $mapfile: $!\n";
68     while (<$maph>) {
69         next unless m/^\s+Symbols\s+$/ .. !/\S/;
70         next unless m/\S/;
71         next if m/^\s+Symbols\s+$/;
72         next if m/^\s+Name\s+Address\s+Location\s+Storage\s+File\s*$/;
73         next if m/^(?:\s+\-\-+){5}\s*$/;
74         m/^\s*([0-9a-zA-Z_]+)\s+(0+|0x[0-9a-f]+)\s+(program|data)\s+(static|extern)\s+(\S+)\s*$/
75             or die "$0: $mapfile:$.: cannot parse ?!\n";
76         ($sym,$val,$progdata,$staticext,$filename) = ($1,$2,$3,$4,$5);
77         next if $progdata ne 'data';
78         $filename =~ s/\.asm$//;
79         $sym= $staticext eq 'static' ? "$filename:$sym" : "::$sym";
80         $symval{$sym}= $val;
81     }
82     die "$0: $mapfile: $!\n" if $maph->error;
83 }
84
85 $"=',';
86
87 print <<'END' or die $!
88 ; autogenerated - do not edit
89 END
90     ;
91
92 print <<END or die $!
93
94         include $includefile
95         radix dec
96
97 xxx_unknown_xxx equ     0
98 morse_section   org     morse_messages_start
99
100 END
101     if $which eq 'asm';
102
103 $bytes= 0;
104 $.= 0;
105
106 while (<>) {
107     chomp;
108     s/\#.*//;
109     next unless m/\S/;
110     s/\s+$//;
111     m/^([A-Z0-9]+)(\??)(?:\s+([^\t ;]+))?(?:\s+\;\s*(.*))?$/
112         or oops("syntax error");
113     $morse_name= $1;
114     $morse_optional= $2;
115     @morse= split //, $morse_name;
116     @addrs= defined($3) ? split /\,/, $3 : ();
117     $comment= $4;
118
119     @addrs < 8 or oops("only up to 7 addrs are supported");
120
121     @data= ();
122
123     $morse= join '00000', map { $morse{$_} } @morse;
124     $morse .= '0' x 7; # padding to fill any partial byte
125     while ($morse =~ s/^([01]{8})//) {
126         push @data, "$&b";
127     }
128     $morse =~ m/^0{0,7}$/ or die;
129     $morse_bytes= scalar(@data);
130
131     unshift @data, sprintf "0x%x%x", scalar(@addrs), $morse_bytes;
132     push @data, map {
133         s/^\:\b/ $filename.':' /e;
134         $filename= $1 if m/^([^:]+)\:/;
135         $_ = $symval{$_} if exists $symval{$_};
136         if ($which eq 'inc') {
137             $val= $_;
138         } elsif (m/\:/) {
139             printf STDERR "morse-generator: message \`%s': %s".
140                 "unknown symbol \`%s'\n",
141                 $morse_name, ($morse_optional ? 'warning: ' :''), $_;
142             exit 4 unless $morse_optional;
143             $val= ' xxx_unknown_xxx';
144         } else {
145             $val= "$_ - (0xf00 * !(($_ & 0xf00)^0xf00))";
146         }
147         $val;
148     } @addrs;
149
150     push @data, ('0') x (3 - (scalar(@data) + 3) % 4);
151
152     print("morse_$morse_name db @data\n") or die $!
153         if $which eq 'asm';
154
155     printf("morse_$morse_name equ morse_messages_start+0x%x\n",
156            $bytes) or die $!
157         if $which eq 'inc';
158
159     $bytes += scalar @data;
160 }
161
162 print <<'END' or die $!
163
164         if $ > morse_messages_end
165          error "too much morse - extends beyond morse_messages_end"
166         endif
167
168         end
169 END
170     if $which eq 'asm';
171
172 STDIN->error and die $!;
173 STDOUT->error and die $!;
174
175 __DATA__
176 A       .-
177 B       -...
178 C       -.-.
179 D       -..
180 E       .
181 F       ..-.
182 G       --.
183 H       ....
184 I       ..
185 J       .---
186 K       -.-
187 L       .-..
188 M       --
189 N       -.
190 O       ---
191 P       .--.
192 Q       --.-
193 R       .-.
194 S       ...
195 T       -
196 U       ..-
197 V       ...-
198 W       .--
199 X       -..-
200 Y       -.--
201 Z       --..
202 0       -----
203 1       .----
204 2       ..---
205 3       ...--
206 4       ....-
207 5       .....
208 6       -....
209 7       --...
210 8       ---..
211 9       ----.