CPU-Z80-Disassembler
view release on metacpan or search on metacpan
t/dis_zx81.t view on Meta::CPAN
}
else {
push @block, "\n", x4($addr)."\t:C $label\n", "\n";
}
}
push @$ctl_to, @block;
return $addr;
}
elsif ($asm->[0] =~ /^L[0-9A-F]+:\s*|^\s+/) { # code block
# get opcode and first comment
my $line = $';
my($opcode, $comment);
if ($line =~ /\s*;/) {
$opcode = $`;
chomp($comment = $');
}
else {
($opcode = $line) =~ s/\s+$//;
}
# update ctl file
if ($opcode =~ /^DEFB\s+(.*)/) {
$addr = consume_bytes($addr, 1, $1, $ctl_from, $ctl_to, $comment);
}
elsif ($opcode =~ /^DEFW\s+(.*)/) {
$addr = consume_bytes($addr, 2, $1, $ctl_from, $ctl_to, $comment);
}
else {
$addr = consume_code($addr, $opcode, $ctl_from, $ctl_to, $comment);
}
# get following comments
shift @$asm;
while (@$asm && $asm->[0] =~ /^\s+;|^\s*$/) { # follow-on comments
chomp(my $comment = $');
push @$ctl_to, " " x 32, ":;$comment\n";
shift @$asm;
}
return $addr;
}
else {
die "cannot parse ", $asm->[0];
}
}
sub consume_bytes {
my($addr, $size, $def_args, $ctl_from, $ctl_to, $comment) = @_;
my $num = scalar(split(/,/, $def_args));
my($new_addr, $bytes_str) = get_bytes_str($addr, $num * $size, $ctl_from);
push @$ctl_to, sprintf("%-31s", x4($addr).'-'.x4($new_addr-1).' '.$bytes_str)." :".
($size == 1 ? 'B' : 'W')."\n";
if (defined $comment) {
push @$ctl_to, (" " x 32).":;$comment\n";
}
# synchronize code after bytes
isa_ok my $dis = CPU::Z80::Disassembler->new(), 'CPU::Z80::Disassembler';
$dis->memory->load_file($rom_file, $new_addr, $new_addr);
$dis->write_dump($ctl_file."2");
@$ctl_from = path($ctl_file."2")->lines;
unlink $ctl_file."2";
return $new_addr;
}
sub consume_code {
my($addr, $opcode, $ctl_from, $ctl_to, $comment) = @_;
# compare asm hash
@$ctl_from or die;
$ctl_from->[0] =~ /^([0-9A-F]{4})\s+([0-9A-F]+)\s+(.*)/ or die;
hex($1) == $addr or die;
my $size = length($2) / 2;
my $ctl_hash = $3;
my $opcode_hash = $opcode;
for ($ctl_hash, $opcode_hash) {
$_ = uc($_);
s/\s+//g;
s/[L\$]([0-9A-F]{4})/\$$1/g;
s/(I[XY])\+\$0+/$1/g;
s/(RST)\$?([0-9A-F]{2})H?/$1$2/;
s/[L\$]([0-9A-F]+)\+\$?([0-9A-F]+)/ '$' . x4(hex($1)+hex($2)) /ge;
s/[L\$]([0-9A-F]+)\-\$?([0-9A-F]+)/ '$' . x4(hex($1)-hex($2)) /ge;
}
$ctl_hash eq $opcode_hash or die "($ctl_hash,$opcode_hash)";
# copy to output
chomp(my $line = shift @$ctl_from);
$line = sprintf("%-31s", $line).(defined $comment ? " :;$comment" : "")."\n";
push @$ctl_to, $line;
$addr += $size;
return $addr;
}
sub get_bytes_str {
my($addr, $num, $ctl_from) = @_;
my $bytes_str = '';
my $got = 0;
while ($got < $num) {
@$ctl_from or die;
if ($ctl_from->[0] =~ /^([0-9A-F]{4})\s+([0-9A-F]{2})([0-9A-F]*)/) { # has one byte
hex($1) == $addr or die;
$ctl_from->[0] = x4($addr+1).' '.$3.' '.$';
$bytes_str .= $2;
shift @$ctl_from if $3 eq ''; # was last byte in the line
$addr++;
$got++;
}
else {
shift @$ctl_from;
}
( run in 1.984 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )