#!/usr/bin/perl
# Converts morse.messages to *+morse.asm or morse+auto.inc.
# morse-auto.asm specifies some flash contents, as follows:
#
# Each message XY produces a symbol
# morse_XY
# which is in the flash between morse_messages_start and
# morse_messages_end, and which is guaranteed to be aligned to a
# multiple of 4 bytes.
#
# At that symbol will be a message in the following format:
# RAAAMMMM header byte, contents as follows:
# M (4 bits) number of bytes of morse pattern
# R reserved bit, always zero
# A (3 bits) number of bytes of addresses
# M bytes morse pattern, as bit string of LED on/off
# values (1=on) for equal-length periods
# (1 period = 1 morse dot), MS bit first
# trailing zeroes in last byte are probably
# best elided
# A bytes zero or more addresses which should be read
# and the corresponding value shown in binary.
# Addresses are only one byte each, interpreted
# like an access bank reference.
#
# morse_messages_start and morse_messages_end should be defined in
# morse-defs.inc, and should also be 4-byte aligned. morse-defs.inc
# should also arrange to define any symbolic addresse referred to
# in morse-auto.messages, eg by including the pXXXX.inc.
#
# *+morse.asm contains the actual source and morse+auto.inc
# contains `equ' definitions for the addresses morse_XY.
use IO::File;
use IO::Handle;
sub badusage () {
die ("usages:\n".
" morse-generator ... asm\n".
" morse-generator ... [.map] inc\n");
}
@ARGV or badusage();
$includefile= 'morse-defs.inc';
if ($ARGV[$#ARGV] =~ s/^\-I//) {
$includefile= pop @ARGV;
}
$which= pop @ARGV;
$which eq 'asm' or $which eq 'inc' or badusage();
while () {
($let,$morse) = (m/^([0-9A-Z])\s+([-.]+)$/) or die;
$morse =~ s/\./10/g;
$morse =~ s/\-/1110/g;
$morse =~ s/0$//;
$morse{$let}= $morse;
}
sub oops ($) { die "morse-generator: $ARGV:$.: $_[0]\n"; }
$mapfile= $ARGV[$#ARGV];
if ($mapfile =~ m/\.map$/) {
pop @ARGV;
$maph= new IO::File "$mapfile", 'r' or die "$0: $mapfile: $!\n";
while (<$maph>) {
next unless m/^\s+Symbols\s+$/ .. !/\S/;
next unless m/\S/;
next if m/^\s+Symbols\s+$/;
next if m/^\s+Name\s+Address\s+Location\s+Storage\s+File\s*$/;
next if m/^(?:\s+\-\-+){5}\s*$/;
m/^\s*([0-9a-zA-Z_]+)\s+(0+|0x[0-9a-f]+)\s+(program|data)\s+(static|extern)\s+(\S+)\s*$/
or die "$0: $mapfile:$.: cannot parse ?!\n";
($sym,$val,$progdata,$staticext,$filename) = ($1,$2,$3,$4,$5);
next if $progdata ne 'data';
$filename =~ s/\.asm$//;
$sym= $staticext eq 'static' ? "$filename:$sym" : "::$sym";
$symval{$sym}= $val;
}
die "$0: $mapfile: $!\n" if $maph->error;
}
$"=',';
print <<'END' or die $!
; autogenerated - do not edit
END
;
print <) {
chomp;
s/\#.*//;
next unless m/\S/;
s/\s+$//;
m/^([A-Z0-9]+)(\??)(?:\s+([^\t ;]+))?(?:\s+\;\s*(.*))?$/
or oops("syntax error");
$morse_name= $1;
$morse_optional= $2;
@morse= split //, $morse_name;
@addrs= defined($3) ? split /\,/, $3 : ();
$comment= $4;
@addrs < 8 or oops("only up to 7 addrs are supported");
@data= ();
$morse= join '000', map { $morse{$_} } @morse;
$morse .= '0' x 7; # padding to fill any partial byte
while ($morse =~ s/^([01]{8})//) {
push @data, "$&b";
}
$morse =~ m/^0{0,7}$/ or die;
$morse_bytes= scalar(@data);
unshift @data, sprintf "0x%x%x", scalar(@addrs), $morse_bytes;
push @data, map {
s/^\:\b/ $filename.':' /e;
$filename= $1 if m/^([^:]+)\:/;
$_ = $symval{$_} if exists $symval{$_};
if ($which eq 'inc') {
$val= $_;
} elsif (m/\:/) {
printf STDERR "morse-generator: message \`%s': %s".
"unknown symbol \`%s'\n",
$morse_name, ($morse_optional ? 'warning: ' :''), $_;
exit 4 unless $morse_optional;
$val= ' xxx_unknown_xxx';
} else {
$val= "$_ - (0xf00 * !(($_ & 0xf00)^0xf00))";
}
$val;
} @addrs;
push @data, ('0') x (3 - (scalar(@data) + 3) % 4);
print("morse_$morse_name db @data\n") or die $!
if $which eq 'asm';
printf("morse_$morse_name equ morse_messages_start+0x%x; panic_address=%x\n",
$bytes, $bytes/4) or die $!
if $which eq 'inc';
$bytes += scalar @data;
}
print <<'END' or die $!
if $ > morse_messages_end
error "too much morse - extends beyond morse_messages_end"
endif
end
END
if $which eq 'asm';
STDIN->error and die $!;
STDOUT->error and die $!;
__DATA__
A .-
B -...
C -.-.
D -..
E .
F ..-.
G --.
H ....
I ..
J .---
K -.-
L .-..
M --
N -.
O ---
P .--.
Q --.-
R .-.
S ...
T -
U ..-
V ...-
W .--
X -..-
Y -.--
Z --..
0 -----
1 .----
2 ..---
3 ...--
4 ....-
5 .....
6 -....
7 --...
8 ---..
9 ----.