mirror of
https://github.com/simonowen/apple1emu.git
synced 2024-05-31 12:41:31 +00:00
90 lines
2.3 KiB
Perl
90 lines
2.3 KiB
Perl
#!/usr/bin/perl -w
|
|
#
|
|
# Calculates opcode addresses for the inline instruction decoding table
|
|
#
|
|
# Used by the VIC-20 emulator, available from:
|
|
#
|
|
# http://simonowen.com/sam/apple1emu/
|
|
|
|
# Assemble, outputting the symbols containing opcode implementation lengths
|
|
$_ = `pyz80.py -s op_.*_len apple1emu.asm`;
|
|
|
|
# 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 &b000\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;
|
|
|
|
# Special fiddle to allow room for EX AF,AF' before BRA
|
|
$start-- if $op == 0x80;
|
|
|
|
# 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;
|
|
}
|
|
}
|
|
|
|
# Undo fiddle so BRA is positioned as normal
|
|
$off{0x80}++;
|
|
|
|
# Position base so code finishes just before &c000
|
|
$base = 0xc000 - (($size + 0xff) & ~0xff);
|
|
|
|
print "Size = $size, used = $used, slack = ", $size-$used, "\n";
|
|
|
|
# Output sorted list of calculated positions
|
|
foreach (sort { $a <=> $b } @todo)
|
|
{
|
|
my $offset = $base + $off{$_};
|
|
printf FILE "op_%02x: equ &%04x ; +$len{$_}\n", $_, $base+$off{$_};
|
|
}
|
|
|
|
close FILE;
|