#!/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 ----.