Я не обязательно думаю, что будет хорошей идеей читать двоичный символ по одному за раз (хотя, для достаточно маленьких файлов вы будете извлекать из буфера большую часть времени).Концептуально чтение файла в плоский массив лучше.Вы можете получить это, используя
my @ROM = do {
local $/ = \1;
map ord, <$fh>;
};
Я думаю, что это отвечает сути вашего вопроса.
Теперь, что касается идеи не читать весь файл в массив, а использоватьсам файл в качестве исполняемого образа, вот небольшой скрипт, который я написал на основе более ранних версий этого поста и отзывов.
Обратите внимание, что вся функция скалярного дескриптора файла предназначена для предоставления лесов для запуска ПЗУ, включенных в статью.Вы связались путем копирования и вставки вместо того, чтобы создавать двоичные файлы.
#!/usr/bin/env perl
use strict;
use warnings;
use Fcntl ':seek';
use Try::Tiny;
my %ROMS = (
rom1 => [0x04, 0x41, 0x09, 0x02, 0x0a],
rom2 => [
0x04, 0x41, 0x09, 0x02,
0x07, 0x09, 0x02, 0x07,
0x09, 0x02, 0x07, 0x09,
0x02, 0x07, 0x09, 0x02,
0x0A,
],
rom3 => [
0x04, 69, 0x09, 0x02, 0x04, 110, 0x09, 0x02,
0x04, 116, 0x09, 0x02, 0x04, 101, 0x09, 0x02,
0x04, 114, 0x09, 0x02, 0x04, 32, 0x09, 0x02,
0x04, 97, 0x09, 0x02, 0x04, 32, 0x09, 0x02,
0x04, 67, 0x09, 0x02, 0x04, 104, 0x09, 0x02,
0x04, 97, 0x09, 0x02, 0x04, 114, 0x09, 0x02,
0x04, 32, 0x09, 0x02, 0x04, 58, 0x09, 0x02,
0x04, 32, 0x09, 0x02, 0x04, 50, 0x03, 0x01,
0x04, 2, 0x03, 0x04, 89, 0x09, 0x02, 0x04,
111, 0x09, 0x02, 0x04, 117, 0x09, 0x02, 0x04,
32, 0x09, 0x02, 0x04, 84, 0x09, 0x02, 0x04,
121, 0x09, 0x02, 0x04, 112, 0x09, 0x02, 0x04,
101, 0x09, 0x02, 0x04, 100, 0x09, 0x02, 0x04,
32, 0x09, 0x02, 0x04, 58, 0x09, 0x02, 0x04,
32, 0x09, 0x02, 0x04, 50, 0x03, 0x02, 0x0A,
]
);
for my $rom (sort keys %ROMS) {
my $rom_s = join '', map chr, @{ $ROMS{ $rom } };
open my $rom_h, '<:raw', \$rom_s
or die "Cannot open handle to ROM string: $!\n";
print "Executing $rom\n";
try {
execute($rom_h);
}
catch {
print "\n$rom: $_\n";
};
close $rom_h
or die "Cannot close handle to ROM string: $!\n";
}
sub get_next_byte {
my ($fh) = @_;
my $byte = do {
local $/ = \1;
scalar <$fh>;
};
return unless defined $byte;
$byte = ord $byte;
return $byte;
}
sub execute {
my ($ROM) = @_;
my $FLAG = 0;
my $SP = 0;
my $X = 0;
my @STACK;
my @machine = (
# NOP
sub {},
# INPUT
sub { $STACK[$SP] = ord(getc STDIN) },
# OUTPUT
sub { printf STDOUT '%c', $STACK[$SP] },
# MOV SP, X
sub { $SP = $X },
# MOV X, DATA
sub {
$X = get_next_byte($ROM);
},
# CMP X, DATA
sub {
$FLAG = $X - get_next_byte($ROM);
},
# JE
sub {
my $offset = get_next_byte($ROM);
if ($FLAG == 0) {
seek $ROM, $offset, SEEK_CUR
}
},
# INC X
sub { $X += 1 },
# INC SP
sub { $SP += 1 },
# MOV [SP], X
sub { $STACK[$SP] = $X },
# HALT
sub {
die "HALT\n";
},
);
while (1) {
my $opcode = get_next_byte($ROM);
last unless defined $opcode;
if (($opcode >= 0) and ($opcode < @machine)) {
$machine[ $opcode ]->();
}
else {
die sprintf(
"Invalid opcode '%02x' at offset '%x'\n",
$opcode, $.,
);
}
}
}
Вывод:
Executing rom1
A
rom1: HALT
Executing rom2
ABCDE
rom2: HALT
Executing rom3
Enter a Char : d
You Typed : d
rom3: HALT