1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
#!/usr/bin/perl
use bytes;
sub genpad($$) {
my($left, $final) = @_;
my $o = ($final ? "\x01" : "\x00") . ("\x00" x $$left);
$$left = 252; # Bytes left in block minus end marker
return $o;
}
sub bacstmt($$$) {
my($line, $left, $data) = @_;
my $l = length($data) + 4;
my $d = pack("Cv", $l, $line) . $data . "\x0d";
if ($l > $$left) {
$d = genpad($left,0).$d;
}
$$left -= $l;
return $pad.$d;
}
sub makebac($$$) {
my($data, $addr, $entrypt) = @_;
# <bacldr.asm code>
my $bld1 = "\x2a\x1c\xfe\x11";
# 16-bit offset from BOFA to first data line between $bld1 and $bld2
my $bld2 = "\x19\x11";
# 16-bit load address between $bld2 and $bld3
my $bld3 = "\x06\x00\x3e\xf8\x86\xd2";
# 16-bit entr point between $bld3 and $bld4
my $bld4 = "\x0e\x06\x09\x4f\xed\xb0\x23\x23\x18\xf0";
# 0x00C9 is the address for END in all ABC80 BASIC interpreters
$entrypt = 0x00c9 unless(defined($entrypt));
# +2 for the final 0xbb + CR
my $bldlen = length($bld1) + 2 + length($bld2) + 2 + length($bld3) + 2 +
length($bld4) + 2;
my $q = "\x82"; # Output (program start marker)
my $left = 251; # Bytes left in block
my $r = 0; # Last emitted line number
# Address 65054 is EOFA
# 1 Z%=CALL(PEEK(65054%)+SWAP%(PEEK(65055%)-<loader offset>)
$q .= bacstmt(++$r, \$left,
"\x83\xc1\xf1\x5a\x00\xbb\xc7\x1e\xfe\xce\x36\xc7".
"\x1f\xfe\xce\x36\xce\x34\xf5\xc7".
pack("v",$bldlen)."\xf8\xce\x3a\xb7");
my $pfxlen = length($q) - 1; # The initial 0x82 isn't stored in RAM
my $bld = $bld1 . pack("v", $pfxlen) . $bld2 . pack("v", $addr) .
$bld3 . pack("v", $entrypt) . $bld4;
my $i = 0;
my $dl = length($data);
while ($i < $dl) {
my $l = $dl - $i;
# 8 = 3 byte BAC header + 4 byte overhead + CR
$q .= genpad(\$left,0) if ($left <= 8);
$l = $left-8 if ($l > $left-8);
# String expression + address + data + return
$q .= bacstmt(++$r, \$left,
"\xcb\"" . pack("C", $l) . substr($data,$i,$l)."\xbb");
$i += $l;
$addr += $l;
}
# Terminal END statement
$q .= bacstmt(++$r, \$left, "\x86\x8a"); # END
# Loader code (string expression)
$q .= bacstmt(++$r, \$left, "\xcb\"".pack("C",length($bld)).$bld."\xbb");
$q .= genpad(\$left,1);
return $q;
}
($file, $org, $entry) = @ARGV;
$org = oct $org if ( $org =~ /^0/ );
$entry = oct $entry if ( $entry =~ /^0/ );
open(FILE, '<:raw', $file) or die "$0: $file: $!\n";
$l = read(FILE, $dd, 65536);
close(FILE);
$segs{$org} = $dd;
print makebac($dd, $org, $entry);
|