line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package D64::File::PRG;
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
D64::File::PRG - Handling individual C64's PRG files
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use D64::File::PRG;
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my $prg = D64::File::PRG->new('FILE' => $file);
|
12
|
|
|
|
|
|
|
my $prg = D64::File::PRG->new('RAW_DATA' => \$data, 'LOADING_ADDRESS' => 0x0801);
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
$prg->change_loading_address('LOADING_ADDRESS' => 0x6400);
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my $data = $prg->get_data();
|
17
|
|
|
|
|
|
|
my $data = $prg->get_data('FORMAT' => 'ASM', 'ROW_LENGTH' => 10);
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
$prg->set_data('RAW_DATA' => \$data, 'LOADING_ADDRESS' => 0x1000);
|
20
|
|
|
|
|
|
|
$prg->set_data('RAW_DATA' => \$data);
|
21
|
|
|
|
|
|
|
$prg->set_file_data('FILE_DATA' => \$file_data);
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
$prg->write_file('FILE' => $file);
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
D64::File::PRG is a Perl module providing the set of methods for handling individual C64's PRG files. It enables an easy access to the raw contents of any PRG file, manipulation of its loading address, and transforming binary data into assembly code understood by tools like "Dreamass" or "Turbo Assembler".
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 METHODS
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=cut
|
32
|
|
|
|
|
|
|
|
33
|
2
|
|
|
2
|
|
73014
|
use bytes;
|
|
2
|
|
|
|
|
21
|
|
|
2
|
|
|
|
|
9
|
|
34
|
2
|
|
|
2
|
|
54
|
use strict;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
68
|
|
35
|
2
|
|
|
2
|
|
12
|
use warnings;
|
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
55
|
|
36
|
|
|
|
|
|
|
|
37
|
2
|
|
|
2
|
|
11
|
use Carp;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
178
|
|
38
|
2
|
|
|
2
|
|
10
|
use Exporter;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
82
|
|
39
|
2
|
|
|
2
|
|
2132
|
use IO::Scalar;
|
|
2
|
|
|
|
|
40718
|
|
|
2
|
|
|
|
|
117
|
|
40
|
2
|
|
|
2
|
|
58
|
use Scalar::Util qw(looks_like_number);
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
8442
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
our $VERSION = '0.03';
|
43
|
|
|
|
|
|
|
our @ISA = qw(Exporter);
|
44
|
|
|
|
|
|
|
our @EXPORT = ();
|
45
|
|
|
|
|
|
|
our @EXPORT_OK = qw();
|
46
|
|
|
|
|
|
|
our %EXPORT_TAGS = (default => [qw()]);
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
local $| = 1;
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head2 new
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
A new D64::File::PRG object instance is created either by providing the path to an existing file, which is then being read into a memory, or by providing a scalar reference to the raw binary data with an accompanying loading address. This is illustrated by the following examples:
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
my $prg = D64::File::PRG->new('FILE' => $file);
|
55
|
|
|
|
|
|
|
my $prg = D64::File::PRG->new('RAW_DATA' => \$data, 'LOADING_ADDRESS' => 0x0801);
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Constructor will die upon one of the following conditions:
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
1. File size is less than two bytes.
|
60
|
|
|
|
|
|
|
2. Loading address provided is outside of a 16-bit range.
|
61
|
|
|
|
|
|
|
3. Any character within a raw data is not a single byte.
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
There is an additional optional boolean "VERBOSE" available (defaulting to 0), which indicates that the extensive debugging messages should be printed out to the standard output. By default module acts silently, reporting error messages only.
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=cut
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub new {
|
68
|
15
|
|
|
15
|
1
|
15541
|
my $this = shift;
|
69
|
15
|
|
33
|
|
|
75
|
my $class = ref($this) || $this;
|
70
|
15
|
|
|
|
|
25
|
my $self = {};
|
71
|
15
|
|
|
|
|
245
|
bless $self, $class;
|
72
|
15
|
|
|
|
|
43
|
$self->_initialize(@_);
|
73
|
15
|
|
|
|
|
40
|
return $self;
|
74
|
|
|
|
|
|
|
}
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _initialize {
|
77
|
15
|
|
|
15
|
|
21
|
my $self = shift;
|
78
|
15
|
|
|
|
|
50
|
my $params = {@_};
|
79
|
15
|
|
|
|
|
27
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
80
|
15
|
|
|
|
|
460
|
my $file = $params->{'FILE'}; # get data from file
|
81
|
15
|
|
|
|
|
23
|
my $loading_address = $params->{'LOADING_ADDRESS'}; # externally provided loading address
|
82
|
15
|
|
|
|
|
22
|
my $raw_data_ref = $params->{'RAW_DATA'}; # externally provided raw data
|
83
|
15
|
|
|
|
|
258
|
my ($package) = (caller(0))[0];
|
84
|
15
|
|
|
|
|
210
|
$self->{'VERBOSE'} = $verbose;
|
85
|
15
|
50
|
|
|
|
35
|
$self->_verbose_message('MESSAGE' => "Initializing new \"${package}\" object instance", 'ERROR' => 0) if $verbose;
|
86
|
|
|
|
|
|
|
# When "FILE" parameter is defined, it takes the precedence over "LOAD/DATA" parameters:
|
87
|
15
|
50
|
|
|
|
32
|
if (defined $file) {
|
88
|
0
|
|
|
|
|
0
|
$self->read_file('FILE' => $file);
|
89
|
|
|
|
|
|
|
}
|
90
|
|
|
|
|
|
|
else {
|
91
|
|
|
|
|
|
|
# LOADING_ADDRESS: loading address (must be a valid value)
|
92
|
15
|
50
|
|
|
|
233
|
unless (defined $loading_address) {
|
93
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "an undefined loading address has been provided to the constructor", 'ERROR' => 1);
|
94
|
|
|
|
|
|
|
}
|
95
|
15
|
|
|
|
|
43
|
$self->_get_loading_address_from_scalar('LOADING_ADDRESS' => $loading_address, 'VERBOSE' => $verbose);
|
96
|
|
|
|
|
|
|
# RAW_DATA: binary data provided as a raw data scalar
|
97
|
15
|
|
|
|
|
78
|
$self->_get_raw_contents_from_scalarref('RAW_DATA' => $raw_data_ref, 'VERBOSE' => $verbose);
|
98
|
|
|
|
|
|
|
}
|
99
|
15
|
50
|
|
|
|
36
|
$self->_verbose_message('MESSAGE' => "Returning new object instance upon successful init", 'ERROR' => 0) if $verbose;
|
100
|
15
|
|
|
|
|
38
|
return;
|
101
|
|
|
|
|
|
|
}
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub _get_loading_address_from_scalar {
|
104
|
18
|
|
|
18
|
|
23
|
my $self = shift;
|
105
|
18
|
|
|
|
|
51
|
my $params = {@_};
|
106
|
18
|
|
|
|
|
30
|
my $loading_address = $params->{'LOADING_ADDRESS'}; # externally provided loading address
|
107
|
18
|
|
|
|
|
227
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
108
|
18
|
100
|
|
|
|
64
|
unless (looks_like_number $loading_address) {
|
109
|
1
|
|
|
|
|
3
|
$self->_verbose_message('MESSAGE' => "a non-numeric scalar value cannot be converted into loading address", 'ERROR' => 1);
|
110
|
|
|
|
|
|
|
}
|
111
|
17
|
|
|
|
|
68
|
my $loading_address_readable = uc sprintf "\$%04x", $loading_address;
|
112
|
17
|
50
|
|
|
|
49
|
$self->_verbose_message('MESSAGE' => "Validating value of provided loading address: ${loading_address_readable}", 'ERROR' => 0) if $verbose;
|
113
|
17
|
50
|
33
|
|
|
82
|
if ($loading_address < 0x0000 or $loading_address > 0xffff) {
|
114
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "invalid loading address provided (${loading_address_readable})", 'ERROR' => 1);
|
115
|
|
|
|
|
|
|
}
|
116
|
17
|
50
|
|
|
|
138
|
$self->_verbose_message('MESSAGE' => "Received the correct file loading address: ${loading_address_readable}", 'ERROR' => 0) if $verbose;
|
117
|
17
|
|
|
|
|
50
|
$self->{'LOADING_ADDRESS'} = $loading_address;
|
118
|
|
|
|
|
|
|
}
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head2 read_file
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
While operating an existing D64::File::PRG object instance, there is no need to create a new one when you simply want to replace it with the contents of another file, that is if you only want to load a new data (however you need to create a new object instance if you want to provide raw data through a scalar reference - this limitation should be patched with the next release of this module). The example follows:
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
$prg->read_file('FILE' => $file);
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=cut
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub read_file {
|
129
|
0
|
|
|
0
|
1
|
0
|
my $self = shift;
|
130
|
0
|
|
|
|
|
0
|
my $params = {@_};
|
131
|
0
|
|
|
|
|
0
|
my $file = $params->{'FILE'}; # get data from file
|
132
|
0
|
|
|
|
|
0
|
my $verbose = $self->{'VERBOSE'}; # display diagnostic messages
|
133
|
|
|
|
|
|
|
# Verify if file exists:
|
134
|
0
|
0
|
|
|
|
0
|
unless (-e $file) {
|
135
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "file \"${file}\" does not exist", 'ERROR' => 1);
|
136
|
|
|
|
|
|
|
}
|
137
|
0
|
|
|
|
|
0
|
$self->{'FILENAME'} = $file;
|
138
|
|
|
|
|
|
|
# Read data from file:
|
139
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Opening file \"${file}\" for reading", 'ERROR' => 0) if $verbose;
|
140
|
0
|
0
|
|
|
|
0
|
open my $fh, '<', $file or $self->_verbose_message('MESSAGE' => "could not open filehandle for \"${file}\" file", 'ERROR' => 1);
|
141
|
0
|
|
|
|
|
0
|
binmode $fh, ':bytes';
|
142
|
0
|
|
|
|
|
0
|
$self->_read_file('FILEHANDLE' => $fh, 'VERBOSE' => $verbose);
|
143
|
0
|
0
|
|
|
|
0
|
close $fh or $self->_verbose_message('MESSAGE' => "could not close opened filehandle for \"${file}\" file", 'ERROR' => 1);
|
144
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Closing file \"${file}\" upon successful read", 'ERROR' => 0) if $verbose;
|
145
|
|
|
|
|
|
|
}
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub _read_file {
|
148
|
4
|
|
|
4
|
|
12
|
my ($self, %params) = @_;
|
149
|
|
|
|
|
|
|
|
150
|
4
|
|
|
|
|
7
|
my $fh = $params{FILEHANDLE};
|
151
|
4
|
|
|
|
|
5
|
my $verbose = $params{VERBOSE};
|
152
|
|
|
|
|
|
|
|
153
|
4
|
|
|
|
|
11
|
$self->_get_loading_address_from_file(FILEHANDLE => $fh, VERBOSE => $verbose);
|
154
|
2
|
|
|
|
|
8
|
$self->_get_raw_contents_from_file(FILEHANDLE => $fh, VERBOSE => $verbose);
|
155
|
|
|
|
|
|
|
|
156
|
2
|
|
|
|
|
5
|
return;
|
157
|
|
|
|
|
|
|
}
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub _get_raw_contents_from_scalarref {
|
160
|
20
|
|
|
20
|
|
27
|
my $self = shift;
|
161
|
20
|
|
|
|
|
50
|
my $params = {@_};
|
162
|
20
|
|
|
|
|
60
|
my $raw_data_ref = $params->{'RAW_DATA'}; # externally provided raw data
|
163
|
20
|
|
|
|
|
33
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
164
|
20
|
100
|
|
|
|
58
|
unless (ref $raw_data_ref eq 'SCALAR') {
|
165
|
1
|
50
|
|
|
|
5
|
my $raw_data_reftype = ref ($raw_data_ref) ? ( ref ($raw_data_ref) . ' reference' ) : 'SCALAR itself';
|
166
|
1
|
|
|
|
|
7
|
$self->_verbose_message('MESSAGE' => "raw data has to be a SCALAR reference (but is a ${raw_data_reftype})", 'ERROR' => 1);
|
167
|
|
|
|
|
|
|
}
|
168
|
19
|
|
|
|
|
35
|
$self->{'RAW_DATA'} = []; # empty all previously stored raw file contents
|
169
|
19
|
|
|
|
|
47
|
my ($bytes_count, $byte) = (0);
|
170
|
19
|
50
|
|
|
|
37
|
$self->_verbose_message('MESSAGE' => "Retrieving raw file contents from a SCALAR reference", 'ERROR' => 0) if $verbose;
|
171
|
19
|
|
|
|
|
29
|
my $raw_data_length = length ${$raw_data_ref};
|
|
19
|
|
|
|
|
33
|
|
172
|
19
|
|
|
|
|
49
|
while ($bytes_count < $raw_data_length) {
|
173
|
116
|
|
|
|
|
127
|
my $byte = substr ${$raw_data_ref}, $bytes_count, 1;
|
|
116
|
|
|
|
|
198
|
|
174
|
116
|
|
|
|
|
151
|
my $byte_value = ord $byte; # get byte numeric value
|
175
|
116
|
50
|
33
|
|
|
496
|
if ($byte_value < 0x00 or $byte_value > 0xff) {
|
176
|
0
|
|
|
|
|
0
|
my $byte_value_readable = sprintf "\$%02x", $byte_value;
|
177
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "invalid byte value (${byte_value_readable}) in raw data at offset ${bytes_count}", 'ERROR' => 1);
|
178
|
|
|
|
|
|
|
}
|
179
|
116
|
|
|
|
|
123
|
push @{$self->{'RAW_DATA'}}, $byte_value;
|
|
116
|
|
|
|
|
215
|
|
180
|
116
|
|
|
|
|
248
|
$bytes_count++;
|
181
|
|
|
|
|
|
|
}
|
182
|
19
|
50
|
|
|
|
68
|
$self->_verbose_message('MESSAGE' => "Received ${bytes_count} bytes of the raw file contents", 'ERROR' => 0) if $verbose;
|
183
|
|
|
|
|
|
|
}
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub _get_raw_contents_from_file {
|
186
|
2
|
|
|
2
|
|
3
|
my $self = shift;
|
187
|
2
|
|
|
|
|
5
|
my $params = {@_};
|
188
|
2
|
|
|
|
|
3
|
my $fh = $params->{'FILEHANDLE'}; # already opened filehandle
|
189
|
2
|
|
|
|
|
4
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
190
|
2
|
|
|
|
|
4
|
my $file = $self->{'FILENAME'}; # filename associated with "$fh" filehandle
|
191
|
2
|
|
|
|
|
9
|
my ($bytes_count, $byte) = (0);
|
192
|
2
|
|
|
|
|
6
|
$self->{'RAW_DATA'} = []; # empty all previously stored raw file contents
|
193
|
2
|
50
|
|
|
|
7
|
$self->_verbose_message('MESSAGE' => "Retrieving raw file contents from an opened filehandle", 'ERROR' => 0) if $verbose;
|
194
|
2
|
|
|
|
|
7
|
while ( sysread $fh, $byte, 1 ) {
|
195
|
9
|
|
|
|
|
113
|
$bytes_count++;
|
196
|
9
|
|
|
|
|
10
|
push @{$self->{'RAW_DATA'}}, ord $byte; # get byte numeric value
|
|
9
|
|
|
|
|
38
|
|
197
|
|
|
|
|
|
|
}
|
198
|
2
|
50
|
|
|
|
29
|
$self->_verbose_message('MESSAGE' => "Received ${bytes_count} bytes of the raw file contents", 'ERROR' => 0) if $verbose;
|
199
|
|
|
|
|
|
|
}
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub _get_loading_address_from_file {
|
202
|
4
|
|
|
4
|
|
6
|
my $self = shift;
|
203
|
4
|
|
|
|
|
10
|
my $params = {@_};
|
204
|
4
|
|
|
|
|
8
|
my $fh = $params->{'FILEHANDLE'}; # already opened filehandle
|
205
|
4
|
|
|
|
|
7
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
206
|
4
|
|
|
|
|
5
|
my $file = $self->{'FILENAME'}; # filename associated with "$fh" filehandle
|
207
|
4
|
|
|
|
|
6
|
my ($load_addr_lo, $load_addr_hi, $bytes_count);
|
208
|
4
|
50
|
|
|
|
9
|
$self->_verbose_message('MESSAGE' => "Retrieving loading address from an opened filehandle", 'ERROR' => 0) if $verbose;
|
209
|
4
|
|
|
|
|
27
|
$bytes_count = sysread $fh, $load_addr_lo, 1;
|
210
|
4
|
50
|
|
|
|
72
|
my $filename = defined $file ? qq{"${file}"} : q{IO::Scalar};
|
211
|
4
|
100
|
|
|
|
10
|
if ($bytes_count != 1) {
|
212
|
1
|
|
|
|
|
6
|
$self->_verbose_message('MESSAGE' => "unexpected end of file while reading loading address from $filename filehandle", 'ERROR' => 1);
|
213
|
|
|
|
|
|
|
}
|
214
|
3
|
|
|
|
|
8
|
$bytes_count = sysread $fh, $load_addr_hi, 1;
|
215
|
3
|
100
|
|
|
|
37
|
if ($bytes_count != 1) {
|
216
|
1
|
|
|
|
|
5
|
$self->_verbose_message('MESSAGE' => "unexpected end of file while reading loading address from $filename filehandle", 'ERROR' => 1);
|
217
|
|
|
|
|
|
|
}
|
218
|
2
|
|
|
|
|
6
|
my $loading_address = ord ($load_addr_lo) + 0x100 * ord ($load_addr_hi);
|
219
|
2
|
|
|
|
|
8
|
my $loading_address_readable = uc sprintf "\$%04x", $loading_address;
|
220
|
2
|
50
|
|
|
|
5
|
$self->_verbose_message('MESSAGE' => "Received the correct file loading address: ${loading_address_readable}", 'ERROR' => 0) if $verbose;
|
221
|
2
|
|
|
|
|
6
|
$self->{'LOADING_ADDRESS'} = $loading_address;
|
222
|
|
|
|
|
|
|
}
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head2 get_data
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
All raw data can be accessed through this method. You might explicitly want to request the format of a data retrieved. By default the raw content is collected unless you otherwise specify to get an assembly formatted source code. In both cases a scalar value is returned. In the latter case you are able to provide an additional parameter indicating how many byte values will be returned on a single line (these are 8 bytes by default). Here are a couple of examples:
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
my $raw_data = $prg->get_data('FORMAT' => 'RAW', 'LOAD_ADDR_INCL' => 0);
|
229
|
|
|
|
|
|
|
my $asm_data = $prg->get_data('FORMAT' => 'ASM', 'LOAD_ADDR_INCL' => 1, 'ROW_LENGTH' => 4);
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
There is an additional optional boolean "LOAD_ADDR_INCL", which indicates if a loading address should be included in the output string. For raw contents it defaults to 0, while for assembly source code format it defaults to 1. This is reasonable, as you usually don't want loading address included in a raw data, but it becomes quite useful when compiling a source code.
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=cut
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub get_data {
|
236
|
16
|
|
|
16
|
1
|
271
|
my $self = shift;
|
237
|
16
|
|
|
|
|
44
|
my $params = {@_};
|
238
|
16
|
|
|
|
|
29
|
my $verbose = $self->{'VERBOSE'};
|
239
|
16
|
|
|
|
|
28
|
my $format = $params->{'FORMAT'}; # format of data returned from this method (defaults to "RAW")
|
240
|
16
|
100
|
|
|
|
38
|
$format = 'RAW' unless defined $format;
|
241
|
|
|
|
|
|
|
# LOAD_ADDR_INCL: a boolean indicating if loading address should be included to output
|
242
|
|
|
|
|
|
|
# It defaults to 0 for RAW format, and to 1 for ASM format
|
243
|
16
|
|
|
|
|
24
|
my $loading_address_included = $params->{'LOAD_ADDR_INCL'};
|
244
|
16
|
100
|
|
|
|
35
|
if ($format eq 'RAW') {
|
|
|
50
|
|
|
|
|
|
245
|
14
|
50
|
|
|
|
37
|
$self->_verbose_message('MESSAGE' => "Getting raw data contents into a scalar value", 'ERROR' => 0) if $verbose;
|
246
|
14
|
|
|
|
|
19
|
my $data = ''; # prepare scalar value with the whole RAW contents
|
247
|
14
|
100
|
|
|
|
55
|
$self->_add_loading_address_to_scalarref('RAW_DATA' => \$data, 'VERBOSE' => $verbose) if $loading_address_included;
|
248
|
14
|
|
|
|
|
38
|
$self->_add_raw_data_to_scalarref('RAW_DATA' => \$data, 'VERBOSE' => $verbose);
|
249
|
14
|
|
|
|
|
66
|
return $data;
|
250
|
|
|
|
|
|
|
} elsif ($format eq 'ASM') {
|
251
|
2
|
50
|
|
|
|
6
|
$loading_address_included = 1 unless defined $loading_address_included;
|
252
|
2
|
50
|
|
|
|
5
|
$self->_verbose_message('MESSAGE' => "Getting raw data composed as an assembly source code", 'ERROR' => 0) if $verbose;
|
253
|
2
|
|
100
|
|
|
9
|
my $row_length = $params->{'ROW_LENGTH'} || 8;
|
254
|
2
|
50
|
33
|
|
|
28
|
if ($row_length !~ m/^\d+$/ or $row_length < 0x01 or $row_length > 0xff) {
|
|
|
|
33
|
|
|
|
|
255
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "invalid row length (\"${row_length}\") request for assembly raw data composition", 'ERROR' => 1);
|
256
|
|
|
|
|
|
|
}
|
257
|
2
|
|
|
|
|
4
|
my $data = ''; # prepare scalar value with the whole ASSEMBLY contents
|
258
|
2
|
50
|
|
|
|
7
|
if ($loading_address_included) {
|
259
|
2
|
|
|
|
|
9
|
$self->_compose_comment_line_to_scalarref('RAW_DATA' => \$data, 'ROW_LENGTH' => $row_length, 'VERBOSE' => $verbose);
|
260
|
2
|
|
|
|
|
8
|
$self->_compose_loading_address_to_scalarref('RAW_DATA' => \$data, 'VERBOSE' => $verbose);
|
261
|
|
|
|
|
|
|
}
|
262
|
2
|
|
|
|
|
7
|
$self->_compose_comment_line_to_scalarref('RAW_DATA' => \$data, 'ROW_LENGTH' => $row_length, 'VERBOSE' => $verbose);
|
263
|
2
|
|
|
|
|
7
|
$self->_compose_raw_data_to_scalarref('RAW_DATA' => \$data, 'ROW_LENGTH' => $row_length, 'VERBOSE' => $verbose);
|
264
|
2
|
|
|
|
|
6
|
$self->_compose_comment_line_to_scalarref('RAW_DATA' => \$data, 'ROW_LENGTH' => $row_length, 'VERBOSE' => $verbose);
|
265
|
2
|
|
|
|
|
8
|
return $data;
|
266
|
|
|
|
|
|
|
}
|
267
|
|
|
|
|
|
|
else {
|
268
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "unrecognized data format (\"${format}\")", 'ERROR' => 1);
|
269
|
|
|
|
|
|
|
}
|
270
|
|
|
|
|
|
|
}
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub _compose_comment_line_to_scalarref {
|
273
|
6
|
|
|
6
|
|
7
|
my $self = shift;
|
274
|
6
|
|
|
|
|
18
|
my $params = {@_};
|
275
|
6
|
|
|
|
|
11
|
my $data_ref = $params->{'RAW_DATA'}; # scalar value with the whole RAW contents
|
276
|
6
|
|
|
|
|
9
|
my $row_length = $params->{'ROW_LENGTH'}; # number of byte values per single line
|
277
|
6
|
|
|
|
|
9
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
278
|
6
|
|
|
|
|
7
|
${$data_ref} .= ';' . '-' x (19 + 5 * $row_length) . "\n";
|
|
6
|
|
|
|
|
33
|
|
279
|
|
|
|
|
|
|
}
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub _compose_raw_data_to_scalarref {
|
282
|
2
|
|
|
2
|
|
4
|
my $self = shift;
|
283
|
2
|
|
|
|
|
5
|
my $params = {@_};
|
284
|
2
|
|
|
|
|
3
|
my $data_ref = $params->{'RAW_DATA'}; # scalar value with the whole RAW contents
|
285
|
2
|
|
|
|
|
3
|
my $row_length = $params->{'ROW_LENGTH'}; # number of byte values per single line
|
286
|
2
|
|
|
|
|
4
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
287
|
2
|
|
|
|
|
2
|
my $line;
|
288
|
2
|
|
|
|
|
3
|
my $offset = 0;
|
289
|
2
|
|
|
|
|
2
|
foreach my $byte (@{$self->{'RAW_DATA'}}) {
|
|
2
|
|
|
|
|
6
|
|
290
|
6
|
100
|
|
|
|
25
|
if ($offset % $row_length == 0) {
|
291
|
3
|
100
|
|
|
|
9
|
if ($offset != 0) {
|
292
|
1
|
|
|
|
|
5
|
$line =~ s/, $//;
|
293
|
1
|
|
|
|
|
2
|
${$data_ref} .= "${line}\n";
|
|
1
|
|
|
|
|
4
|
|
294
|
|
|
|
|
|
|
}
|
295
|
3
|
|
|
|
|
5
|
$line = ' ' x 16 . '.byte ';
|
296
|
|
|
|
|
|
|
}
|
297
|
6
|
|
|
|
|
12
|
my $byte_value = sprintf "\$%02x, ", $byte;
|
298
|
6
|
|
|
|
|
7
|
$line .= $byte_value;
|
299
|
6
|
|
|
|
|
12
|
$offset++;
|
300
|
|
|
|
|
|
|
}
|
301
|
2
|
50
|
|
|
|
10
|
${$data_ref} .= "${line}\n" if $line =~ m/, $/i;
|
|
2
|
|
|
|
|
6
|
|
302
|
2
|
|
|
|
|
3
|
${$data_ref} =~ s/, $//;
|
|
2
|
|
|
|
|
13
|
|
303
|
|
|
|
|
|
|
}
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub _add_raw_data_to_scalarref {
|
306
|
14
|
|
|
14
|
|
20
|
my $self = shift;
|
307
|
14
|
|
|
|
|
37
|
my $params = {@_};
|
308
|
14
|
|
|
|
|
22
|
my $data_ref = $params->{'RAW_DATA'}; # scalar value with the whole RAW contents
|
309
|
14
|
|
|
|
|
22
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
310
|
14
|
|
|
|
|
17
|
foreach my $byte (@{$self->{'RAW_DATA'}}) {
|
|
14
|
|
|
|
|
34
|
|
311
|
79
|
|
|
|
|
108
|
my $raw_byte = chr $byte;
|
312
|
79
|
|
|
|
|
85
|
${$data_ref} .= $raw_byte;
|
|
79
|
|
|
|
|
156
|
|
313
|
|
|
|
|
|
|
}
|
314
|
|
|
|
|
|
|
}
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub _compose_loading_address_to_scalarref {
|
317
|
2
|
|
|
2
|
|
3
|
my $self = shift;
|
318
|
2
|
|
|
|
|
6
|
my $params = {@_};
|
319
|
2
|
|
|
|
|
4
|
my $data_ref = $params->{'RAW_DATA'}; # scalar value with the whole RAW contents
|
320
|
2
|
|
|
|
|
3
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
321
|
2
|
|
|
|
|
9
|
my $loading_address = sprintf "%04x", hex $self->{'LOADING_ADDRESS'};
|
322
|
2
|
|
|
|
|
3
|
${$data_ref} .= ' ' x 16;
|
|
2
|
|
|
|
|
6
|
|
323
|
2
|
|
|
|
|
3
|
${$data_ref} .= sprintf "*= \$%04x\n", $loading_address;
|
|
2
|
|
|
|
|
10
|
|
324
|
|
|
|
|
|
|
}
|
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub _add_loading_address_to_scalarref {
|
327
|
9
|
|
|
9
|
|
14
|
my $self = shift;
|
328
|
9
|
|
|
|
|
23
|
my $params = {@_};
|
329
|
9
|
|
|
|
|
18
|
my $data_ref = $params->{'RAW_DATA'}; # scalar value with the whole RAW contents
|
330
|
9
|
|
|
|
|
12
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
331
|
9
|
|
|
|
|
29
|
my $loading_address = sprintf "%04x", $self->{'LOADING_ADDRESS'};
|
332
|
9
|
|
|
|
|
52
|
my ($addr_hi, $addr_lo) = ( $loading_address =~ m/([0-9a-f]{2})/ig );
|
333
|
9
|
|
|
|
|
14
|
${$data_ref} .= chr (hex $addr_lo);
|
|
9
|
|
|
|
|
24
|
|
334
|
9
|
|
|
|
|
10
|
${$data_ref} .= chr (hex $addr_hi);
|
|
9
|
|
|
|
|
31
|
|
335
|
|
|
|
|
|
|
}
|
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=head2 change_loading_address
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
You can modify original file loading address by performing the following operation:
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
$prg->change_loading_address('LOADING_ADDRESS' => 0x6400);
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=cut
|
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
sub change_loading_address {
|
346
|
4
|
|
|
4
|
1
|
9
|
my $self = shift;
|
347
|
4
|
|
|
|
|
13
|
my $params = {@_};
|
348
|
4
|
|
|
|
|
8
|
my $loading_address = $params->{'LOADING_ADDRESS'}; # new loading address
|
349
|
4
|
|
|
|
|
9
|
my $verbose = $self->{'VERBOSE'}; # display diagnostic messages
|
350
|
|
|
|
|
|
|
# Verify if provided loading address is correct:
|
351
|
4
|
100
|
|
|
|
14
|
unless (defined $loading_address) {
|
352
|
1
|
|
|
|
|
6
|
$self->_verbose_message('MESSAGE' => "an undefined loading address has been provided to the method that was supposed to change its value", 'ERROR' => 1);
|
353
|
|
|
|
|
|
|
}
|
354
|
|
|
|
|
|
|
# Update loading address if correct value provided:
|
355
|
3
|
|
|
|
|
19
|
$self->_get_loading_address_from_scalar('LOADING_ADDRESS' => $loading_address, 'VERBOSE' => $verbose);
|
356
|
2
|
50
|
|
|
|
10
|
$self->_verbose_message('MESSAGE' => "File loading address has been succesfully updated", 'ERROR' => 0) if $verbose;
|
357
|
|
|
|
|
|
|
}
|
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=head2 set_data
|
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
You can update raw program data and its loading address by performing the following operation:
|
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
$prg->set_data('RAW_DATA' => \$data, 'LOADING_ADDRESS' => 0x1000);
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
You can update raw program data without modifying its loading address by performing the following operation:
|
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
$prg->set_data('RAW_DATA' => \$data);
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut
|
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub set_data {
|
372
|
5
|
|
|
5
|
1
|
176
|
my ($self, %params) = @_;
|
373
|
|
|
|
|
|
|
|
374
|
5
|
|
|
|
|
17
|
$self->_get_raw_contents_from_scalarref(%params);
|
375
|
4
|
100
|
|
|
|
20
|
$self->change_loading_address(%params) if exists $params{LOADING_ADDRESS};
|
376
|
|
|
|
|
|
|
|
377
|
2
|
|
|
|
|
6
|
return;
|
378
|
|
|
|
|
|
|
}
|
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=head2 set_file_data
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
You can replace original program data assuming that its loading address is included within the first two bytes of provided file data by performing the following operation:
|
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
$prg->set_file_data('FILE_DATA' => \$file_data);
|
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=cut
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub set_file_data {
|
389
|
4
|
|
|
4
|
1
|
103
|
my ($self, %params) = @_;
|
390
|
|
|
|
|
|
|
|
391
|
4
|
|
|
|
|
7
|
my $file_data = $params{FILE_DATA};
|
392
|
4
|
|
|
|
|
6
|
my $verbose = $params{VERBOSE};
|
393
|
|
|
|
|
|
|
|
394
|
4
|
|
|
|
|
26
|
my $fh = new IO::Scalar $file_data;
|
395
|
4
|
|
|
|
|
284
|
$self->_read_file(FILEHANDLE => $fh, VERBOSE => $verbose);
|
396
|
2
|
|
|
|
|
8
|
$fh->close;
|
397
|
|
|
|
|
|
|
|
398
|
2
|
|
|
|
|
16
|
return;
|
399
|
|
|
|
|
|
|
}
|
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=head2 write_file
|
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
There is a command allowing you to save the whole contents into a disk file:
|
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
$prg->write_file('FILE' => $file, 'OVERWRITE' => 1);
|
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
Note that when you specify any value evaluating to true for 'OVERWRITE' parameter, any existing file will be replaced (overwriting is disabled by default).
|
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=cut
|
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub write_file {
|
412
|
0
|
|
|
0
|
1
|
0
|
my $self = shift;
|
413
|
0
|
|
|
|
|
0
|
my $params = {@_};
|
414
|
0
|
|
|
|
|
0
|
my $file = $params->{'FILE'}; # write data to file
|
415
|
0
|
|
|
|
|
0
|
my $overwrite = $params->{'OVERWRITE'}; # a boolean indicating if any existing file should be overwritten (no files will be overwritten by default)
|
416
|
0
|
|
|
|
|
0
|
my $verbose = $self->{'VERBOSE'}; # display diagnostic messages
|
417
|
0
|
|
|
|
|
0
|
$self->{'TARGET_FILENAME'} = $file;
|
418
|
|
|
|
|
|
|
# Write data to file:
|
419
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Opening file \"${file}\" for writing", 'ERROR' => 0) if $verbose;
|
420
|
|
|
|
|
|
|
# Verify if file exists:
|
421
|
0
|
0
|
|
|
|
0
|
if (-e $file) {
|
422
|
0
|
0
|
|
|
|
0
|
unless ($overwrite) {
|
423
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "file \"${file}\" already exists", 'ERROR' => 1);
|
424
|
|
|
|
|
|
|
}
|
425
|
|
|
|
|
|
|
else {
|
426
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "File exists (overwriting the existing content)", 'ERROR' => 0) if $verbose;
|
427
|
|
|
|
|
|
|
}
|
428
|
|
|
|
|
|
|
}
|
429
|
0
|
0
|
|
|
|
0
|
open my $fh, '>', $file or $self->_verbose_message('MESSAGE' => "could not open filehandle for \"${file}\" file", 'ERROR' => 1);
|
430
|
0
|
|
|
|
|
0
|
binmode $fh, ':bytes';
|
431
|
0
|
|
|
|
|
0
|
$self->_write_loading_address_to_file('FILEHANDLE' => $fh, 'VERBOSE' => $verbose);
|
432
|
0
|
|
|
|
|
0
|
$self->_write_raw_contents_to_file('FILEHANDLE' => $fh, 'VERBOSE' => $verbose);
|
433
|
0
|
0
|
|
|
|
0
|
close $fh or $self->_verbose_message('MESSAGE' => "could not close opened filehandle for \"${file}\" file", 'ERROR' => 1);
|
434
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Closing file \"${file}\" upon successful write", 'ERROR' => 0) if $verbose;
|
435
|
|
|
|
|
|
|
}
|
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub _write_raw_contents_to_file {
|
438
|
0
|
|
|
0
|
|
0
|
my $self = shift;
|
439
|
0
|
|
|
|
|
0
|
my $params = {@_};
|
440
|
0
|
|
|
|
|
0
|
my $fh = $params->{'FILEHANDLE'}; # already opened filehandle
|
441
|
0
|
|
|
|
|
0
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
442
|
0
|
|
|
|
|
0
|
my $file = $self->{'TARGET_FILENAME'}; # filename associated with "$fh" filehandle
|
443
|
0
|
|
|
|
|
0
|
my ($bytes_count, $byte) = (0);
|
444
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Writing raw file contents into an opened filehandle", 'ERROR' => 0) if $verbose;
|
445
|
0
|
|
|
|
|
0
|
foreach my $byte (@{$self->{'RAW_DATA'}}) {
|
|
0
|
|
|
|
|
0
|
|
446
|
0
|
|
|
|
|
0
|
my $bytes_written = syswrite $fh, chr (hex $byte), 1;
|
447
|
0
|
0
|
|
|
|
0
|
if ($bytes_written != 1) {
|
448
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "unexpected difficulties writing raw file contents to \"${file}\" filehandle at offset ${bytes_count} ($!)", 'ERROR' => 1);
|
449
|
|
|
|
|
|
|
}
|
450
|
0
|
|
|
|
|
0
|
$bytes_count++;
|
451
|
|
|
|
|
|
|
}
|
452
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Written ${bytes_count} bytes of the raw file contents", 'ERROR' => 0) if $verbose;
|
453
|
|
|
|
|
|
|
}
|
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
sub _write_loading_address_to_file {
|
456
|
0
|
|
|
0
|
|
0
|
my $self = shift;
|
457
|
0
|
|
|
|
|
0
|
my $params = {@_};
|
458
|
0
|
|
|
|
|
0
|
my $fh = $params->{'FILEHANDLE'}; # already opened filehandle
|
459
|
0
|
|
|
|
|
0
|
my $verbose = $params->{'VERBOSE'}; # display diagnostic messages
|
460
|
0
|
|
|
|
|
0
|
my $file = $self->{'TARGET_FILENAME'}; # filename associated with "$fh" filehandle
|
461
|
0
|
|
|
|
|
0
|
my $loading_address = sprintf "%04x", $self->{'LOADING_ADDRESS'};
|
462
|
0
|
|
|
|
|
0
|
my ($addr_hi, $addr_lo) = ( $loading_address =~ m/([0-9a-f]{2})/ig );
|
463
|
0
|
|
|
|
|
0
|
my $bytes_count;
|
464
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Writing loading address into an opened filehandle", 'ERROR' => 0) if $verbose;
|
465
|
0
|
|
|
|
|
0
|
$bytes_count = syswrite $fh, chr (hex $addr_lo), 1;
|
466
|
0
|
0
|
|
|
|
0
|
if ($bytes_count != 1) {
|
467
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "unexpected difficulties writing loading address to \"${file}\" filehandle ($!)", 'ERROR' => 1);
|
468
|
|
|
|
|
|
|
}
|
469
|
0
|
|
|
|
|
0
|
$bytes_count = syswrite $fh, chr (hex $addr_hi), 1;
|
470
|
0
|
0
|
|
|
|
0
|
if ($bytes_count != 1) {
|
471
|
0
|
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "unexpected difficulties writing loading address to \"${file}\" filehandle ($!)", 'ERROR' => 1);
|
472
|
|
|
|
|
|
|
}
|
473
|
0
|
|
|
|
|
0
|
my $loading_address_readable = uc sprintf "\$%04x", $self->{'LOADING_ADDRESS'};
|
474
|
0
|
0
|
|
|
|
0
|
$self->_verbose_message('MESSAGE' => "Written the following file loading address: ${loading_address_readable}", 'ERROR' => 0) if $verbose;
|
475
|
|
|
|
|
|
|
}
|
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
sub _verbose_message {
|
478
|
5
|
|
|
5
|
|
9
|
my $self = shift;
|
479
|
5
|
|
|
|
|
13
|
my $params = {@_};
|
480
|
5
|
|
|
|
|
10
|
my $message = $params->{'MESSAGE'};
|
481
|
5
|
|
|
|
|
16
|
my $error = $params->{'ERROR'};
|
482
|
5
|
|
|
|
|
17
|
my ($package, $line, $subroutine) = (caller(1))[0,2,3];
|
483
|
5
|
50
|
|
|
|
234
|
($package, $line, $subroutine) = (caller(0))[0,2,3] if $package eq 'main';
|
484
|
5
|
50
|
|
|
|
12
|
if ($error) {
|
485
|
5
|
|
|
|
|
76
|
croak "[${package}][ERROR] ${subroutine} subroutine error at line ${line}: ${message}";
|
486
|
|
|
|
|
|
|
}
|
487
|
|
|
|
|
|
|
else {
|
488
|
0
|
|
|
|
|
|
print "[${package}][INFO] ${message}\n";
|
489
|
|
|
|
|
|
|
}
|
490
|
|
|
|
|
|
|
}
|
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head1 EXAMPLES
|
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
Retrieving raw data as an assembly formatted source code can be expressed using the following few lines of Perl code:
|
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
use D64::File::PRG;
|
497
|
|
|
|
|
|
|
my $data = join ('', map {chr} (1,2,3,4,5));
|
498
|
|
|
|
|
|
|
my $prg = D64::File::PRG->new('RAW_DATA' => \$data, 'LOADING_ADDRESS' => 0x0801);
|
499
|
|
|
|
|
|
|
my $src = $prg->get_data('FORMAT' => 'ASM', 'ROW_LENGTH' => 4);
|
500
|
|
|
|
|
|
|
print $src;
|
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
When executed, it prints out the source code that is ready for compilation:
|
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
;---------------------------------------
|
505
|
|
|
|
|
|
|
*= $0801
|
506
|
|
|
|
|
|
|
;---------------------------------------
|
507
|
|
|
|
|
|
|
.byte $01, $02, $03, $04
|
508
|
|
|
|
|
|
|
.byte $05
|
509
|
|
|
|
|
|
|
;---------------------------------------
|
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=head1 BUGS
|
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
There are no known bugs at the moment. Please report any bugs or feature requests.
|
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
=head1 EXPORT
|
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
None. No method is exported into the caller's namespace either by default or explicitly.
|
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=head1 SEE ALSO
|
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
I am working on the set of modules providing an easy way to access and manipulate the contents of D64 disk images and T64 tape images. D64::File::PRG is the first module of this set, as it provides operations necessary for handling individual C64's PRG files, which are the smallest building blocks for those images. Upon completion I am going to successively upload all my new modules into the CPAN.
|
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head1 AUTHOR
|
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
Pawel Krol, Epawelkrol@cpan.orgE.
|
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=head1 VERSION
|
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
Version 0.03 (2013-01-19)
|
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
Copyright (C) 2010, 2013 by Pawel Krol.
|
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
This library is free open source software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.
|
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
PLEASE NOTE THAT IT COMES WITHOUT A WARRANTY OF ANY KIND!
|
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=cut
|
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
1;
|