mirror of
https://github.com/simonowen/apple1emu.git
synced 2025-02-10 22:30:30 +00:00
87 lines
2.1 KiB
Perl
Executable File
87 lines
2.1 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
#
|
|
# Calculates opcode addresses for the inline instruction decoding table
|
|
|
|
# Allow -v option for verbose output
|
|
use Getopt::Std;
|
|
$opt_v = 0;
|
|
getopts('v');
|
|
|
|
$source = 'apple1emu.asm';
|
|
$codeend = 0xd000;
|
|
|
|
# Assemble, outputting the symbols containing opcode implementation lengths
|
|
$_ = `pyz80.py -s op_.*_len $source`;
|
|
|
|
# Create include file for definitions
|
|
my $outfile = 'opdefs.inc';
|
|
open(FILE, ">$outfile") or die "$!";
|
|
print FILE "; Opcode table positions (auto-generated by opdefs.pl)\n\n";
|
|
|
|
# Assembly failed?
|
|
if ($?)
|
|
{
|
|
# Create dummy offset list to allow lengths to be calculated
|
|
for (0..255) {
|
|
printf FILE "op_%02x: equ &%04x\n", $_, $codeend-0x1000;
|
|
}
|
|
|
|
print "Assembly error, creating dummy definitions!\n";
|
|
exit;
|
|
}
|
|
|
|
# Create hash from opcode to length
|
|
while (/OP_(..)_LEN': (\d+)/g) {
|
|
$len{hex $1} = $2;
|
|
}
|
|
|
|
# Position in order of size, largest first
|
|
@todo = reverse sort { $len{$a} <=> $len{$b} } keys %len;
|
|
|
|
my($size,$used) = (0,0);
|
|
|
|
OPCODE:
|
|
foreach $op (@todo)
|
|
{
|
|
MSB:
|
|
# Work up through MSB values until we find a space
|
|
for ($msb = 0 ; ; $msb++)
|
|
{
|
|
# Determine the extent of the opcode in the current MSB
|
|
my $start = ($msb << 8) | $op;
|
|
my $end = $start + $len{$op}-1;
|
|
|
|
# Check against what we've already positioned
|
|
foreach (keys %off)
|
|
{
|
|
# Determine extent of existing item
|
|
my $start2 = $off{$_};
|
|
my $end2 = $start2 + $len{$_}-1;
|
|
|
|
# Reject MSB if new position would overlap
|
|
next MSB unless ($start > $end2 || $end < $start2);
|
|
}
|
|
|
|
# Assign to the free spot we've found
|
|
$off{$op} = $start;
|
|
|
|
# Update size stats
|
|
$used += $len{$op};
|
|
if ($end > $size) { $size = $end; }
|
|
|
|
next OPCODE;
|
|
}
|
|
}
|
|
|
|
# Position base so code finishes at the required point
|
|
$base = $codeend - (($size + 0xff) & ~0xff);
|
|
|
|
print "Size = $size, used = $used, slack = ", $size-$used, "\n" unless !$opt_v;
|
|
|
|
# Output sorted list of calculated positions
|
|
foreach (sort { $a <=> $b } @todo) {
|
|
printf FILE "op_%02x: equ &%04x ; +$len{$_}\n", $_, $base+$off{$_};
|
|
}
|
|
|
|
close FILE;
|