File Coverage

blib/lib/Games/Rezrov/ZInterpreter.pm
Criterion Covered Total %
statement 118 159 74.2
branch 48 76 63.1
condition 5 16 31.2
subroutine 16 17 94.1
pod 0 5 0.0
total 187 273 68.5


line stmt bran cond sub pod time code
1             package Games::Rezrov::ZInterpreter;
2             # interpret z-code
3              
4 1     1   634 use strict;
  1         3  
  1         47  
5 1     1   81 no strict "refs";
  1         2  
  1         31  
6             # maybe a little faster here than during opcode call?
7              
8 1     1   7 use Games::Rezrov::Inliner;
  1         2  
  1         28  
9              
10 1     1   6 use constant OP_UNKNOWN => -1;
  1         2  
  1         75  
11 1     1   6 use constant OP_0OP => 0;
  1         2  
  1         45  
12 1     1   5 use constant OP_1OP => 1;
  1         1  
  1         37  
13 1     1   5 use constant OP_2OP => 2;
  1         2  
  1         36  
14 1     1   5 use constant OP_VAR => 3;
  1         3  
  1         32  
15 1     1   4 use constant OP_EXT => 4;
  1         2  
  1         32  
16              
17 1     1   4 use constant CALL_VN2 => 0x1a;
  1         3  
  1         31  
18 1     1   4 use constant CALL_VS2 => 0x0c;
  1         3  
  1         521  
19             # var opcodes
20              
21             my $INTERPRETER_GENERATED = 0;
22              
23             sub new {
24 1     1 0 15 my ($type, $zio) = @_;
25 1         3 my $self = {};
26 1         3 bless $self, $type;
27              
28 1         4 generate_interpreter_code();
29             # delay code generation until now so we can add optional code
30             # (or not include it) based on runtime options
31              
32 1         6 $self->zio($zio);
33              
34 1 50       6 if (my $where = Games::Rezrov::ZOptions::WRITE_OPCODES()) {
35 0 0       0 if ($where eq "STDERR") {
36 0         0 *Games::Rezrov::ZInterpreter::LOG = \*main::STDERR;
37             } else {
38 0 0       0 die "Can't write to $where: $!\n"
39             unless open(LOG, ">$where");
40             }
41 0         0 my $old = select();
42 0         0 select LOG;
43 0         0 $|=1;
44 0         0 select $old;
45             }
46              
47 1         5 $self->restart(1);
48 1         34 $self->interpret();
49 1         6 return $self;
50             }
51              
52             sub generate_interpreter_code {
53 1 50   1 0 4 unless ($INTERPRETER_GENERATED) {
54             # Generate code for main interpreter routine.
55             # add optional chunks of code only if they're being used, to
56             # make the loops as tight as possible. Good for a small
57             # speed improvement.
58              
59 1         8 local $/ = undef;
60 1         69 my $inline_code = ;
61              
62 1         5 my $CODE;
63              
64 1 50       14 if (Games::Rezrov::ZOptions::WRITE_OPCODES()) {
65 0         0 $CODE = '
66             printf LOG "count:%d style:%d pc:%d type:%s opcode:%d(0x%02x;raw=%d) (%s) operands:%s\n",
67             $opcode_count,
68             $op_style,
69             $start_pc,
70             $TYPE_LABELS[$op_style],
71             $opcode,
72             $opcode,
73             $orig_opcode,
74             ($generic_opcodes[$op_style]->[$opcode] ||
75             $manual_descs[$op_style]->[$opcode] || "???"),
76             join(",", @operands);
77             ';
78              
79 0 0       0 $inline_code =~ s/#WRITE_OPCODES_STUB/$CODE/ || die;
80             }
81              
82 1 50       40 if (Games::Rezrov::ZOptions::COUNT_OPCODES()) {
83 0         0 $CODE='
84             $op_counts[$op_style]++;
85             ';
86 0 0       0 $inline_code =~ s/#COUNT_OPCODES_STUB/$CODE/ || die;
87             }
88              
89 1         9 Games::Rezrov::Inliner::inline(\$inline_code);
90              
91             # print $inline_code;die;
92              
93 1 100 33 1 0 3040 eval $inline_code;
  1 100 33 0   4  
  1 100 66     7  
  1 100 33     5  
  1 100 0     3  
  0 50 0     0  
  0 100       0  
  0 100       0  
  0 100       0  
  1 50       2  
  1 100       5  
  1 100       4  
  1 100       1  
  1 100       3  
  1 50       2  
  4268 0       8662  
  4268 50       6989  
  4268 50       4315  
  4268 0       5309  
  4268 50       7617  
  4268 50       9276  
  2563 100       3001  
  2563 100       3423  
  2563 100       51310  
  2563 50       4800  
  2563 50       33077  
  2563 50       3221  
  2563 50       3259  
  1010         1887  
  1010         1186  
  1010         1235  
  695         2236  
  0         0  
  0         0  
  0         0  
  76         115  
  76         109  
  619         638  
  619         758  
  619         872  
  500         664  
  500         12704  
  119         285  
  619         1043  
  4268         14225  
  1010         5439  
  0         0  
  0         0  
  1010         1209  
  1010         1737  
  1010         2315  
  3862         5869  
  3862         8016  
  2910         4757  
  2673         3817  
  2673         76890  
  237         787  
  1010         1261  
  4268         9862  
  4234         4649  
  4234         56035  
  29         60  
  29         96  
  0         0  
  4         12  
  4         28  
  4         20  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         7  
  0         0  
  1         2  
  0         0  
  0         0  
  1         8  
  1         6  
  0         0  
  0         0  
  0         0  
  0         0  
  1         7  
  1         15  
  1         7  
  0         0  
  0         0  
  0         0  
94              
95 1         7 $INTERPRETER_GENERATED = 1;
96             }
97             }
98              
99             sub zio {
100 2 100   2 0 44 return (defined $_[1] ? $_[0]->{"zio"} = $_[1] : $_[0]->{"zio"});
101             }
102              
103             sub restart {
104 1     1 0 4 my ($self, $first_time) = @_;
105 1 50       5 Games::Rezrov::StoryFile::reset_storyfile() unless $first_time;
106 1         8 Games::Rezrov::StoryFile::reset_game();
107             }
108              
109             1;
110              
111             #
112             # code to be inlined starts here:
113             #
114             __DATA__