mirror of
https://github.com/AK6DN/dec-utilities-for-pdp.git
synced 2026-01-11 23:42:54 +00:00
Initial commit
This commit is contained in:
parent
f9380b6e1e
commit
e65490a767
29
License.pl
Normal file
29
License.pl
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (c) 2005 Don North
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# o Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# o Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# o Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
146
README.md
Normal file
146
README.md
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<B>obj2bin.pl</B> is a PDP-11 object file translator / linker, transforming an .obj file as output from macro11 into an absolute binary load image file (.bin) or other useful formats (.hex).
|
||||||
|
|
||||||
|
If run with no options, it prints a usage screen:
|
||||||
|
|
||||||
|
```
|
||||||
|
obj2bin.pl v2.0 by Don North (perl 5.022)
|
||||||
|
Usage: ./obj2bin.pl [options...] arguments
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
--boot M9312 boot prom
|
||||||
|
--console M9312 console/diagnostic prom
|
||||||
|
--binary binary program load image
|
||||||
|
--ascii ascii m9312 program load image
|
||||||
|
--bytes=N bytes per block on output
|
||||||
|
--nocrc inhibit output of CRC-16 in hex format
|
||||||
|
--logfile=LOGFILE logging message file
|
||||||
|
--outfile=OUTFILE output .hex/.txt/.bin file
|
||||||
|
OBJFILE... macro11 object .obj file(s)
|
||||||
|
Aborted due to command line errors.
|
||||||
|
```
|
||||||
|
|
||||||
|
If run with the --help option it prints a longer manual page:
|
||||||
|
|
||||||
|
```
|
||||||
|
NAME
|
||||||
|
obj2bin.pl - Convert a Macro-11 program image to PROM/load format
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
obj2bin.pl [--help] [--debug] [--verbose] [--boot] [--console] [--binary]
|
||||||
|
[--ascii] [--bytes=N] [--nocrc] [--logfile=LOGFILE] --outfile=BINFILE
|
||||||
|
OBJFILE...
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Converts a Macro-11 object file to various output formats, including M9312
|
||||||
|
boot and console PROM, straight binary records, ASCII format for M9312
|
||||||
|
console load commands, and loadable absolute binary program images (.BIN)
|
||||||
|
files.
|
||||||
|
|
||||||
|
Currently the program is limited to a single object input file that can be
|
||||||
|
output in the selected format. Multiple .psect/.asect ops are supported,
|
||||||
|
as well as all local (non-global) relocation directory entries. Multiple
|
||||||
|
object files are (not yet) supported.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
The following options are available:
|
||||||
|
|
||||||
|
--help
|
||||||
|
Output this manpage and exit the program.
|
||||||
|
|
||||||
|
--debug
|
||||||
|
Enable debug mode; print input file records as parsed.
|
||||||
|
|
||||||
|
--verbose
|
||||||
|
Verbose status; output status messages during processing.
|
||||||
|
|
||||||
|
--boot
|
||||||
|
Generate a hex PROM file image suitable for programming into an M9312
|
||||||
|
boot prom (512x4 geometry, only low half used).
|
||||||
|
|
||||||
|
--console
|
||||||
|
Generate a hex PROM file image suitable for programming into an M9312
|
||||||
|
console/diagnostic prom (1024x4 geometry).
|
||||||
|
|
||||||
|
--binary
|
||||||
|
Generate binary format load records of the program image (paper tape
|
||||||
|
format) for loading into SIMH or compatible simulators. These files
|
||||||
|
can also be copied onto XXDP filesystems to generate runnable program
|
||||||
|
images (used to write custom diaqnostics).
|
||||||
|
|
||||||
|
--ascii
|
||||||
|
Generate a a sequence of 'L addr' / 'D data' commands for downloading
|
||||||
|
a program via a terminal emulator thru the M9312 user command
|
||||||
|
interface. Suitable only for really small test programs.
|
||||||
|
|
||||||
|
Exactly ONE of --boot, --console, --binary, or --ascii must be
|
||||||
|
specified.
|
||||||
|
|
||||||
|
--bytes=N
|
||||||
|
For hex format output files, output N bytes per line (default 16).
|
||||||
|
|
||||||
|
--nocrc
|
||||||
|
For hex format output files, don't automatically stuff the computed
|
||||||
|
CRC-16 as the last word in the ROM.
|
||||||
|
|
||||||
|
--logfile=FILENAME
|
||||||
|
Generate debug output into this file.
|
||||||
|
|
||||||
|
--outfile=FILENAME
|
||||||
|
Output binary file in format selected by user option.
|
||||||
|
|
||||||
|
OBJFILE...
|
||||||
|
Input object file(s) in .obj format.
|
||||||
|
|
||||||
|
ERRORS
|
||||||
|
The following diagnostic error messages can be produced on STDERR. The
|
||||||
|
meaning should be fairly self explanatory.
|
||||||
|
|
||||||
|
"Aborted due to command line errors" -- bad option or missing file(s)
|
||||||
|
|
||||||
|
"Can't open input file '$file'" -- bad filename or unreadable file
|
||||||
|
|
||||||
|
"Error: Improper object file format (1)" -- valid record must start with
|
||||||
|
0x01
|
||||||
|
|
||||||
|
"Error: Improper object file format (2)" -- second byte must be 0x00
|
||||||
|
|
||||||
|
"Error: Improper object file format (3)" -- third byte is low byte of
|
||||||
|
record length
|
||||||
|
|
||||||
|
"Error: Improper object file format (4)" -- fourth byte is high byte of
|
||||||
|
record length
|
||||||
|
|
||||||
|
"Error: Improper object file format (5)" -- bytes five thru end-1 are data
|
||||||
|
bytes
|
||||||
|
|
||||||
|
"Error: Improper object file format (6)" -- last byte is checksum
|
||||||
|
|
||||||
|
"Error: Bad checksum exp=0x%02X rcv=0x%02X" -- compare rcv'ed checksum vs
|
||||||
|
exp'ed checksum
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
Some examples of common usage:
|
||||||
|
|
||||||
|
obj2bin.pl --help
|
||||||
|
|
||||||
|
obj2bin.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj
|
||||||
|
|
||||||
|
obj2bin.pl --verbose --binary --out memtest.bin memtest.obj
|
||||||
|
|
||||||
|
AUTHOR
|
||||||
|
Don North - donorth <ak6dn _at_ mindspring _dot_ com>
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
Modification history:
|
||||||
|
|
||||||
|
2005-05-05 v1.0 donorth - Initial version.
|
||||||
|
2016-01-15 v1.1 donorth - Added RLD(IR) processing, moved sub's to end.
|
||||||
|
2016-01-18 v1.2 donorth - Added GSD processing, improved debug output.
|
||||||
|
2016-01-20 v1.3 donorth - Initial support for linking multiple PSECTs.
|
||||||
|
2016-01-22 v1.4 donorth - Added objfile/outfile/logfile switches vs stdio.
|
||||||
|
2016-01-28 v1.5 donorth - Added RLD processing, especially complex.
|
||||||
|
2017-04-01 v2.0 donorth - Started to add capability to process multiple
|
||||||
|
input object files ... still a work in progress.
|
||||||
|
Renamed from obj2hex.pl to obj2bin.pl
|
||||||
|
```
|
||||||
388
binchk/binchk.pl
Normal file
388
binchk/binchk.pl
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
# Copyright (c) 2005 Don North
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# o Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# o Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# o Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
require 5.008;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
hdr - Standard template for a Perl module
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
hdr
|
||||||
|
S<[--help]>
|
||||||
|
S<[--debug]>
|
||||||
|
S<[--verbose]>
|
||||||
|
S<[random arguments ...]>
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Description of the command ...
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
The following options are available:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<--help>
|
||||||
|
|
||||||
|
Output this manpage and exit the program.
|
||||||
|
|
||||||
|
=item B<--debug>
|
||||||
|
|
||||||
|
Enable debug mode.
|
||||||
|
|
||||||
|
=item B<--verbose>
|
||||||
|
|
||||||
|
Verbose status reporting (not implemented).
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 ERRORS
|
||||||
|
|
||||||
|
The following diagnostic error messages can be produced on STDERR.
|
||||||
|
The meaning should be fairly self explanatory.
|
||||||
|
|
||||||
|
C<List all the error messages here...> -- some error
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
Some examples of common usage:
|
||||||
|
|
||||||
|
hdr --help
|
||||||
|
|
||||||
|
hdr --verbose --string 'a string' --integer 5 some_other_argument
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
Related commands cross reference...
|
||||||
|
|
||||||
|
=head1 NOTES
|
||||||
|
|
||||||
|
Caveat emptor...
|
||||||
|
|
||||||
|
=head1 FILES
|
||||||
|
|
||||||
|
Any standard files used?
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Don North
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
Modification history:
|
||||||
|
|
||||||
|
2005-05-05 v0.0 donorth - Initial version.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external standard modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
use FileHandle;
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, $ENV{PERL5LIB}) if defined($ENV{PERL5LIB}); # cygwin bugfix
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v0.1d1'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help" => \$HELP,
|
||||||
|
"debug" => \$DEBUG,
|
||||||
|
"verbose" => \$VERBOSE,
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# say hello
|
||||||
|
printf STDERR "binchk.pl %s by Don North (perl %g)\n", $VERSION, $] if $VERBOSE;
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR && scalar(@ARGV) == 1) {
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
OBJFILE macro11 object .obj file
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# setup log file as a file, defaults to STDERR if not supplied
|
||||||
|
my $LOG = FileHandle->new_from_fd(fileno(STDERR),"w");
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# subroutine prototypes
|
||||||
|
|
||||||
|
sub chksum (@);
|
||||||
|
sub rad2asc (@);
|
||||||
|
sub crc (%);
|
||||||
|
sub read_rec ($);
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
my @mem = (); # real pdp11 memory data bytes
|
||||||
|
foreach my $adr (0..65535) { $mem[$adr] = 0; }
|
||||||
|
|
||||||
|
my ($minadr,$maxadr,$staadr) = ('','',1);
|
||||||
|
|
||||||
|
# open the input .bin file, die if error
|
||||||
|
my $OBJ = FileHandle->new("< ".$ARGV[0]);
|
||||||
|
die "Can't open input binary file '$ARGV[0]'\n" unless defined $OBJ;
|
||||||
|
|
||||||
|
while (my @rec = &read_rec($OBJ)) {
|
||||||
|
# first two bytes are the load address
|
||||||
|
my $adr = shift(@rec); $adr += shift(@rec)<<8;
|
||||||
|
printf STDERR "record at address %06o\n", $adr if $DEBUG;
|
||||||
|
if (@rec == 0) { $staadr = $adr; next; }
|
||||||
|
# rest of the bytes are data (if present)
|
||||||
|
$minadr = $adr if $minadr eq '' || $adr < $minadr;
|
||||||
|
while (@rec) { $mem[$adr++] = shift(@rec); }
|
||||||
|
$maxadr = $adr if $maxadr eq '' || $adr > $maxadr;
|
||||||
|
}
|
||||||
|
$OBJ->close;
|
||||||
|
|
||||||
|
# print some info
|
||||||
|
printf "address = (%06o,%06o) start = %06o\n", $minadr, $maxadr, $staadr;
|
||||||
|
|
||||||
|
if ($VERBOSE) {
|
||||||
|
# print the whole program image
|
||||||
|
for (my $adr = ($minadr&~0xF); $adr <= ($maxadr|0xF); ) {
|
||||||
|
printf " %06o :", $adr;
|
||||||
|
for (my $next = $adr+16; $adr < $next; $adr += 2) {
|
||||||
|
if ($adr < $minadr-1 || $adr > $maxadr+1) {
|
||||||
|
printf " ......";
|
||||||
|
} else {
|
||||||
|
printf " %06o", ($mem[$adr+1]<<8)|$mem[$adr+0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub fix ($) { my ($c) = @_; $c < 0x20 || $c > 0x7E ? '.' : chr($c); }
|
||||||
|
printf " \"%s\"\n", join('',map(&fix($mem[$adr-16+$_]),(0..15)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# all done
|
||||||
|
$LOG->close;
|
||||||
|
exit;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# compute checksum (twos complement of the sum of bytes)
|
||||||
|
|
||||||
|
sub chksum (@) {
|
||||||
|
|
||||||
|
my $sum = 0;
|
||||||
|
|
||||||
|
map($sum += $_, @_);
|
||||||
|
|
||||||
|
return (-$sum) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# RAD50 to ASCII decode
|
||||||
|
|
||||||
|
sub rad2asc (@) {
|
||||||
|
|
||||||
|
my @str = split(//, ' ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789'); # RAD50 character subset
|
||||||
|
|
||||||
|
my $ascii = "";
|
||||||
|
foreach my $rad50 (@_) {
|
||||||
|
$ascii .= $str[int($rad50/1600)%40] . $str[int($rad50/40)%40] . $str[$rad50%40];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ascii;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# crc computation routine
|
||||||
|
|
||||||
|
sub crc (%) {
|
||||||
|
|
||||||
|
# pass all args by name
|
||||||
|
my %args = @_;
|
||||||
|
|
||||||
|
# all the crcs we know how to compute
|
||||||
|
my %crcdat = ( 'CRC-16' => [ 0xA001, 2, 0x0000, 0x0000 ],
|
||||||
|
'CRC-32' => [ 0xEDB88320, 4, 0xFFFFFFFF, 0xFFFFFFFF ] );
|
||||||
|
|
||||||
|
# run next byte thru crc computation, return updated crc
|
||||||
|
return $args{-table}[($args{-crc}^$args{-byte}) & 0xFF]^($args{-crc}>>8) if exists($args{-byte});
|
||||||
|
|
||||||
|
# return initial crc value
|
||||||
|
return $crcdat{$args{-name}}->[2] if exists($args{-init});
|
||||||
|
|
||||||
|
# return final crc value xored with xorout
|
||||||
|
return $args{-crc} ^ $crcdat{$args{-name}}->[3] if exists($args{-last});
|
||||||
|
|
||||||
|
# compute the crc lookup table, return a pointer to it
|
||||||
|
if (exists($args{-new})) {
|
||||||
|
my $crctab = [];
|
||||||
|
my $poly = $crcdat{$args{-name}}->[0];
|
||||||
|
foreach my $byte (0..255) {
|
||||||
|
my $data = $byte;
|
||||||
|
foreach (1..8) { $data = ($data>>1) ^ ($data&1 ? $poly : 0); }
|
||||||
|
$$crctab[$byte] = $data;
|
||||||
|
}
|
||||||
|
return $crctab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# read a record from the binary file
|
||||||
|
|
||||||
|
sub read_rec ($) {
|
||||||
|
|
||||||
|
my ($fh) = @_;
|
||||||
|
|
||||||
|
my ($buf, $cnt, $len, $err) = (0,0,0,0);
|
||||||
|
my @pre = ();
|
||||||
|
my @dat = ();
|
||||||
|
my @suf = ();
|
||||||
|
|
||||||
|
# Binary file format consists of blocks, optionally preceded, separated, and
|
||||||
|
# followed by zeroes. Each block consists of:
|
||||||
|
#
|
||||||
|
# 001 ---
|
||||||
|
# 000 |
|
||||||
|
# lo(length) |
|
||||||
|
# hi(length) |
|
||||||
|
# lo(address) > 'length' bytes
|
||||||
|
# hi(address) |
|
||||||
|
# databyte1 |
|
||||||
|
# : |
|
||||||
|
# databyteN ---
|
||||||
|
# checksum
|
||||||
|
#
|
||||||
|
|
||||||
|
# skip over strings of 0x00; exit OK if hit EOF
|
||||||
|
do { return () unless $cnt = read($fh, $buf, 1); } while (ord($buf) == 0);
|
||||||
|
|
||||||
|
# valid record starts with (1)
|
||||||
|
$err = 1 unless $cnt == 1 && ord($buf) == 1;
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# second byte must be (0)
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 2 unless $cnt == 1 && ord($buf) == 0;
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# third byte is low byte of record length
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 3 unless $cnt == 1;
|
||||||
|
$len = ord($buf);
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# fourth byte is high byte of record length
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 4 unless $cnt == 1;
|
||||||
|
$len += ord($buf)<<8;
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# bytes five thru end-1 are two address bytes plus data bytes
|
||||||
|
$cnt = read($fh, $buf, $len-4);
|
||||||
|
$err = 5 unless $cnt == $len-4 && $len >= 4;
|
||||||
|
@dat = unpack("C*", $buf);
|
||||||
|
|
||||||
|
# last byte is checksum
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 6 unless $cnt == 1;
|
||||||
|
my $rcv = ord($buf);
|
||||||
|
push(@suf, ord($buf));
|
||||||
|
|
||||||
|
# output the record if debugging
|
||||||
|
if ($DEBUG) {
|
||||||
|
my $fmt = "%03o";
|
||||||
|
my $n = 16;
|
||||||
|
my $pre = sprintf("RECORD: [%s] ",join(" ",map(sprintf($fmt,$_),@pre)));
|
||||||
|
printf $LOG "\n\n%s", $pre;
|
||||||
|
my $k = length($pre);
|
||||||
|
my @tmp = @dat;
|
||||||
|
while (@tmp > $n) {
|
||||||
|
printf $LOG "%s\n%*s", join(" ",map(sprintf($fmt,$_),splice(@tmp,0,$n))), $k, '';
|
||||||
|
}
|
||||||
|
printf $LOG "%s", join(" ",map(sprintf($fmt,$_),@tmp)) if @tmp;
|
||||||
|
printf $LOG " [%s]\n\n", join(" ",map(sprintf($fmt,$_),@suf));
|
||||||
|
}
|
||||||
|
|
||||||
|
# check we have a well formatted record
|
||||||
|
die sprintf("Error: invalid binary file record format (%d)", $err) if $err;
|
||||||
|
|
||||||
|
# compare rcv'ed checksum vs exp'ed checksum
|
||||||
|
my $exp = &chksum(0x01, $len>>0, $len>>8, @dat);
|
||||||
|
die sprintf("Error: Bad checksum exp=0x%02X rcv=0x%02X", $exp, $rcv) unless $exp == $rcv;
|
||||||
|
|
||||||
|
# all is well, return the record
|
||||||
|
return @dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# the end
|
||||||
332
config11/config11.pl
Normal file
332
config11/config11.pl
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
# Copyright (c) 2005 Don North
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# o Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# o Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# o Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
require 5.008;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
config11.pl - Configure PDP-11 I/O Space Addresses
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
config11.pl
|
||||||
|
S<[--help]>
|
||||||
|
S<[--debug]>
|
||||||
|
S<[--verbose]>
|
||||||
|
<INPFILE
|
||||||
|
>OUTFILE
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Configures the CSR and vector addresses for a set of
|
||||||
|
PDP-11 peripherals using the 'standard' autoconfigure
|
||||||
|
algorithm used by DEC software for device discovery.
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
The following options are available:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<--help>
|
||||||
|
|
||||||
|
Output this manpage and exit the program.
|
||||||
|
|
||||||
|
=item B<--debug>
|
||||||
|
|
||||||
|
Enable debug mode; print input file records as parsed.
|
||||||
|
|
||||||
|
=item B<--verbose>
|
||||||
|
|
||||||
|
Verbose status; output status messages during processing.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 ERRORS
|
||||||
|
|
||||||
|
The following diagnostic error messages can be produced on STDERR.
|
||||||
|
The meaning should be fairly self explanatory.
|
||||||
|
|
||||||
|
C<Aborted due to command line errors> -- bad option or missing file(s)
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
Some examples of common usage:
|
||||||
|
|
||||||
|
config11.pl --help
|
||||||
|
|
||||||
|
config11.pl --verbose < input.txt > output.txt
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Don North - donorth <ak6dn _at_ mindspring _dot_ com>
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
Modification history:
|
||||||
|
|
||||||
|
2005-09-21 v1.0 donorth - Initial version.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external standard modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, $ENV{PERL5LIB}) if defined($ENV{PERL5LIB}); # cygwin bugfix
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v1.0'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help" => \$HELP,
|
||||||
|
"debug" => \$DEBUG,
|
||||||
|
"verbose" => \$VERBOSE,
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# say hello
|
||||||
|
printf STDERR "config11.pl %s by Don North (perl %g)\n", $VERSION, $] if $VERBOSE;
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR && scalar(@ARGV) == 0) {
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
< INPFILE input device list
|
||||||
|
> OUTFILE output device assignment list
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
my %vec = ( # name => [ rank, numvec [,basevec] ]
|
||||||
|
DC11 => [ 1, 2 ],
|
||||||
|
TU58 => [ 1, 2 ],
|
||||||
|
KL11 => [ 2, 2 ], # (1)
|
||||||
|
DL11A => [ 2, 2 ], # (1)
|
||||||
|
DL11B => [ 2, 2 ], # (1)
|
||||||
|
DLV11J => [ 2, 8 ], # (1)
|
||||||
|
DLV11 => [ 2, 2 ], # (1)
|
||||||
|
DLV11F => [ 2, 2 ], # (1)
|
||||||
|
DP11 => [ 3, 2 ],
|
||||||
|
DM11A => [ 4, 2 ],
|
||||||
|
DN11 => [ 5, 1 ],
|
||||||
|
DM11BA => [ 6, 1 ],
|
||||||
|
DM11BB => [ 6, 1 ],
|
||||||
|
DH11_modem => [ 7, 1 ],
|
||||||
|
DR11A => [ 8, 2 ],
|
||||||
|
DRV11B => [ 8, 2 ],
|
||||||
|
DR11C => [ 9, 2 ],
|
||||||
|
DRV11 => [ 9, 2 ],
|
||||||
|
PA611 => [ 10, 4 ],
|
||||||
|
LPD11 => [ 11, 2 ],
|
||||||
|
DT07 => [ 12, 2 ],
|
||||||
|
DX11 => [ 13, 2 ],
|
||||||
|
DL11C => [ 14, 2 ],
|
||||||
|
DL11D => [ 14, 2 ],
|
||||||
|
DL11E => [ 14, 2 ],
|
||||||
|
DL11F => [ 14, 2 ],
|
||||||
|
DLV11C => [ 14, 2 ],
|
||||||
|
DLV11D => [ 14, 2 ],
|
||||||
|
DLV11E => [ 14, 2 ],
|
||||||
|
DLV11F => [ 14, 2 ],
|
||||||
|
DJ11 => [ 15, 2 ],
|
||||||
|
DH11 => [ 16, 2 ],
|
||||||
|
VT40 => [ 17, 4 ],
|
||||||
|
VSV11 => [ 17, 4 ],
|
||||||
|
LPS11 => [ 18, 6 ],
|
||||||
|
DQ11 => [ 19, 2 ],
|
||||||
|
KW11W => [ 20, 2 ],
|
||||||
|
KWV11 => [ 20, 2 ],
|
||||||
|
DU11 => [ 21, 2 ],
|
||||||
|
DUV11 => [ 21, 2 ],
|
||||||
|
DUP11 => [ 22, 2 ],
|
||||||
|
DV11_modem => [ 23, 3 ],
|
||||||
|
LK11A => [ 24, 2 ],
|
||||||
|
DWUN => [ 25, 2 ],
|
||||||
|
DMC11 => [ 26, 2 ],
|
||||||
|
DMR11 => [ 26, 2 ],
|
||||||
|
DZ11 => [ 27, 2 ],
|
||||||
|
DZS11 => [ 27, 2 ],
|
||||||
|
DZV11 => [ 27, 2 ],
|
||||||
|
DZ32 => [ 27, 2 ],
|
||||||
|
KMC11 => [ 28, 2 ],
|
||||||
|
LPP11 => [ 29, 2 ],
|
||||||
|
VMV21 => [ 30, 2 ],
|
||||||
|
VMV31 => [ 31, 2 ],
|
||||||
|
VTV01 => [ 32, 2 ],
|
||||||
|
DWR70 => [ 33, 2 ],
|
||||||
|
RL11 => [ 34, 1 ], # (2)
|
||||||
|
RLV11 => [ 34, 1 ], # (2)
|
||||||
|
TS11 => [ 35, 1 ], # (2)
|
||||||
|
TU80 => [ 35, 1 ], # (2)
|
||||||
|
LPA11K => [ 36, 2 ],
|
||||||
|
IP11 => [ 37, 1 ], # (2)
|
||||||
|
IP300 => [ 37, 1 ], # (2)
|
||||||
|
KW11C => [ 38, 2 ],
|
||||||
|
RX11 => [ 39, 1 ], # (2)
|
||||||
|
RX211 => [ 39, 1 ], # (2)
|
||||||
|
RXV11 => [ 39, 1 ], # (2)
|
||||||
|
RXV21 => [ 39, 1 ], # (2)
|
||||||
|
DR11W => [ 40, 1 ],
|
||||||
|
DR11B => [ 41, 1 ], # (2)
|
||||||
|
DMP11 => [ 42, 2 ],
|
||||||
|
DPV11 => [ 43, 2 ],
|
||||||
|
ML11 => [ 44, 1 ], # (3)
|
||||||
|
ISB11 => [ 45, 2 ],
|
||||||
|
DMV11 => [ 46, 2 ],
|
||||||
|
DEUNA => [ 47, 1, 0120 ], # (2)
|
||||||
|
UDA50 => [ 48, 1, 0154 ], # (2)
|
||||||
|
DMF32 => [ 49, 8 ],
|
||||||
|
KMS11 => [ 50, 3 ],
|
||||||
|
PCL11B => [ 51, 2 ],
|
||||||
|
VS100 => [ 52, 1 ],
|
||||||
|
TU81 => [ 53, 1 ], # (2)
|
||||||
|
KMV11 => [ 54, 2 ],
|
||||||
|
Reserved => [ 55, 2 ],
|
||||||
|
IEX => [ 56, 2 ],
|
||||||
|
DHV11 => [ 57, 2 ],
|
||||||
|
DMZ32 => [ 58, 6 ],
|
||||||
|
CP132 => [ 59, 6 ],
|
||||||
|
# (1) A KL11 or DL11 used as a console, has a fixed vector.
|
||||||
|
# (2) The first device of this type has a fixed vector. Any extra devices have a floating vector.
|
||||||
|
# (3) ML11 is a Massbus device which can connect to a UNIBUS via a bus adapter.
|
||||||
|
);
|
||||||
|
|
||||||
|
my %csr = ( # name => [ rank, numcsr [,basecsr] ]
|
||||||
|
DJ11 => [ 1, 4 ],
|
||||||
|
DH11 => [ 2, 8 ],
|
||||||
|
DQ11 => [ 3, 4 ],
|
||||||
|
DU11 => [ 4, 4 ],
|
||||||
|
DUV11 => [ 4, 4 ],
|
||||||
|
DUP11 => [ 5, 4 ],
|
||||||
|
LK11A => [ 6, 4 ],
|
||||||
|
DMC11 => [ 7, 4 ],
|
||||||
|
DMR11 => [ 7, 4 ],
|
||||||
|
DZ11 => [ 8, 4 ],
|
||||||
|
DZV11 => [ 8, 4 ],
|
||||||
|
DZS11 => [ 8, 4 ],
|
||||||
|
DZ32 => [ 8, 4 ],
|
||||||
|
KMC11 => [ 9, 4 ],
|
||||||
|
LPP11 => [ 10, 4 ],
|
||||||
|
VMV21 => [ 11, 4 ],
|
||||||
|
VMV31 => [ 12, 8 ],
|
||||||
|
DWR70 => [ 13, 4 ],
|
||||||
|
RL11 => [ 14, 4, 0774400 ],
|
||||||
|
RLV11 => [ 14, 4, 0774400 ],
|
||||||
|
LPA11K => [ 15, 8, 0770460 ],
|
||||||
|
KW11C => [ 16, 4 ],
|
||||||
|
rsvd => [ 17, 4 ],
|
||||||
|
RX11 => [ 18, 4, 0777170 ],
|
||||||
|
RX211 => [ 18, 4, 0777170 ],
|
||||||
|
RXV11 => [ 18, 4, 0777170 ],
|
||||||
|
RXV21 => [ 18, 4, 0777170 ],
|
||||||
|
DR11W => [ 19, 4 ],
|
||||||
|
DR11B => [ 20, 4, 0772410 ],
|
||||||
|
DMP11 => [ 21, 4 ],
|
||||||
|
DPV11 => [ 22, 4 ],
|
||||||
|
ISB11 => [ 23, 4 ],
|
||||||
|
DMV11 => [ 24, 8 ],
|
||||||
|
DEUNA => [ 25, 4, 0774440 ],
|
||||||
|
UDA50 => [ 26, 2, 0772150 ],
|
||||||
|
DMF32 => [ 27, 16 ],
|
||||||
|
KMS11 => [ 28, 6 ],
|
||||||
|
VS100 => [ 29, 8 ],
|
||||||
|
TK50 => [ 30, 2, 0774500 ],
|
||||||
|
TU81 => [ 30, 2, 0774500 ],
|
||||||
|
KMV11 => [ 31, 8 ],
|
||||||
|
DHV11 => [ 32, 8 ],
|
||||||
|
DMZ32 => [ 33, 16 ],
|
||||||
|
CP132 => [ 34, 16 ],
|
||||||
|
);
|
||||||
|
|
||||||
|
# printf ("\nRank\tName\tCtrl#\t CSR\n\n");
|
||||||
|
# csr = 0760010;
|
||||||
|
# for (i = 0; i < RANK_LNT; i++) {
|
||||||
|
# if (numctl[i] == 0) {
|
||||||
|
# printf (" %02d\t%s\tgap\t%06o\n", i+1, namtab[i], csr); }
|
||||||
|
# else {
|
||||||
|
# if (fixtab[i])
|
||||||
|
# printf (" %02d\t%s\t 1\t%06o*\n", i+1, namtab[i], fixtab[i]);
|
||||||
|
# else {
|
||||||
|
# printf (" %02d\t%s\t 1\t%06o\n", i+1, namtab[i], csr);
|
||||||
|
# csr = (csr + modtab[i] + 1) & ~modtab[i]; }
|
||||||
|
# for (j = 1; j < numctl[i]; j++) {
|
||||||
|
# printf ("\t\t %d\t%06o\n", j + 1, csr);
|
||||||
|
# csr = (csr + modtab[i] + 1) & ~modtab[i]; }
|
||||||
|
# printf (" %\t\tgap\t%06o\n", csr);
|
||||||
|
# }
|
||||||
|
# if ((i + 1) < RANK_LNT) csr = (csr + modtab[i+1] + 1) & ~modtab[i+1];
|
||||||
|
# }
|
||||||
|
# printf ("\n\n");
|
||||||
|
# }
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
exit;
|
||||||
|
|
||||||
|
# the end
|
||||||
56
d8tape/LICENSE
Normal file
56
d8tape/LICENSE
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
This software is copyrighted as per the individual source modules.
|
||||||
|
Where no copyright is given, the following applies:
|
||||||
|
|
||||||
|
(C) Copyright 2002 by 1230599 Ontario Inc., dba PARSE Softare Devices
|
||||||
|
All rights reserved. Use subject to terms in LICENSE file.
|
||||||
|
|
||||||
|
This software may be used for non-commercial applications without restriction.
|
||||||
|
Redistribution must occur without charge, and the distribution must be intact
|
||||||
|
and include all copyright notices and LICENSE files. A charge may be made
|
||||||
|
for distribution to cover media and shipping only.
|
||||||
|
|
||||||
|
This license is incompatible with the GNU-GPL and therefore GPL source cannot be
|
||||||
|
combined with this source. Other licenses may or may not be compatible; you
|
||||||
|
assume full responsibility for license compliance.
|
||||||
|
|
||||||
|
To use this software in a commercial product, please contact:
|
||||||
|
|
||||||
|
licensing@parse.com
|
||||||
|
|
||||||
|
Licensing fees are generally a direct function of the amount of work that went
|
||||||
|
into a particular product; the advantage to you is that you get the product
|
||||||
|
immediately, for approximately the same cost as it would cost you to hire someone
|
||||||
|
to develop it, and you have the ability to evaluate it under the terms of the
|
||||||
|
non-commercial use (above).
|
||||||
|
|
||||||
|
There is no warranty with this software, expressed or implied. Neither the
|
||||||
|
author, 1230599 Ontario Inc., nor anyone connected in any way with the development
|
||||||
|
or distribution of this software may be held liable for any losses, not limited
|
||||||
|
to consequential or direct, however caused.
|
||||||
|
|
||||||
|
For any further information, please contact us at:
|
||||||
|
|
||||||
|
1230599 Ontario Inc
|
||||||
|
dba PARSE Software Devices
|
||||||
|
278 Equestrian Drive
|
||||||
|
Kanata, ON K2M 1C5
|
||||||
|
CANADA
|
||||||
|
+1 613 599 8316 (voice)
|
||||||
|
+1 877 727 7379 (toll free North America)
|
||||||
|
+1 613 599 8317 (fax)
|
||||||
|
|
||||||
|
In case this address or contact information changes, you can always get the latest
|
||||||
|
contact information from the following URL:
|
||||||
|
|
||||||
|
http://www.parse.com
|
||||||
|
|
||||||
|
PARSE Software Devices is an established research and development organization,
|
||||||
|
specializing in realtime and embedded systems architecture and software
|
||||||
|
development. We are also the publishers of the "Getting Started with QNX(R) 4"
|
||||||
|
and "Getting Started with QNX(R) Neutrino(R) 2" (Momentics(R)) books. As well,
|
||||||
|
we have a video training course available to help you get started with QNX(R)
|
||||||
|
Neutrino(R) (Momentics(R)). Please see our website for more information.
|
||||||
|
|
||||||
|
All trademarks and registered trademarks mentioned belong to their respective
|
||||||
|
owners.
|
||||||
54
d8tape/Makefile
Normal file
54
d8tape/Makefile
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#
|
||||||
|
# makefile for d8tape
|
||||||
|
#
|
||||||
|
# (C) Copyright 2001, 2003, 2007, by Robert Krten, all rights reserved.
|
||||||
|
# Please see the LICENSE file for more information.
|
||||||
|
#
|
||||||
|
# I collect PDP systems of almost all shapes and sizes; send me an
|
||||||
|
# email to "rk@parse.com" if you have one to give away, sell,
|
||||||
|
# or trade, or visit the museum at http://www.parse.com/~museum/
|
||||||
|
#
|
||||||
|
# 2001 01 07 R. Krten created
|
||||||
|
# 2007 10 25 R. Krten added flow module
|
||||||
|
#
|
||||||
|
# The "bm" utility in the "core:" target simply increments
|
||||||
|
# the version number -- you can comment out that line with
|
||||||
|
# no ill effects, or simply "ln /bin/true /usr/local/bin/bm"
|
||||||
|
# (or similar) to nullify its effects.
|
||||||
|
#
|
||||||
|
|
||||||
|
DEBUG = -g2
|
||||||
|
OBJECTS = main.o dasm.o flow.o
|
||||||
|
|
||||||
|
CFLAGS = $(DEBUG) -Wall
|
||||||
|
LDFLAGS = $(DEBUG)
|
||||||
|
|
||||||
|
Common = Makefile
|
||||||
|
|
||||||
|
d8tape: $(OBJECTS)
|
||||||
|
cc $(CFLAGS) -o d8tape $(OBJECTS) version.c $(LDFLAGS)
|
||||||
|
|
||||||
|
main.o: main.c $(Common)
|
||||||
|
|
||||||
|
install:
|
||||||
|
make
|
||||||
|
cp -v d8tape.exe ../../../tools/exe
|
||||||
|
|
||||||
|
release:
|
||||||
|
make clean
|
||||||
|
tar cvf d8tape.tar Makefile *.c *.h LICENSE
|
||||||
|
gzip -9v d8tape.tar
|
||||||
|
|
||||||
|
test:
|
||||||
|
macro8x -d -x -m -u test.pal
|
||||||
|
d8tape test.bin | expand -4 > test.list
|
||||||
|
cp test.list verify.pal
|
||||||
|
macro8x -d -x -m -u verify.pal
|
||||||
|
../dumpbin.pl test.bin > test.dump
|
||||||
|
../dumpbin.pl verify.bin > verify.dump
|
||||||
|
-diff -s test.dump verify.dump
|
||||||
|
d8tape verify.bin | expand -4 > verify.list
|
||||||
|
-diff -s test.list verify.list
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o d8tape.exe
|
||||||
46
d8tape/d8tape.h
Normal file
46
d8tape/d8tape.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* d8tape.h
|
||||||
|
*
|
||||||
|
* (C) Copyright 2007 by Robert Krten, all rights reserved.
|
||||||
|
* Please see the LICENSE file for more information.
|
||||||
|
*
|
||||||
|
* This module contains the manifest constants and other header
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* 2007 10 25 R. Krten created
|
||||||
|
* 2007 10 28 R. Krten added TAG_INDIRECTFC
|
||||||
|
*/
|
||||||
|
|
||||||
|
// constants
|
||||||
|
#define CORE_SIZE 4096 // size of core memory
|
||||||
|
|
||||||
|
#define TAG_DATA 0x0001 // memory region is tagged as data,
|
||||||
|
#define TAG_SUB 0x0002 // subroutine target, or,
|
||||||
|
#define TAG_LABEL 0x0004 // label
|
||||||
|
#define TAG_RETURN 0x0008 // return from subroutine
|
||||||
|
#define TAG_TYPE_MASK 0x00FF // mask of above types
|
||||||
|
#define TAG_WRITABLE 0x0100 // set if anyone writes to this data location (else constant)
|
||||||
|
#define TAG_KONSTANT 0x0200 // can be changed from Caaaa -> Kvvvv
|
||||||
|
#define TAG_INDIRECTFC 0x0400 // target of an indirect flow control (JMS I / JMP I) (only meaningful if not writable)
|
||||||
|
|
||||||
|
// segment info
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t saddr; // starting address
|
||||||
|
uint16_t nwords; // number of contiguous words
|
||||||
|
} segment_t;
|
||||||
|
|
||||||
|
|
||||||
|
// prototypes
|
||||||
|
|
||||||
|
// flow.c
|
||||||
|
extern void flow (void);
|
||||||
|
|
||||||
|
// dasm.c
|
||||||
|
extern int ea (int addr, int opcode, int *indirect, int *curpage);
|
||||||
|
extern void disassemble (void);
|
||||||
|
extern int is_data (int v);
|
||||||
|
extern int fetch_iot (int code, char *dis, char *com);
|
||||||
|
|
||||||
706
d8tape/dasm.c
Normal file
706
d8tape/dasm.c
Normal file
@ -0,0 +1,706 @@
|
|||||||
|
#define DNN1 1
|
||||||
|
#define DNN2 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dasm.c
|
||||||
|
*
|
||||||
|
* (C) Copyright 2003 by Robert Krten, all rights reserved.
|
||||||
|
* Please see the LICENSE file for more information.
|
||||||
|
*
|
||||||
|
* This module contains the PDP-8 disassembler.
|
||||||
|
* Note that the 8/I and 8/L are featured at this point; other models
|
||||||
|
* should be added (particularly the 8/E's EAE instructions, as well
|
||||||
|
* as new IOT decodings, etc)
|
||||||
|
*
|
||||||
|
* 2003 12 16 R. Krten created
|
||||||
|
* 2007 10 29 R. Krten added better output formatting
|
||||||
|
* 2007 11 02 R. Krten added xrefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "d8tape.h"
|
||||||
|
#include "iot.h" // decode table for IOTs
|
||||||
|
|
||||||
|
extern char *progname; // main.c
|
||||||
|
extern char *version; // version.c
|
||||||
|
|
||||||
|
extern int optv; // main.c
|
||||||
|
extern char *tapename; // main.c, name of tape image
|
||||||
|
|
||||||
|
extern short int core []; // main.c, in-core image (-1 means location never used)
|
||||||
|
extern uint16_t tags []; // main.c, analysis tags
|
||||||
|
extern segment_t *segments; // main.c, used to accumulate runs of data (from origin for nwords)
|
||||||
|
extern int nsegments; // main.c, indicates how many segments we have
|
||||||
|
|
||||||
|
static void header (void);
|
||||||
|
static void disassemble_range (int start, int end);
|
||||||
|
static void pad (char *buf, int off, int pos);
|
||||||
|
static void xrefs (int addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dasm8
|
||||||
|
*
|
||||||
|
* This takes the current address and the instruction value
|
||||||
|
* and prints the decoded instruction. A static variable
|
||||||
|
* is used to kludge up 2-word instructions (e.g., MUY <const>).
|
||||||
|
*
|
||||||
|
* The IOTs are coded in a table; in some cases, conflicts exist, you'll
|
||||||
|
* need to select the appropriate #defines to make them go away :-)
|
||||||
|
* As shipped, the #defines match my preferences.
|
||||||
|
*
|
||||||
|
* Formatting rules:
|
||||||
|
* - the following types of output exist:
|
||||||
|
* - labels
|
||||||
|
* - banners
|
||||||
|
* - code
|
||||||
|
* - data
|
||||||
|
*
|
||||||
|
* For each type, the following format is used (all tabs, as shown by the single backtick
|
||||||
|
* character, are assumed to be at 4 character tabstops. If you don't like this, pipe
|
||||||
|
* the output through "expand -4").
|
||||||
|
*
|
||||||
|
* Labels:
|
||||||
|
* 1111111111222222222233333333334444444444555555555566666666667777777777
|
||||||
|
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||||
|
* t t t t t t t t t t t t t t t t t t t t
|
||||||
|
* TAAAA,
|
||||||
|
*
|
||||||
|
* where "T" is the label type, one of "D" for data, "L" for executable label,
|
||||||
|
* and "S" for subroutine entry, and "AAAA" is the four digit octal address.
|
||||||
|
* (See "Data" below for additional details of the "D" type).
|
||||||
|
*
|
||||||
|
* Banners:
|
||||||
|
* 1111111111222222222233333333334444444444555555555566666666667777777777
|
||||||
|
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||||
|
* t t t t t t t t t t t t t t t t t t t t
|
||||||
|
* ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
* /
|
||||||
|
* /```CONTENT
|
||||||
|
* /
|
||||||
|
* ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
*
|
||||||
|
* Where "CONTENT" is the content of the banner, e.g., "SUBROUTINE S1234".
|
||||||
|
*
|
||||||
|
* Code:
|
||||||
|
* 1111111111222222222233333333334444444444555555555566666666667777777777
|
||||||
|
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||||
|
* t t t t t t t t t t t t t t t t t t t t
|
||||||
|
* op1`````````````````````/ COMMENTS..............................@@=AAAA,OOOO
|
||||||
|
* opc1````````````````````/ COMMENTS..............................@@=AAAA,OOOO
|
||||||
|
* op1 TAAAA```````````````/ COMMENTS..............................@@=AAAA,OOOO
|
||||||
|
* op1 I TAAAA`````````````/ COMMENTS..............................@@=AAAA,OOOO
|
||||||
|
* op1 op2 op3 op4 op5 op6`/ COMMENTS..............................@@=AAAA,OOOO
|
||||||
|
* 12345678911234567892123 1234567891123456789212345678931234567 (DISLEN and COMLEN, resp.)
|
||||||
|
* 01234567891123456789212345678 234567891123456789212345678931234567890 (COMSTART and DATASTART, resp.)
|
||||||
|
*
|
||||||
|
* Where "op1", "opc1", "op2" through "op6" are 3 or 4 character mnemonic
|
||||||
|
* opcodes. "T" is the label type (as above), and "AAAA" is the address.
|
||||||
|
* Tabs are used to fill whitespace to the "/" comment delimiter, and from the
|
||||||
|
* end of the comment to the @@. The area at the "@@" indicates the address
|
||||||
|
* and the contents.
|
||||||
|
*
|
||||||
|
* This is where the COMLEN and DISLEN buffer sizes are derived from, and the
|
||||||
|
* COMSTART position (28, the start of the "/")
|
||||||
|
*
|
||||||
|
* Data:
|
||||||
|
* 1111111111222222222233333333334444444444555555555566666666667777777777
|
||||||
|
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||||
|
* t t t t t t t t t t t t t t t t t t t t
|
||||||
|
* CAAAA,``VVVV````````````````/ op1 op2 op3 op4 op5 op6 COMMENTS..................
|
||||||
|
* DAAAA,``VVVV````````````````/ op1 op2 op3 op4 op5 op6 COMMENTS..................
|
||||||
|
* KVVVV,``VVVV````````````````/ op1 op2 op3 op4 op5 op6 COMMENTS..................
|
||||||
|
*
|
||||||
|
* Where "C" is used for constants whose values are not unique, "D" is used
|
||||||
|
* for writable data, and "K" is used for constants that can be added in the
|
||||||
|
* symbol table. The distinction between "C" and "K" is that if two different
|
||||||
|
* memory locations both define the same constant value, we need to use "C"
|
||||||
|
* because it's tagged based on the address, whereas "K" is tagged based on
|
||||||
|
* the value.
|
||||||
|
*
|
||||||
|
* Other types to consider are comment blocks imported from a control file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char *codes [6] = {"AND", "TAD", "ISZ", "DCA", "JMS", "JMP"}; // IOT and OPR are decoded elsewhere
|
||||||
|
|
||||||
|
static unsigned short int two_word = 0; // set to hold two-word instruction (e.g., EAE ops), else zero (instruction 0, AND, is not a two-word instruction)
|
||||||
|
|
||||||
|
#define COMLEN 37 // length of comment, see "Code", above (both the number of bytes and the max number of characters; tabs will only make the number of bytes less)
|
||||||
|
#define DISLEN 23 // length of disassembly area, see "Code" above (ditto)
|
||||||
|
#define COMSTART 28 // 0-based column number where the comments start
|
||||||
|
#define DATASTART 40 // 0-based column number where the data (@@=AAAA,OOOO) starts
|
||||||
|
static char disbuf [DISLEN + 1];
|
||||||
|
static char combuf [COMLEN + 1];
|
||||||
|
|
||||||
|
void
|
||||||
|
dasm8 (int addr, unsigned short int buf)
|
||||||
|
{
|
||||||
|
int ind, cur;
|
||||||
|
int eff_addr;
|
||||||
|
int primary; // is primary disassembly 'c'ode or 'd'ata?
|
||||||
|
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("dasm8 (addr 0%04o word 0%04o tag 0x%04x)\n", addr, buf, tags [addr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
eff_addr = ea (addr, buf, &ind, &cur);
|
||||||
|
|
||||||
|
if (two_word) {
|
||||||
|
printf ("\t%04o /\t\t\t\t\t / (operand)\n", buf);
|
||||||
|
two_word = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare buffer areas for disassembly and comments.
|
||||||
|
memset (disbuf, 0, sizeof (disbuf));
|
||||||
|
memset (combuf, 0, sizeof (combuf));
|
||||||
|
|
||||||
|
primary = 'c'; // default to code disassembly
|
||||||
|
|
||||||
|
if (tags [addr] & TAG_LABEL) {
|
||||||
|
printf ("L%04o,\n", addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags [addr] & TAG_SUB) {
|
||||||
|
printf ("\n");
|
||||||
|
printf ("////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
printf ("/\n");
|
||||||
|
printf ("/\tSUBROUTINE: S%04o\n", addr);
|
||||||
|
printf ("/\n");
|
||||||
|
xrefs (addr);
|
||||||
|
printf ("////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
printf ("S%04o,\n", addr);
|
||||||
|
printf ("\t0\t\t\t\t\t\t/ return area\n");
|
||||||
|
// done; can't be SUB and anything else (except label, perhaps)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags [addr] & TAG_DATA) {
|
||||||
|
// if it's data, set primary as data
|
||||||
|
primary = 'd';
|
||||||
|
if ((addr & 07770) == 00010) { // addresses 0010 -> 0017 are autoindex
|
||||||
|
printf ("AI%o,\t%04o\t\t\t\t/ AUTO-INDEX REGISTER", addr & 7, core [addr]);
|
||||||
|
} else {
|
||||||
|
if (tags [addr] & TAG_INDIRECTFC) {
|
||||||
|
printf ("C%04o,\n", addr);
|
||||||
|
}
|
||||||
|
printf ("%c%04o,\t", tags [addr] & TAG_KONSTANT ? 'K' : tags [addr] & TAG_WRITABLE ? 'D' : 'C', tags [addr] & TAG_KONSTANT ? core [addr] : addr);
|
||||||
|
printf ("%04o\t\t\t\t/", core [addr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (buf & 07000) {
|
||||||
|
case 00000: // AND
|
||||||
|
case 01000: // TAD
|
||||||
|
case 02000: // ISZ
|
||||||
|
case 03000: // DCA
|
||||||
|
case 04000: // JMS
|
||||||
|
case 05000: // JMP
|
||||||
|
sprintf (disbuf, "%s ", codes [buf >> 9]);
|
||||||
|
|
||||||
|
if (ind) {
|
||||||
|
strcat (disbuf, "I ");
|
||||||
|
} else {
|
||||||
|
strcat (disbuf, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags [eff_addr] & TAG_SUB) {
|
||||||
|
strcat (disbuf, "S");
|
||||||
|
} else if (tags [eff_addr] & TAG_LABEL) {
|
||||||
|
strcat (disbuf, "L");
|
||||||
|
} else {
|
||||||
|
if ((eff_addr & 07770) == 00010) { // addresses 0010 -> 0017
|
||||||
|
strcat (disbuf, "AI");
|
||||||
|
strcat (combuf, "AUTO INDEX REGISTER");
|
||||||
|
} else {
|
||||||
|
strcat (disbuf, (tags [eff_addr] & TAG_KONSTANT) ? "K" : tags [eff_addr] & TAG_WRITABLE ? "D" : "C");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags [addr] & TAG_RETURN) {
|
||||||
|
strcat (combuf, "return ");
|
||||||
|
} else {
|
||||||
|
// comment indirect flow control change to reflect ultimate target
|
||||||
|
switch (buf & 07400) {
|
||||||
|
case 04400:
|
||||||
|
sprintf (combuf + strlen (combuf), "long call to S%04o ", core [eff_addr]);
|
||||||
|
break;
|
||||||
|
case 05400:
|
||||||
|
sprintf (combuf + strlen (combuf), "long jump to L%04o ", core [eff_addr]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((eff_addr & 07770) == 00010) { // address 0010 -> 0017
|
||||||
|
sprintf (disbuf + strlen (disbuf), "%o ", eff_addr & 7);
|
||||||
|
} else {
|
||||||
|
sprintf (disbuf + strlen (disbuf), "%04o ", (tags [eff_addr] & TAG_KONSTANT) ? core [eff_addr] : eff_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 06000: // IOT
|
||||||
|
fetch_iot (buf, disbuf, combuf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 07000: // OPR
|
||||||
|
// perform "short form" OPRs here first...
|
||||||
|
switch (buf) {
|
||||||
|
case 07000: sprintf (disbuf, "NOP"); break;
|
||||||
|
#ifdef DNN1
|
||||||
|
// case 07002: sprintf (disbuf, "BSW"); break;
|
||||||
|
case 07600: sprintf (disbuf, "7600"); break;
|
||||||
|
#endif // DNN1
|
||||||
|
#ifdef DNN2
|
||||||
|
case 07400: sprintf (disbuf, "7400"); break;
|
||||||
|
case 07401: sprintf (disbuf, "7401"); break;
|
||||||
|
case 07601: sprintf (disbuf, "7601"); break;
|
||||||
|
#endif // DNN2
|
||||||
|
case 07041: sprintf (disbuf, "CIA"); break;
|
||||||
|
case 07120: sprintf (disbuf, "STL"); break;
|
||||||
|
case 07204: sprintf (disbuf, "GLK"); break;
|
||||||
|
case 07240: sprintf (disbuf, "STA"); strcat (combuf, "AC = 7777 (-0001)"); break;
|
||||||
|
case 07300: sprintf (disbuf, "CLA CLL"); strcat (combuf, "AC = 0000"); break;
|
||||||
|
case 07301: sprintf (disbuf, "CLA CLL IAC"); strcat (combuf, "AC = 0001"); break;
|
||||||
|
case 07303: sprintf (disbuf, "CLA CLL IAC BSW"); strcat (combuf, "AC = 0100 (64)"); break;
|
||||||
|
case 07305: sprintf (disbuf, "CLA CLL IAC RAL"); strcat (combuf, "AC = 0002"); break;
|
||||||
|
case 07325: sprintf (disbuf, "CLA CLL CML IAC RAL"); strcat (combuf, "AC = 0003"); break;
|
||||||
|
case 07326: sprintf (disbuf, "CLA CLL CML RTL"); strcat (combuf, "AC = 0002"); break;
|
||||||
|
case 07307: sprintf (disbuf, "CLA CLL IAC RTL"); strcat (combuf, "AC = 0004"); break;
|
||||||
|
case 07327: sprintf (disbuf, "CLA CLL CML IAC RTL"); strcat (combuf, "AC = 0006"); break;
|
||||||
|
case 07330: sprintf (disbuf, "CLA CLL CML RAR"); strcat (combuf, "AC = 4000 (-4000 = -2048 dec)"); break;
|
||||||
|
case 07332: sprintf (disbuf, "CLA CLL CML RTR"); strcat (combuf, "AC = 2000 (1024)"); break;
|
||||||
|
case 07333: sprintf (disbuf, "CLA CLL CML IAC RTL"); strcat (combuf, "AC = 6000 (-2000 = -1024 dec)"); break;
|
||||||
|
case 07340: sprintf (disbuf, "CLA CLL CMA"); strcat (combuf, "AC = 7777 (-0001)"); break;
|
||||||
|
case 07344: sprintf (disbuf, "CLA CLL CMA RAL"); strcat (combuf, "AC = 7776 (-0002)"); break;
|
||||||
|
case 07346: sprintf (disbuf, "CLA CLL CMA RTL"); strcat (combuf, "AC = 7775 (-0003)"); break;
|
||||||
|
case 07350: sprintf (disbuf, "CLA CLL CMA RAR"); strcat (combuf, "AC = 3777 (2047)"); break;
|
||||||
|
case 07352: sprintf (disbuf, "CLA CLL CMA RTR"); strcat (combuf, "AC = 5777 (-2001 = -1025 dec)"); break;
|
||||||
|
#ifndef DNN2
|
||||||
|
case 07401: sprintf (disbuf, "NOP"); break;
|
||||||
|
#endif // !DNN1
|
||||||
|
case 07410: sprintf (disbuf, "SKP"); break;
|
||||||
|
case 07610: sprintf (disbuf, "SKP CLA"); break;
|
||||||
|
case 07604: sprintf (disbuf, "LAS"); break;
|
||||||
|
case 07621: sprintf (disbuf, "CAM"); break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
// determine group (0401 is 0000/0001 for group 1, 0400 for group 2, 0401 for EAE)
|
||||||
|
switch (buf & 00401) {
|
||||||
|
case 00000: // group 1
|
||||||
|
case 00001: // group 1
|
||||||
|
// sequence 1
|
||||||
|
if (buf & 00200) {
|
||||||
|
strcat (disbuf, "CLA ");
|
||||||
|
}
|
||||||
|
if (buf & 00100) {
|
||||||
|
strcat (disbuf, "CLL ");
|
||||||
|
}
|
||||||
|
// sequence 2
|
||||||
|
if (buf & 00040) {
|
||||||
|
strcat (disbuf, "CMA ");
|
||||||
|
}
|
||||||
|
if (buf & 00020) {
|
||||||
|
strcat (disbuf, "CML ");
|
||||||
|
}
|
||||||
|
// sequence 3
|
||||||
|
if (buf & 00001) {
|
||||||
|
strcat (disbuf, "IAC ");
|
||||||
|
}
|
||||||
|
// sequence 4
|
||||||
|
if (buf & 00010) {
|
||||||
|
if (buf & 00002) {
|
||||||
|
strcat (disbuf, "RTR ");
|
||||||
|
} else {
|
||||||
|
strcat (disbuf, "RAR ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf & 00004) {
|
||||||
|
if (buf & 00002) {
|
||||||
|
strcat (disbuf, "RTL ");
|
||||||
|
} else {
|
||||||
|
strcat (disbuf, "RAL ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DNN2
|
||||||
|
if ((buf & 00016) == 00002) {
|
||||||
|
strcat (disbuf, "BSW ");
|
||||||
|
}
|
||||||
|
#endif // DNN2
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 00400: // group 2
|
||||||
|
// sequence 1
|
||||||
|
if (buf & 00100) {
|
||||||
|
if (buf & 00010) {
|
||||||
|
strcat (disbuf, "SPA ");
|
||||||
|
} else {
|
||||||
|
strcat (disbuf, "SMA ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf & 00040) {
|
||||||
|
if (buf & 00010) {
|
||||||
|
strcat (disbuf, "SNA ");
|
||||||
|
} else {
|
||||||
|
strcat (disbuf, "SZA ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf & 00020) {
|
||||||
|
if (buf & 00010) {
|
||||||
|
strcat (disbuf, "SZL ");
|
||||||
|
} else {
|
||||||
|
strcat (disbuf, "SNL ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DNN2
|
||||||
|
if ((buf & 00170) == 00010) {
|
||||||
|
strcat (disbuf, "SKP ");
|
||||||
|
}
|
||||||
|
#endif // DNN2
|
||||||
|
// sequence 2
|
||||||
|
if (buf & 00200) {
|
||||||
|
strcat (disbuf, "CLA ");
|
||||||
|
}
|
||||||
|
// sequence 3
|
||||||
|
if (buf & 00004) {
|
||||||
|
strcat (disbuf, "OSR ");
|
||||||
|
}
|
||||||
|
if (buf & 00002) {
|
||||||
|
strcat (disbuf, "HLT ");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 00401: // EAE
|
||||||
|
// sequence 1
|
||||||
|
if (buf & 00200) {
|
||||||
|
strcat (disbuf, "CLA ");
|
||||||
|
}
|
||||||
|
// sequence 2
|
||||||
|
if (buf & 00100) {
|
||||||
|
strcat (disbuf, "MQA ");
|
||||||
|
}
|
||||||
|
if (buf & 00040) {
|
||||||
|
strcat (disbuf, "SCA ");
|
||||||
|
}
|
||||||
|
if (buf & 00020) {
|
||||||
|
strcat (disbuf, "MQL ");
|
||||||
|
}
|
||||||
|
// sequence 3
|
||||||
|
switch (buf & 00016) {
|
||||||
|
case 0: // no further ops, done
|
||||||
|
break;
|
||||||
|
case 002:
|
||||||
|
strcat (disbuf, "SCL ");
|
||||||
|
two_word = buf;
|
||||||
|
break;
|
||||||
|
case 004:
|
||||||
|
strcat (disbuf, "MUY ");
|
||||||
|
two_word = buf;
|
||||||
|
break;
|
||||||
|
case 006:
|
||||||
|
strcat (disbuf, "DVI ");
|
||||||
|
two_word = buf;
|
||||||
|
break;
|
||||||
|
case 010:
|
||||||
|
strcat (disbuf, "NMI");
|
||||||
|
break;
|
||||||
|
case 012:
|
||||||
|
strcat (disbuf, "SHL ");
|
||||||
|
two_word = buf;
|
||||||
|
break;
|
||||||
|
case 014:
|
||||||
|
strcat (disbuf, "ASR ");
|
||||||
|
two_word = buf;
|
||||||
|
break;
|
||||||
|
case 016:
|
||||||
|
strcat (disbuf, "LSR ");
|
||||||
|
two_word = buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (two_word) {
|
||||||
|
strcat (disbuf, "+");
|
||||||
|
}
|
||||||
|
// trim any trailing spaces
|
||||||
|
while (*disbuf && disbuf [strlen (disbuf) - 1] == ' ') {
|
||||||
|
disbuf [strlen (disbuf) - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (primary == 'c') { // if primary is code, then spill data too
|
||||||
|
pad (disbuf, 0, COMSTART - 4); // add tabs to get disassembly to comment start (one tab less because we print it next)
|
||||||
|
printf ("\t%s", disbuf); // print disassembly so far
|
||||||
|
printf ("/ "); // print comment start
|
||||||
|
pad (combuf, 2, DATASTART); // pad comment buffer to get to data area
|
||||||
|
printf ("%s@@%04o=%04o\n", combuf, addr, buf); // print comment, address and opcode
|
||||||
|
} else { // else we've already spilled both, just terminate the line
|
||||||
|
pad (disbuf, 2, DATASTART);
|
||||||
|
printf (" %s", disbuf);
|
||||||
|
printf ("\n");
|
||||||
|
two_word = 0; // we don't care that it's a two-word when we're printing it as data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ea
|
||||||
|
*
|
||||||
|
* Calculate the effective address given the
|
||||||
|
* address and opcode. Opcodes that don't have
|
||||||
|
* an effective address (e.g., IOTs), return -1.
|
||||||
|
*
|
||||||
|
* The indirect pointer is optional, and, if specified,
|
||||||
|
* will cause the location to be returned with a zero
|
||||||
|
* or one indicating indirection. The indirect pointer
|
||||||
|
* is not modified in case of a non-EA opcode.
|
||||||
|
*
|
||||||
|
* Similarly for the curpage pointer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ea (int addr, int opcode, int *indirect, int *curpage)
|
||||||
|
{
|
||||||
|
int eff_addr;
|
||||||
|
int c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (opcode >= 06000) { // IOTs and OPRs don't have an EA
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = opcode & 00400;
|
||||||
|
c = opcode & 00200;
|
||||||
|
eff_addr = c ? (addr & 07600) + (opcode & 00177) : opcode & 00177;
|
||||||
|
if (indirect) {
|
||||||
|
*indirect = i;
|
||||||
|
}
|
||||||
|
if (curpage) {
|
||||||
|
*curpage = c;
|
||||||
|
}
|
||||||
|
return (eff_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* disassemble
|
||||||
|
*
|
||||||
|
* This drives disassembly once the flow analysis has been done.
|
||||||
|
*
|
||||||
|
* We disassemle in segment order.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
disassemble (void)
|
||||||
|
{
|
||||||
|
int snum;
|
||||||
|
|
||||||
|
header ();
|
||||||
|
for (snum = 0; snum < nsegments; snum++) {
|
||||||
|
printf ("\n*%04o\n", segments [snum].saddr);
|
||||||
|
disassemble_range (segments [snum].saddr, segments [snum].saddr + segments [snum].nwords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
header (void)
|
||||||
|
{
|
||||||
|
struct tm *tm;
|
||||||
|
time_t now;
|
||||||
|
int nused, ndata, ncode;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
time (&now);
|
||||||
|
tm = localtime (&now);
|
||||||
|
|
||||||
|
nused = ndata = ncode = 0;
|
||||||
|
for (i = 0; i < CORE_SIZE; i++) {
|
||||||
|
if (core [i] >= 0) {
|
||||||
|
nused++;
|
||||||
|
if (tags [i] & TAG_DATA) {
|
||||||
|
ndata++;
|
||||||
|
} else {
|
||||||
|
ncode++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("TITLE \"AUTOMATIC DISASSEMBLY OF %s BY D8TAPE\"\n", tapename);
|
||||||
|
printf ("////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
printf ("/\n");
|
||||||
|
printf ("/\tAutomatic Disassembly of %s\n", tapename);
|
||||||
|
printf ("/\tGenerated %04d %02d %02d %02d:%02d:%02d\n", tm -> tm_year + 1900, tm -> tm_mon + 1, tm -> tm_mday, tm -> tm_hour, tm -> tm_min, tm -> tm_sec);
|
||||||
|
printf ("/\tGenerated by d8tape version %s\n", version);
|
||||||
|
printf ("/\tVisit http://www.pdp12.org/pdp8/software/index.html for updates\n");
|
||||||
|
printf ("/\n");
|
||||||
|
printf ("/\tSymbol format:\n");
|
||||||
|
printf ("/\t\tAIx -- Auto-index variables (address range 001x)\n");
|
||||||
|
printf ("/\t\tCaaaa -- Constants (non-unique)\n");
|
||||||
|
printf ("/\t\tDaaaa -- Data (read/write variables)\n");
|
||||||
|
printf ("/\t\tKvvvv -- Program-wide unique constants\n");
|
||||||
|
printf ("/\t\tLaaaa -- Labels for control flow targets\n");
|
||||||
|
printf ("/\t\tSaaaa -- Subroutines\n");
|
||||||
|
printf ("/\n");
|
||||||
|
printf ("/\tWhere:\n");
|
||||||
|
printf ("/\t\taaaa is the definition address\n");
|
||||||
|
printf ("/\t\tvvvv is the value of the constant\n");
|
||||||
|
printf ("/\t\tx is the last digit of the address 001x for auto-index variables\n");
|
||||||
|
printf ("/\n");
|
||||||
|
printf ("/\t%04o locations used, %04o code and %04o data\n", nused, ncode, ndata);
|
||||||
|
printf ("////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
disassemble_range (int start, int end)
|
||||||
|
{
|
||||||
|
int addr;
|
||||||
|
|
||||||
|
for (addr = start; addr < end; addr++) {
|
||||||
|
dasm8 (addr, core [addr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fetch_iot
|
||||||
|
*
|
||||||
|
* This function looks up in the iot table (iot.h) to find
|
||||||
|
* the opcode passed in "code" and updates the disassembled
|
||||||
|
* output "dis" and the comment "com".
|
||||||
|
*
|
||||||
|
* More work needs to be done here for conflicting IOTs.
|
||||||
|
*
|
||||||
|
* Current, I assume that there are no conflicts (actually, I
|
||||||
|
* return the first match, regardless of conflicts). A command
|
||||||
|
* line / control file option needs to be created to allow
|
||||||
|
* the selection of devices. Something like "-i vc8i", for example
|
||||||
|
* to allow the VC8/I IOTs to be enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
fetch_iot (int code, char *dis, char *com)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof (iots) / sizeof (iots [0]); i++) {
|
||||||
|
if (code == iots [i].code) {
|
||||||
|
if (dis) {
|
||||||
|
strcpy (dis, iots [i].mnemonic);
|
||||||
|
}
|
||||||
|
if (com) {
|
||||||
|
strncpy (com, iots [i].comment, COMLEN - 1);
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dis) {
|
||||||
|
sprintf (dis, "%04o", code);
|
||||||
|
}
|
||||||
|
if (com) {
|
||||||
|
sprintf (com, "unknown IOT");
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pad
|
||||||
|
*
|
||||||
|
* Figures out where the current print position is based on expanding
|
||||||
|
* the current tabs in "buf" and adds more tabs to get to "pos".
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
pad (char *buf, int loc, int pos)
|
||||||
|
{
|
||||||
|
for (; *buf; buf++) {
|
||||||
|
if (*buf == '\t') {
|
||||||
|
if ((loc & 3) == 0) {
|
||||||
|
loc += 4;
|
||||||
|
} else {
|
||||||
|
loc += 4 - (loc & ~3);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = pos / 4 - loc / 4;
|
||||||
|
while (loc--) {
|
||||||
|
*buf++ = '\t';
|
||||||
|
}
|
||||||
|
*buf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
is_data (int v)
|
||||||
|
{
|
||||||
|
return ((v & TAG_TYPE_MASK) == TAG_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xrefs (int addr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int eff;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < CORE_SIZE; i++) {
|
||||||
|
if (core [i] < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags [i] & TAG_DATA) {
|
||||||
|
//printf ("+XREF ADDR %04o CHECK %04o IS DATA\n", addr, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((core [i] & 07400) == 04000) { // direct JMS
|
||||||
|
eff = ea (i, core [i], NULL, NULL);
|
||||||
|
//printf ("+XREF ADDR %04o CHECK %04o %04o JMS EA %04o\n", addr, i, core [i], eff);
|
||||||
|
if (eff == addr) {
|
||||||
|
if (!count) {
|
||||||
|
printf ("/\tCalled from:\n/\t");
|
||||||
|
}
|
||||||
|
printf ("%04o ", i);
|
||||||
|
count++;
|
||||||
|
if ((count % 15) == 0) {
|
||||||
|
printf ("\n/\t");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((core [i] & 07400) == 04400) { // indirect JMS
|
||||||
|
eff = ea (i, core [i], NULL, NULL);
|
||||||
|
//printf ("+XREF ADDR %04o CHECK %04o %04o JMS I EA %04o\n", addr, i, core [i], eff);
|
||||||
|
if (tags [eff] & TAG_WRITABLE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//printf ("+XREF ADDR %04o CHECK %04o %04o JMS I is not writable\n", addr, i, core [i]);
|
||||||
|
if (core [eff] < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//printf ("+XREF ADDR %04o CHECK %04o %04o JMS I has valid indirect value\n", addr, i, core [i]);
|
||||||
|
if (core [eff] == addr) {
|
||||||
|
if (!count) {
|
||||||
|
printf ("/\tCalled from:\n/\t");
|
||||||
|
}
|
||||||
|
printf ("%04o ", i);
|
||||||
|
count++;
|
||||||
|
if ((count % 15) == 0) {
|
||||||
|
printf ("\n/\t");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count) {
|
||||||
|
printf ("\n");
|
||||||
|
printf ("/\tTotal %04o (%d) calls\n", count, count);
|
||||||
|
} else {
|
||||||
|
printf ("/\tNever called\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
472
d8tape/flow.c
Normal file
472
d8tape/flow.c
Normal file
@ -0,0 +1,472 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* flow.c
|
||||||
|
*
|
||||||
|
* (C) Copyright 2007 by Robert Krten, all rights reserved.
|
||||||
|
* Please see the LICENSE file for more information.
|
||||||
|
*
|
||||||
|
* This module contains the PDP-8 flow analyzer.
|
||||||
|
*
|
||||||
|
* 2007 10 25 R. Krten created
|
||||||
|
* 2007 10 28 R. Krten added TAG_INDIRECTFC
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "d8tape.h"
|
||||||
|
|
||||||
|
extern char *progname; // main.c
|
||||||
|
extern char *version; // version.c
|
||||||
|
|
||||||
|
extern int optv; // main.c
|
||||||
|
extern short int core []; // main.c, in-core image (-1 means location never used)
|
||||||
|
extern uint16_t tags []; // main.c, analysis tags
|
||||||
|
|
||||||
|
char konstmap [4096]; // 12 bits gives us 0..4095, so 4096 different constants (0 == not used, 1 == unique, 2 == used but not unique)
|
||||||
|
|
||||||
|
static void pass1 (void);
|
||||||
|
static void pass2 (void);
|
||||||
|
static void pass3 (void);
|
||||||
|
#ifdef PASS4_ENABLED
|
||||||
|
static void pass4 (void);
|
||||||
|
#endif
|
||||||
|
static void verify_subroutines (void);
|
||||||
|
static int valid_opr (int opr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main flow analysis
|
||||||
|
*
|
||||||
|
* See individual functions for more details
|
||||||
|
*
|
||||||
|
* Basic idea is that there is a shadow array called "tags", which indicates
|
||||||
|
* information about the given memory location (e.g., tags [0017] gives
|
||||||
|
* information about core [0017]).
|
||||||
|
*
|
||||||
|
* The various passes affect the tags[] array with whatever they can detect.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
flow (void)
|
||||||
|
{
|
||||||
|
pass1 ();
|
||||||
|
pass2 ();
|
||||||
|
pass3 ();
|
||||||
|
#ifdef PASS4_ENABLED
|
||||||
|
pass4 (); // this pass is fundamentally broken (well, maybe not the pass, but the interpretation of the results in dasm.c)
|
||||||
|
#endif
|
||||||
|
verify_subroutines ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pass1
|
||||||
|
*
|
||||||
|
* On pass 1, we can say with certainty only the following statements:
|
||||||
|
* - if it's an invalid IOT or OPR, then it's data.
|
||||||
|
* - if the instruction must have a valid EA, and it's invalid,
|
||||||
|
* then it's data.
|
||||||
|
* - if the JMS (direct only) target is not zero or the same as the
|
||||||
|
* address, then it's data
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
pass1 (void)
|
||||||
|
{
|
||||||
|
int addr, eff;
|
||||||
|
|
||||||
|
for (addr = 0; addr < CORE_SIZE; addr++) {
|
||||||
|
// skip unused
|
||||||
|
if (core [addr] == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// handle IOTs
|
||||||
|
if ((core [addr] & 07000) == 06000) {
|
||||||
|
// if we can't decode it, it's not valid
|
||||||
|
if (!fetch_iot (core [addr], NULL, NULL)) {
|
||||||
|
tags [addr] |= TAG_DATA;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// check OPRs; if they're invalid, tag as DATA, else skip
|
||||||
|
if ((core [addr] & 07000) == 07000) {
|
||||||
|
if (!valid_opr (core [addr])) {
|
||||||
|
tags [addr] |= TAG_DATA;
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW1 %04o %04o has invalid OPR -> DATA\n", addr, core [addr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// done OPRs, skip
|
||||||
|
continue; // @@@ NOTE: this does not work with EAE OPRs that take the next location as their parameter...
|
||||||
|
}
|
||||||
|
|
||||||
|
// ea() is always valid for opcodes < 06000
|
||||||
|
eff = ea (addr, core [addr], NULL, NULL);
|
||||||
|
|
||||||
|
// if the instruction should have a valid EA and doesn't...
|
||||||
|
if (core [eff] == -1) {
|
||||||
|
// then it's not an instruction
|
||||||
|
tags [addr] |= TAG_DATA;
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW1 %04o %04o has EA %04o (invalid or not in core) and OP < 6000 -> DATA\n", addr, core [addr], eff);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's a plain JMS
|
||||||
|
if ((core [addr] & 07400) == 04000) {
|
||||||
|
// and the target isn't zero or it's not the same as the address
|
||||||
|
if (core [eff] && core [eff] != eff) {
|
||||||
|
tags [addr] |= TAG_DATA;
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW1 %04o %04o JMS target not 0000 or ADDR (EA %04o is %04o)\n", addr, core [addr], eff, core [eff]);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// else, if it's ok, then the target is writable, after all (JMS drops the return address there)
|
||||||
|
tags [eff] |= TAG_WRITABLE;
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW1 %04o %04o JMS target is 0000 or ADDR, marking EA %04o as WRITABLE\n", addr, core [addr], eff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pass2
|
||||||
|
*
|
||||||
|
* In this pass, we operate on the direct targets (no indirection)
|
||||||
|
* and mark the targets as data, variable, label, or subroutine
|
||||||
|
* target.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
pass2 (void)
|
||||||
|
{
|
||||||
|
int addr;
|
||||||
|
int eff;
|
||||||
|
|
||||||
|
for (addr = 0; addr < CORE_SIZE; addr++) {
|
||||||
|
// skip unused or data locations
|
||||||
|
if (core [addr] == -1 || (tags [addr] & TAG_DATA)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
eff = ea (addr, core [addr], NULL, NULL);
|
||||||
|
|
||||||
|
switch (core [addr] & 07400) { // check opcode
|
||||||
|
case 00000: // AND
|
||||||
|
case 00400: // AND I
|
||||||
|
case 01000: // TAD
|
||||||
|
case 01400: // TAD I
|
||||||
|
case 02000: // ISZ
|
||||||
|
case 02400: // ISZ I
|
||||||
|
case 03000: // DCA
|
||||||
|
case 03400: // DCA I
|
||||||
|
tags [eff] |= TAG_DATA; // the referenced EA is data
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW2 %04o %04o is AND/TAD/ISZ/DCA's EA %04o tagged as DATA\n", addr, core [addr], eff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark as writable if someone writes to it directly (ISZ and DCA only)
|
||||||
|
if ((core [addr] & 07400) == 02000 || (core [addr] & 07400) == 03000) {
|
||||||
|
tags [eff] |= TAG_WRITABLE;
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW2 %04o %04o is ISZ/DCA so EA %04o is WRITABLE\n", addr, core [addr], eff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 04000: // JMS
|
||||||
|
if (core [eff] == 0 || core [eff] == eff) { // first word of JMS target must be zero or the address itself
|
||||||
|
tags [eff] |= TAG_SUB; // otherwise, it's a valid subroutine target
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW2 %04o %04o is JMS with good target %04o content (%04o) so tagged as SUB\n", addr, core [addr], eff, core [eff]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tags [addr] |= TAG_DATA; // then invalidate this "instruction", it's bogus
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW2 %04o %04o is JMS with bad target %04o content (%04o) so tagged as DATA\n", addr, core [addr], eff, core [eff]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 05000: // JMP
|
||||||
|
tags [eff] |= TAG_LABEL;
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW2 %04o %04o is JMP so EA %04o is LABEL\n", addr, core [addr], eff);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// JMS I, JMP I, IOTs, and OPRs are not handled in this pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pass3
|
||||||
|
*
|
||||||
|
* In this pass, we verify and mark the indirects
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
pass3 (void)
|
||||||
|
{
|
||||||
|
int addr;
|
||||||
|
int eff;
|
||||||
|
|
||||||
|
for (addr = 0; addr < CORE_SIZE; addr++) {
|
||||||
|
// skip unused, data, or non-indirect opcodes
|
||||||
|
if (core [addr] == -1 || (tags [addr] & TAG_DATA) || core [addr] >= 06000 || !(core [addr] & 00400)) {
|
||||||
|
if (optv > 2 && core [addr] != -1) {
|
||||||
|
printf ("+FLOW3 %04o %04o tags 0x%04x skipped\n", addr, core [addr], tags [addr]);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
eff = ea (addr, core [addr], NULL, NULL);
|
||||||
|
|
||||||
|
switch (core [addr] & 07000) { // check opcode (indirectness assured above)
|
||||||
|
case 00000: // AND I
|
||||||
|
case 01000: // TAD I
|
||||||
|
case 02000: // ISZ I
|
||||||
|
case 03000: // DCA I
|
||||||
|
if (core [eff] != -1 && !(tags [eff] & TAG_WRITABLE)) { // if it's valid and constant
|
||||||
|
tags [core [eff]] |= TAG_DATA; // then the target is data
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW3 %04o %04o is AND/TAD/ISZ/DCA I through constant EA %04o so target %04o is DATA\n", addr, core [addr], eff, core [eff]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark as writable if someone writes to it (ISZ and DCA only)
|
||||||
|
if ((core [addr] & 07000) == 02000 || (core [addr] & 07000) == 03000) {
|
||||||
|
tags [core [eff]] |= TAG_WRITABLE;
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW3 %04o %04o is ISZ/DCA I thorugh constant EA %04o so target %04o is WRITABLE\n", addr, core [addr], eff, core [eff]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 04000: // JMS I
|
||||||
|
if (core [eff] != -1 && !(tags [eff] & TAG_WRITABLE)) { // if it's valid and constant
|
||||||
|
if (core [core [eff]] == 0 || core [core [eff]] == core [eff]) { // valid first word of JMS I target
|
||||||
|
tags [core [eff]] |= TAG_SUB; // ultimate target is a valid subroutine target
|
||||||
|
tags [eff] |= TAG_DATA; // and the pointer is a valid data type
|
||||||
|
tags [eff] |= TAG_INDIRECTFC; // and the pointer is used in an indirect flow control target
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW3 %04o %04o is JMS I through constant EA %04o so target %04o (content %04o) is ok, so tagged as SUB\n", addr, core [addr], eff, core [eff], core [core [eff]]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tags [addr] |= TAG_DATA; // then this isn't a valid instruction
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW3 %04o %04o is JMS I through constant EA %04o with target %04o (invalid content %04o), so tagged as DATA\n", addr, core [addr], eff, core [eff], core [core [eff]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 05000: // JMP I
|
||||||
|
if (core [eff] != -1) { // if it's valid
|
||||||
|
if (!(tags [eff] & TAG_WRITABLE)) { // and constant
|
||||||
|
tags [eff] |= TAG_DATA; // pointer is a valid data type
|
||||||
|
tags [eff] |= TAG_INDIRECTFC; // and the pointer is used in an indirect flow control target
|
||||||
|
tags [core [eff]] |= TAG_LABEL; // ultimate target is a valid JMP target
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW3 %04o %04o is JMP I through constant EA %04o with valid target %04o, so EA tagged as DATA | INDIRECTFC and target data %04o tagged as LABEL\n", addr, core [addr], eff, core [eff], core [core [eff]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tags [addr] |= TAG_DATA; // else, it's not really a valid constant expression
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW3 %04o %04o is JMP I through constant EA %04o with invalid target %04o, so tagged as DATA\n", addr, core [addr], eff, core [eff]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PASS4_ENABLED
|
||||||
|
/*
|
||||||
|
* pass4
|
||||||
|
*
|
||||||
|
* In this pass, we update the constant map (konstmap).
|
||||||
|
*
|
||||||
|
* This effectively converts Cxxxx to Kxxxx, and results in more human-
|
||||||
|
* friendly code. So, instead of:
|
||||||
|
*
|
||||||
|
* C1234, 0777
|
||||||
|
*
|
||||||
|
* you'd see:
|
||||||
|
*
|
||||||
|
* K0777, 0777
|
||||||
|
*
|
||||||
|
* The only trick to this is that since symbols must be unique in 6
|
||||||
|
* characters (for PAL compatibility), we need to ensure that the
|
||||||
|
* items that convert from Cxxxx to Kxxxx are unique. That's why
|
||||||
|
* konstmap[] has the values 0, 1, and 2:
|
||||||
|
*
|
||||||
|
* 0 == constant is not used anywhere in the code
|
||||||
|
* 1 == constant is defined exactly once (can be converted)
|
||||||
|
* 2 == constant has been defined more than once (cannot be converted)
|
||||||
|
*
|
||||||
|
* Any constant that's used in an indirect flow control manner, however,
|
||||||
|
* is not a candidate, because technically it's not used as a K-style
|
||||||
|
* constant.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
pass4 (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset (konstmap, 0, sizeof (konstmap));
|
||||||
|
|
||||||
|
// populate konstant[] map
|
||||||
|
for (i = 0; i < CORE_SIZE; i++) {
|
||||||
|
if (core [i] == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags [i] & TAG_WRITABLE) {
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o TAG %02X is writable, therefore, not a constant\n", i, core [i], tags [i]);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o TAG %02X\n", i, core [i], tags [i]);
|
||||||
|
}
|
||||||
|
if ((tags [i] & TAG_DATA) && !(tags [i] & TAG_INDIRECTFC)) {
|
||||||
|
switch (konstmap [core [i]]) {
|
||||||
|
case 0:
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o FRESH KONSTANT\n", i, core [i]);
|
||||||
|
}
|
||||||
|
konstmap [core [i]]++; // this is our first one, bump the counter
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o NO LONGER UNIQUE KONSTANT\n", i, core [i]);
|
||||||
|
}
|
||||||
|
konstmap [core [i]]++; // this is our second one, go to "2"
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o PROMISCUOUS CONSTANT\n", i, core [i]);
|
||||||
|
}
|
||||||
|
// do nothing, we're at "2" indicating "non-unique"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// analyze konstant[] map
|
||||||
|
for (i = 0; i < CORE_SIZE; i++) {
|
||||||
|
if (core [i] == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tags [i] & TAG_WRITABLE) {
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o TAG %02X is writable, therefore, not a constant\n", i, core [i], tags [i]);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o TESTING (%02X)\n", i, core [i], tags [i]);
|
||||||
|
}
|
||||||
|
if (tags [i] & TAG_DATA) {
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o TESTING...DATA\n", i, core [i]);
|
||||||
|
}
|
||||||
|
if (konstmap [core [i]] == 1) { // if it's unique
|
||||||
|
tags [i] |= TAG_KONSTANT; // then go ahead and tag it
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("+FLOW4 %04o %04o TAGGED AS KONSTANT\n", i, core [i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* verify_subroutines
|
||||||
|
*
|
||||||
|
* This is used to verify that a target really is a subroutine.
|
||||||
|
* Verification consists of ensuring that somewhere within the
|
||||||
|
* same page is a JMP I through the return address. If not,
|
||||||
|
* then the subroutine is bogus, because you can't return from
|
||||||
|
* it, so we knock down the "TAG_SUB" flag.
|
||||||
|
*
|
||||||
|
* BUG: This misses the following case:
|
||||||
|
*
|
||||||
|
* *0
|
||||||
|
* 0 /return area
|
||||||
|
* *4000
|
||||||
|
* jmp i 0 / return through zero page
|
||||||
|
*
|
||||||
|
* because we only search for returns within the page that the
|
||||||
|
* subroutine definition is in. I don't think this is a major
|
||||||
|
* problem, just something to be aware of. Plus, the TAG_RETURN
|
||||||
|
* is *really* only used as a comment field indicator anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
verify_subroutines (void)
|
||||||
|
{
|
||||||
|
int addr;
|
||||||
|
int page;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
for (addr = 0; addr < CORE_SIZE; addr++) {
|
||||||
|
if (!(tags [addr] & TAG_SUB)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try and find returns within page
|
||||||
|
found = 0;
|
||||||
|
for (page = addr; page <= (addr | 00177); page++) {
|
||||||
|
if ((core [page] & 07400) == 05400) {
|
||||||
|
if (ea (page, core [page], NULL, NULL) == addr) { // JMP I <start of subroutine> found!
|
||||||
|
tags [page] |= TAG_RETURN; // mark the returns
|
||||||
|
found++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
tags [addr] &= ~TAG_SUB; // not a subroutine, no return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
valid_opr (int opr)
|
||||||
|
{
|
||||||
|
// a valid OPR must be 07xxx
|
||||||
|
if ((opr & 07000) != 07000) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((opr & 07400) == 07000) { // group 1
|
||||||
|
if ((opr & 00014) == 00014) { // with both L and R rotate bits on
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
} else if ((opr & 07401) == 07400) { // group 2
|
||||||
|
// all ok
|
||||||
|
} else if ((opr & 07401) == 07401) { // EAE
|
||||||
|
// if bits 6, 8, 9, or 10 are set...
|
||||||
|
if (opr & 00056) {
|
||||||
|
return (0); // @@@ we're disabling EAE for now
|
||||||
|
}
|
||||||
|
// otherwise it's an "MQ microinstruction", which is ok
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
418
d8tape/iot.h
Normal file
418
d8tape/iot.h
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* iot.h
|
||||||
|
*
|
||||||
|
* (C) Copyright 2003 by Robert Krten, all rights reserved.
|
||||||
|
* Please see the LICENSE file for more information.
|
||||||
|
*
|
||||||
|
* This module contains the IOT decode table.
|
||||||
|
*
|
||||||
|
* 2003 12 16 R. Krten created
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conflicting decodes for IOTs
|
||||||
|
*
|
||||||
|
* 6050 - 6077 VC8I or KV8I; one only
|
||||||
|
* 6440 - 6457 PT08 uses some of the data areas from the Data Communications System 680/I -- definition of PT08 is optional
|
||||||
|
* 6530 - 6547 AF01A or AF04A; one only
|
||||||
|
* 6551 used by AA01A, AA05, or not used. Define zero or one only.
|
||||||
|
* 6571 used by AF04A, AC01A, or not used. Define zero or one only.
|
||||||
|
* 6600 - 6667 used by DP01AA, overrides DF32/RF08 selection. If defining DP01AA, don't bother with DF32/RF08
|
||||||
|
* 6600 - 6627 used by DF32 and RF08, define one only.
|
||||||
|
* 6640 - 6647 used by RF08 or not used, define RF08 or not.
|
||||||
|
* 6700 - 6727 used by TC58, TR02, and TA8A, define one only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Select one of the following:
|
||||||
|
#define VC8I
|
||||||
|
//#define KV8I
|
||||||
|
|
||||||
|
// Select PT08 if required; it will override some of the IOTs from the Data Communications System 680/I
|
||||||
|
//#define PT08
|
||||||
|
|
||||||
|
// Select one of the following:
|
||||||
|
#define AF01A
|
||||||
|
//#define AF04A
|
||||||
|
|
||||||
|
// Select one of the following:
|
||||||
|
#define AA01A
|
||||||
|
//#define AA05
|
||||||
|
|
||||||
|
// If selecting DP01AA, don't bother with DF32/RF08
|
||||||
|
//#define DP01AA
|
||||||
|
#ifndef DP01AA
|
||||||
|
// Select one of the following:
|
||||||
|
#define DF32
|
||||||
|
// #define RF08
|
||||||
|
#endif // DP01AA
|
||||||
|
|
||||||
|
// Select one of the following:
|
||||||
|
#define TA8A
|
||||||
|
//#define TC58
|
||||||
|
//#define TR02
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int code; // code number, e.g. 06001
|
||||||
|
char *option; // hardware option, e.g., vc8i
|
||||||
|
char *mnemonic; // decoded value, e.g., "ION"
|
||||||
|
char *comment; // code description of IOT, e.g., "clear x coordinate buffer"
|
||||||
|
} one_iot_t;
|
||||||
|
|
||||||
|
#define OP_ALL ""
|
||||||
|
one_iot_t iots [] =
|
||||||
|
{
|
||||||
|
// 6000 Interrupts
|
||||||
|
{ 06001, OP_ALL, "ION", "Enable Interrupts"},
|
||||||
|
{ 06002, OP_ALL, "IOF", "Disable Interrupts"},
|
||||||
|
// 6010 High Speed Perforated Tape Reader and Control
|
||||||
|
{ 06011, OP_ALL, "RSF", "Skip if reader flag is a 1."},
|
||||||
|
{ 06012, OP_ALL, "RFB", "Read the content of the reader buffer and clear the reader flag. This instructions does not clear the AC. RB v AC4-11 -> AC4-11"},
|
||||||
|
{ 06014, OP_ALL, "RFC", "Clear reader flag and reader buffer, fetch one character from tape and load it into the reader buffer, and set the reader flag when done."},
|
||||||
|
// 6020 High Speed Perforated Tape Punch and Control
|
||||||
|
{ 06021, OP_ALL, "PSF", "Skip if punch flag is a 1"},
|
||||||
|
{ 06022, OP_ALL, "PCF", "Clear punch flag and punch buffer."},
|
||||||
|
{ 06024, OP_ALL, "PPC", "Load the punch buffer from bits 4 through 11 of the AC and punch the character. This instructions does not clear the punch flag or punch buffer. AC4-11 v PB -> PB"},
|
||||||
|
{ 06026, OP_ALL, "PLS", "Clear the punch flag, clear the bunch buffer, load the punch buffer from the content of bits 4 through 11 of the accumulator, punch the character, and set the punch flag to 1 when done."},
|
||||||
|
// 6030 Teletype Keyboard / Reader
|
||||||
|
{ 06031, OP_ALL, "KSF", "Skip if keyboard flag is a 1."},
|
||||||
|
{ 06032, OP_ALL, "KCC", "Clear AC and clear keyboard flag."},
|
||||||
|
{ 06034, OP_ALL, "KRS", "Read keyboard buffer static. This is a static command in that neither the AC nor the keyboard flag is cleared. TTI v AC4-11 -> AC4-11"},
|
||||||
|
{ 06036, OP_ALL, "KRB", "Clear AC, clear keyboard flag, and read the content of the keyboard buffer into the content of AC4-11."},
|
||||||
|
// 6040 Teletype Teleprinter / Punch
|
||||||
|
{ 06041, OP_ALL, "TSF", "Skip if teleprinter flag is a 1."},
|
||||||
|
{ 06042, OP_ALL, "TCF", "Clear teleprinter flag."},
|
||||||
|
{ 06044, OP_ALL, "TPC", "Load the TTO from the content of AC4-11 and print and/or punch the character."},
|
||||||
|
{ 06046, OP_ALL, "TLS", "Load the TTO from the content of AC4-11, clear the teleprinter flag, and print and/or punch the character."},
|
||||||
|
#ifdef VC8I
|
||||||
|
// 6050 Oscilloscope Display Type VC8/I [VC8/L]
|
||||||
|
{ 06051, OP_ALL, "DCX", "Clear X coordinate buffer"},
|
||||||
|
{ 06053, OP_ALL, "DXL", "Clear and load X coordinate buffer. AC2-11 -> YB"},
|
||||||
|
{ 06054, OP_ALL, "DIX", "Intensify the point defined by the content of the X and Y coordinate buffers."},
|
||||||
|
{ 06057, OP_ALL, "DXS", "Executes the combined functions of DXL followed by DIX"},
|
||||||
|
// 6060 (continued)
|
||||||
|
{ 06061, OP_ALL, "DCY", "Clear Y coordinate buffer"},
|
||||||
|
{ 06063, OP_ALL, "DYL", "Clear and load Y coordinate buffer. AC2-11 -> YB"},
|
||||||
|
{ 06064, OP_ALL, "DIY", "Intensify the point defined by the content of the X and Y coordinate buffers."},
|
||||||
|
{ 06067, OP_ALL, "DYS", "Executes the combined functions of DYL followed by DIY"},
|
||||||
|
// 6070 (continued)
|
||||||
|
{ 06071, OP_ALL, "DSF", "(Light Pen Type 370) Skip if display flag is a 1."},
|
||||||
|
{ 06072, OP_ALL, "DCF", "(Light Pen Type 370) Clear the display flag."},
|
||||||
|
{ 06074, OP_ALL, "DSB", "Zero brightness"},
|
||||||
|
{ 06075, OP_ALL, "DSB", "Set minimum brightness"},
|
||||||
|
{ 06076, OP_ALL, "DSB", "Set medium brightness"},
|
||||||
|
{ 06077, OP_ALL, "DSB", "Set maximum brightness"},
|
||||||
|
#endif
|
||||||
|
#ifdef KV8I
|
||||||
|
// 6050 Storage Tube Display Control, Type KV8/I [KV8/L]
|
||||||
|
{ 06051, OP_ALL, "SNC", "Senses the condition of the cursor interrupt flag. The flag produces an interrupt request when set by operation of the interrupt pushbutton on the joystick. The flag is initially cleared when the computer is started. As with all flag-sent instructions, SNC can be used under interrupt conditions to detect the source of the interrupt, or it can be used under interrupt on (ION) when the interrupt request has been caused by the operation of thecursor interrupt button. In a program running with the interrupt off, SNC can be used to ignore the cursor successive approximation subroutine in the program if a request for service has not been made from the joystick controller."},
|
||||||
|
{ 06052, OP_ALL, "CCF", "This instruction is used to clear the cursor flag after a request for service has been acknowledged by the program."},
|
||||||
|
// 6060 (continued)
|
||||||
|
{ 06062, OP_ALL, "SAC", "The analog comparator is set to compare the analog content of any one of six analog sources with the content of the digital-to-analog converter. The analog sources are chosen according to a 3-bit binary code. This code establishes the parameter for choosing the wanted register according to the content of AC2, AC3, and AC6."},
|
||||||
|
{ 06063, OP_ALL, "LDF", "This instruction is used to establish the mode in which a wanted graphic is to be produced according to a 2-bit binary code. This code determines whether the wanted vector will be linear absolute relative, whether the point plot mode will be used, or whether the cursor will be displayed. This code establishes the paramteres for these formats according to the content of AC2 and AC3. The LDF instruction must precede the LDX and LDY instructions."},
|
||||||
|
{ 06064, OP_ALL, "LDX", "The X-axis sample and hold register is loaded with the binary equivalent of the X-axis coordinate according to the contents of AC2-11. This data appears at the output of the digital-to-analog converter as the analog equivalent of the X-axis value of the binary word stored in the AC. The LDX instruction clears an existing ready flag and sets the ready flag after 100 +/- 20 us."},
|
||||||
|
{ 06065, OP_ALL, "LDY", "The Y-axis sample and hold register is loaded with the binary equivalent of the Y-axis coordinate according to the contents of AC2-11. This data appears at the output of the digital-to-analog converter as the analog equivalent of the binary word in the AC. The LDY instruction clears an existing ready flag and sets the ready flag after 100 +/- 20 us."},
|
||||||
|
{ 06066, OP_ALL, "EXC", "Used to execute the wanted vector according to the contents of AC2-4 and AC6-11. The parameter word establishes long or short formats, circular vectors, display erasure, reset of the integrators, and intensification of the vector. The EXC instruction clears an existing ready flag and sets the ready flag as follows: a) after 20 +/- 5 us for a point or vector continue; b) after 250 us for short vectors; c) after 4.05 ms for long vectors; d) after 500 ms for an erase."},
|
||||||
|
// 6070 (continued)
|
||||||
|
{ 06071, OP_ALL, "SRF", "Used to determine when the controller is ready to perform the next execute instruction. The ready flag produces an interrupt condition when set. The flag can be set by pressing the erase pushbutton on the VT01 unit. Normally, however, the state of this flag is determined by the controller. This flag is initially cleared when the computer is started and prior to an LDX, LDY, or EXC instruction."},
|
||||||
|
{ 06072, OP_ALL, "CRF", "This instruction clears the ready flag after a skip instruction has been acknowledged."},
|
||||||
|
{ 06073, OP_ALL, "SDA", "Used in the successive approximation subroutine to determine the digital equivalent of the selected analog holding register. This instruction is used with the SAC (6062) instruction."},
|
||||||
|
{ 06074, OP_ALL, "LDA", "This instruction is used to load the content of AC2-11. This instruction is used with DSA (6073) in the successive approximation subroutine to determine the digital value of the content of the selected analog holding register. Does not change flag states."},
|
||||||
|
#endif
|
||||||
|
// 6100 Memory Parity Type MP8/I [MP8/L]
|
||||||
|
// 6100 Automatic Restart Type KP8/I [KP8/L]
|
||||||
|
{ 06101, OP_ALL, "SMP", "(MP8/I) Skip if memory parity error flag = 0."},
|
||||||
|
{ 06102, OP_ALL, "SPL", "(KP8/I) Skip if power low"},
|
||||||
|
{ 06104, OP_ALL, "CMP", "(MP8/I) Clear memory parity error flag."},
|
||||||
|
// 6110 Multiple Asynchronous Serial Line Interface Unit, Type DC02D
|
||||||
|
{ 06111, OP_ALL, "MKSF", "Skip the next instruction if the keyboard flag is set."},
|
||||||
|
{ 06112, OP_ALL, "MKCC", "Clear the keyboard and reader flags; clear the AC."},
|
||||||
|
{ 06113, OP_ALL, "MTPF", "(DC02A) Transfer status of teleprinter flags to AC 0-3."},
|
||||||
|
{ 06114, OP_ALL, "MKRS", "Transfer the shift register contents to AC 4-11."},
|
||||||
|
{ 06115, OP_ALL, "MINT", "(DC02A) Interrupt on if AC 11 is set (interrupt request, if any flags)."},
|
||||||
|
{ 06116, OP_ALL, "MKRB", "Clear the keyboard and reader flags, clear the AC, trasnfer the shift register contents to AC 4-11 (MKCC and MKRS combined)."},
|
||||||
|
{ 06117, OP_ALL, "MTON", "Transfer AC0-3 to selection register (SELF) (select stations when bit is set)."},
|
||||||
|
// 6120 Multiple Asynchronous Line Unit, Type DC02A
|
||||||
|
{ 06121, OP_ALL, "MTSF", "Skip the next instruction if the teleprinter flag is set."},
|
||||||
|
{ 06122, OP_ALL, "MTCF", "Clear the teleprinter flag."},
|
||||||
|
{ 06123, OP_ALL, "MTKF", "Transfer status of keyboard flags to AC 0-3."},
|
||||||
|
{ 06124, OP_ALL, "MTPC", "Load AC4-11 into the shift register (begin print/punch)."},
|
||||||
|
{ 06125, OP_ALL, "MINS", "Skip if the interrupt request is active (if interrupt is on and any flag is raised)."},
|
||||||
|
{ 06126, OP_ALL, "MTLS", "Clear the teleprinter flag and load AC4-11 into the shift register (MTCF and MTPC combined)"},
|
||||||
|
{ 06127, OP_ALL, "MTRS", "Trasnfer the status of the selection register to AC 0-3."},
|
||||||
|
// 6130 Real Time Clock, Type KW8/I [KW8/L]
|
||||||
|
{ 06132, OP_ALL, "CCFF", "The flag, flag buffer, clock enable, and interrupt enable flip-flops are cleared. This disables the real-time clock."},
|
||||||
|
{ 06133, OP_ALL, "CSCF", "When the flag flip-flop has been set by a clock pulse, the flag buffer flip-flop is set to a 1. Upon execution of this instruction, an IO BUS IN SKIP is generated if the flag is set. The content of the PC is incremented by 1, so that the next sequential instruction is skipped. The flag flip-flop is then cleared. If the flag flip-flop has not been set, no skip is generated nor is the flag flip-flop cleared."},
|
||||||
|
{ 06134, OP_ALL, "CRCA", "The output buffer is gated to the I/O BUS during IOP4, and a CLK AC CLR signal generated. This register contains the last count in the count register. The transfer from the count register is synchronized with this instruction so that a transfer that would occur during this instruction is not made."},
|
||||||
|
{ 06136, OP_ALL, "CCEC", "All clock control flip-flops are first cleared, then the clock enable flip-flop is set. For the variable frequency clock, the frequency source is enabled synchronously with program operation. With all clocks, the data input to the flag is enabled after IOP2 time. This represents an 800-ns mask, after the clock is enabled."},
|
||||||
|
{ 06137, OP_ALL, "CECI", "All clock control flip-flops are cleared, then the clock enable, and interrupt enable flip-flops are set. The clock enable flip-flop is described with the CCEC instruction. The interrupt enable flip-flop allows an IO BUS IN INT signal when the flag is set."},
|
||||||
|
// 6140
|
||||||
|
// 6150
|
||||||
|
// 6160
|
||||||
|
// 6170
|
||||||
|
// 6200 through 6277 Memory Extension Control Type MC8/I [MC8/L]
|
||||||
|
{ 06201, OP_ALL, "CDF 0^10", "Change to data field 0."},
|
||||||
|
{ 06202, OP_ALL, "CIF 0^10", "Prepare to change to instruction field 0 at next JMP or JMS instruction."},
|
||||||
|
{ 06204, OP_ALL, "CINT", "Clear user interrupt."},
|
||||||
|
// 6210
|
||||||
|
{ 06211, OP_ALL, "CDF 1^10", "Change to data field 1."},
|
||||||
|
{ 06212, OP_ALL, "CIF 1^10", "Prepare to change to instruction field 1 at next JMP or JMS instruction."},
|
||||||
|
{ 06214, OP_ALL, "RDF", "Read data field into AC6-8. Bit 0-5 and 9-11 of the AC are not affected."},
|
||||||
|
// 6220
|
||||||
|
{ 06221, OP_ALL, "CDF 2^10", "Change to data field 2."},
|
||||||
|
{ 06222, OP_ALL, "CIF 2^10", "Prepare to change to instruction field 2 at next JMP or JMS instruction."},
|
||||||
|
{ 06224, OP_ALL, "RIF", "Read instruction field into AC6-8. Bit 0-5 and 9-11 of the AC are not affected."},
|
||||||
|
// 6230
|
||||||
|
{ 06231, OP_ALL, "CDF 3^10", "Change to data field 3."},
|
||||||
|
{ 06232, OP_ALL, "CIF 3^10", "Prepare to change to instruction field 3 at the next JMP or JMS instruction."},
|
||||||
|
{ 06234, OP_ALL, "RIB", "Read interrupt buffer. The instruction field and data field stored during an interrupt are read into AC6-8 and AC9-11."},
|
||||||
|
// 6240
|
||||||
|
{ 06241, OP_ALL, "CDF 4^10", "Change to data field 4."},
|
||||||
|
{ 06242, OP_ALL, "CIF 4^10", "Prepare to change to instruction field 4 at the next JMP or JMS instruction."},
|
||||||
|
{ 06244, OP_ALL, "RMF", "Restore memory field."},
|
||||||
|
// 6250
|
||||||
|
{ 06251, OP_ALL, "CDF 5^10", "Change to data field 5."},
|
||||||
|
{ 06252, OP_ALL, "CIF 5^10", "Prepare to change to instruction field 5 at the next JMP or JMS instruction."},
|
||||||
|
{ 06254, OP_ALL, "SINT", "Skip on user interrupt."},
|
||||||
|
// 6260
|
||||||
|
{ 06261, OP_ALL, "CDF 6^10", "Change to data field 6."},
|
||||||
|
{ 06262, OP_ALL, "CIF 6^10", "Prepare to change to instruction field 6 at the next JMP or JMS instruction."},
|
||||||
|
{ 06264, OP_ALL, "CUF", "Clear the user mode flag."},
|
||||||
|
// 6270
|
||||||
|
{ 06271, OP_ALL, "CDF 7^10", "Change to data field 7."},
|
||||||
|
{ 06272, OP_ALL, "CIF 7^10", "Prepare to change to instruction field 7 at the next JMP or JMS instruction."},
|
||||||
|
{ 06274, OP_ALL, "SUF", "Set the user mode flag at the next JMP or JMS instruction."},
|
||||||
|
// 6400 Data Communications System 680/I
|
||||||
|
{ 06401, OP_ALL, "TTINCR", "This instruction causes the contents of the line register to be incremented by 1. This command, when microprogrammed with a TTO command is executed."},
|
||||||
|
{ 06402, OP_ALL, "TTI", "Causes a JMS to be executed (N+3) if the R register does not equal 0 and either the line hold bit of the selected line (specified by bits 2-8 of the LSW) is in the 1 state, or as a result of jamming the line state into and shifting the CAW; bit 11 of the CAW is a 1."},
|
||||||
|
{ 06404, OP_ALL, "TTO", "Clears the link and shifts the link and accumulator one bit position to the right. Bit 11 of the accumulator is shifted into the line unit specified by the line register. The previuos contents (1 bit) of the selected line unit is lost."},
|
||||||
|
// 6410
|
||||||
|
{ 06411, OP_ALL, "TTCL", "The command sets the contents of the line register to 0."},
|
||||||
|
{ 06412, OP_ALL, "TTSL", "The contents of AC5-11 are ORed into the line register."},
|
||||||
|
{ 06413, OP_ALL, "TTLL", "The contents of AC5-11 are trasnferred into the line register. This is a microprogram of TTCL and TTSL."},
|
||||||
|
{ 06414, OP_ALL, "TTRL", "The contents of the line register are ORed into AC5-11. The AC must be 0 for a true transfer."},
|
||||||
|
// 6420
|
||||||
|
{ 06421, OP_ALL, "T1skip", "(Data Communications System 680/I) Clock Control Instruction: Causes the program to skip the next instruction if clock flag 1 is in the 1 state. To clear the flag, either T1on or T1off can be used."},
|
||||||
|
{ 06422, OP_ALL, "T1off", "(Data Communications System 680/I) Clock Control Instruction: Inhibits clock 1 from setting its flag. This instruction also sets the flag to the 0 state."},
|
||||||
|
{ 06424, OP_ALL, "T1on", "(Data Communications System 680/I) Clock Control Instruction: Enables clock 1 to set its flag at the predetermined lcock rate. The flag in the 1 state causes a program interrupt when the interrupt is enabled. This instruction also sets the flag to the 0 state."},
|
||||||
|
// 6430
|
||||||
|
{ 06431, OP_ALL, "T2skip", "(Data Communications System 680/I) same as T1skip except for clock 2"},
|
||||||
|
{ 06432, OP_ALL, "T2off", "(Data Communications System 680/I) same as T1off except for clock 2"},
|
||||||
|
{ 06434, OP_ALL, "T2on", "(Data Communications System 680/I) same as T1on except for clock 2"},
|
||||||
|
#ifdef PT08
|
||||||
|
// 6440 Asynchronous Serial Line Interface, Type PT08
|
||||||
|
{ 06441, OP_ALL, "TSFXXX", "Skip if teleprinter/punch 3 flag is a 1."},
|
||||||
|
{ 06442, OP_ALL, "TCFXXX", "Clear teleprinter/punch 3 flag."},
|
||||||
|
{ 06444, OP_ALL, "TPCXXX", "Load teleprinter 3 buffer (TTOX) with AC4-11 and print/punch the character."},
|
||||||
|
{ 06446, OP_ALL, "TLSXXX", "Load TTOX with AC4-11, 3 flag, print/punch the character and clear teleprinter/punch."},
|
||||||
|
{ "6450"},
|
||||||
|
{ 06451, OP_ALL, "KSFXXX", "Skip if keyboard/reader 3 flag is a 1."},
|
||||||
|
{ 06452, OP_ALL, "KCCXXX", "Clear AC and keyboard/reader 3 flag."},
|
||||||
|
{ 06454, OP_ALL, "KRSXXX", "Read keyboard/reader 3 buffer (TTI3) static. TTI3 is loaded into AC4-11 by an OR transfer."},
|
||||||
|
{ 06456, OP_ALL, "KRBXXX", "Clear the AC, read TTI3 into AC4-11, and clear keyboard 3 flag."},
|
||||||
|
{#else "PT08"},
|
||||||
|
{ 06441, OP_ALL, "T3skip", "(Data Communications System 680/I) same as T1skip except for clock 3"},
|
||||||
|
{ 06442, OP_ALL, "T3off", "(Data Communications System 680/I) same as T1off except for clock 3"},
|
||||||
|
{ 06444, OP_ALL, "T3on", "(Data Communications System 680/I) same as T1on except for clock 3"},
|
||||||
|
{ 06451, OP_ALL, "T4skip", "(Data Communications System 680/I) same as T1skip except for clock 4"},
|
||||||
|
{ 06452, OP_ALL, "T4off", "(Data Communications System 680/I) same as T1off except for clock 4"},
|
||||||
|
{ 06454, OP_ALL, "T4on", "(Data Communications System 680/I) same as T1on except for clock 4"},
|
||||||
|
#endif
|
||||||
|
{ 06461, OP_ALL, "TTRINC", "(Data Communications System 680/I) This command causes the contents of the R register to be incremented by 1. Because it is loaded with a 2's complement number, the result is a subtract. This instruction can be microprogrammed with TTRR."},
|
||||||
|
{ 06464, OP_ALL, "TTRR", "(Data Communications System 680/I) This command reads the contents of the R register into AC7-11. The contents of the AC must be 0s before issuing this instruction. This instruction, when microprogrammed with TTINCR, causes the incremented results to be read into the AC."},
|
||||||
|
// 6470
|
||||||
|
{ 06471, OP_ALL, "TTCR", "(Data Communications System 680/I) This command causes the R register to be set to 0"},
|
||||||
|
{ 06472, OP_ALL, "TTLR", "(Data Communications System 680/I) This command causes the contents of AC7-11 to be trasnferred into the R register."},
|
||||||
|
// 6500 Incremental Plotter and Control Type VP8/I
|
||||||
|
{ 06501, OP_ALL, "PLSF", "Skip if plotter flag is a 1."},
|
||||||
|
{ 06502, OP_ALL, "PLCF", "Clear plotter flag."},
|
||||||
|
{ 06504, OP_ALL, "PLPU", "Plotter pen up. Raise pen off of paper."},
|
||||||
|
// 6510
|
||||||
|
{ 06511, OP_ALL, "PLPR", "Plotter pen right."},
|
||||||
|
{ 06512, OP_ALL, "PLDU", "Plotter drum (paper) upward"},
|
||||||
|
{ 06514, OP_ALL, "PLDD", "Plotter drum (paper) downward."},
|
||||||
|
// 6520
|
||||||
|
{ 06521, OP_ALL, "PLPL", "Plotter pen left."},
|
||||||
|
{ 06522, OP_ALL, "PLUD", "Plotter drum (paper) upward. Same as 6512"},
|
||||||
|
{ 06524, OP_ALL, "PLPD", "Plotter pen down. Lower pen on to paper."},
|
||||||
|
#ifdef AF01A
|
||||||
|
// 6530 General Purpose Converter and Multiplexer Control Type AF01A (this option is mutually exclusive with AF04A)
|
||||||
|
{ 06531, OP_ALL, "ADSE", "Skip if A/D converter flag is a 1."},
|
||||||
|
{ 06532, OP_ALL, "ADCV", "Clear A/D converter flag and convert input voltage to a digital number, flag will set to 1 at end of conversion. Number of bits in converted number determined by switch setting, 11 bits maximum."},
|
||||||
|
{ 06534, OP_ALL, "ADRB", "Read A/D converter buffer into AC, left justified, and clear flag."},
|
||||||
|
// 6540
|
||||||
|
{ 06541, OP_ALL, "ADCC", "Clear multiplexer channel address register."},
|
||||||
|
{ 06542, OP_ALL, "ADSC", "Set up multiplexer channel as per AC6-11. Maximum of 64 single ended or 32 differntial input channels."},
|
||||||
|
{ 06544, OP_ALL, "ADIC", "Index multiplexer channel address (present address + 1). Upon reaching address limit, increment will cause channel 00 to be selected."},
|
||||||
|
#endif // AF01A
|
||||||
|
#ifdef AF04A
|
||||||
|
// 6530 Guarded Scanning Digital Voltmeter Type AF04A (this option is mutually exclusive with AF01A)
|
||||||
|
{ 06531, OP_ALL, "VSDR", "Skip if data ready flag is a 1."},
|
||||||
|
{ 06532, OP_ALL, "VRD", "Selected byte of voltmeter is transferred to the accumulator and the data ready flag is cleared."},
|
||||||
|
{ 06534, OP_ALL, "VBA", "BYTE ADVANCE command requests next twelve bits, data ready flag is set."},
|
||||||
|
// 6540
|
||||||
|
{ 06541, OP_ALL, "VCNV", "The contents of the accumulator are transferred to the AF04A channel address register. Analog signal on selected channel is automatically digitized."},
|
||||||
|
{ 06542, OP_ALL, "VSEL", "The contents of the accumulator are transferred to the AF04A control register."},
|
||||||
|
{ 06544, OP_ALL, "VINX", "The last channel address is incremented by one and the analog signal on the selected channel is automatically digitized."},
|
||||||
|
#endif // AF04A
|
||||||
|
// 6550
|
||||||
|
#ifdef AA01A
|
||||||
|
{ 06551, OP_ALL, "DAL1", "(AA01A) The character in the accumulator is loaded into the channel 1 buffer. The DAC then converts the buffered value to the analog equivalent. NOTE: Similar instructions for DAL2 and DAL3 load respective DACs."},
|
||||||
|
#else // AA01A
|
||||||
|
#ifdef AA05
|
||||||
|
{ 06551, OP_ALL, "CLDA", "The address register in the AA05/AA07 is cleared."},
|
||||||
|
#else // AA05
|
||||||
|
#endif // AA05
|
||||||
|
#endif // AA01A
|
||||||
|
{ 06552, OP_ALL, "LDAD", "(AA05/AA07) The address register in the AA05/AA07 is loaded with the contents of AC0-5."},
|
||||||
|
// 6560
|
||||||
|
{ 06562, OP_ALL, "LDAR", "(AA05/AA07) The buffer (input buffer, if the channel is double-buffered) of the DAC is loaded from AC0-9."},
|
||||||
|
{ 06564, OP_ALL, "UPDT", "(AA05/AA07) The contents of the input buffers of all double-buffered channels are trasnferred to their respective output buffers. The input buffer is not affected by this instruction."},
|
||||||
|
// 6570
|
||||||
|
#ifdef AF04A
|
||||||
|
{ 06571, OP_ALL, "VSCC", "SAMPLE CURRENT CHANNEL when required to digitize analog signal on current channel repeatedly (AF04A)"},
|
||||||
|
#else // AF04A
|
||||||
|
#ifdef AC01A
|
||||||
|
{ 06571, OP_ALL, "HRAN", "The contents of AC3-5 are trasnferred to the channel address register (CHAR). The 3-bit code is decoded to address any of the 8 channels."},
|
||||||
|
#else // AC01A
|
||||||
|
#endif // AC01A
|
||||||
|
#endif // AF04A
|
||||||
|
#ifdef AC01A
|
||||||
|
{ 06572, OP_ALL, "HSIM", "Simultaneously places all 8 channels into the hold mode."},
|
||||||
|
#else // AC01A
|
||||||
|
#endif // AC01A
|
||||||
|
{ 06574, OP_ALL, "SAMP", "(AA01A) Places all 8 channels into the sample (or track) mode."},
|
||||||
|
#ifdef DP01AA
|
||||||
|
// 6600 Synchronous Modem Interface, Type DP01AA
|
||||||
|
{ 06601, OP_ALL, "TAC", "Causes the contents of the AC (6, 7, 8, or 9 bits right-justified) to be transferred into the TB."},
|
||||||
|
{ 06602, OP_ALL, "CTF", "Resets the trasnmit flag. If trasnmit active flag is set, CTF also causes the program to skip the next instruction."},
|
||||||
|
{ 06604, OP_ALL, "CIM", "Resets the transmit logic idle mode (IM) flip-flop."},
|
||||||
|
{ 06611, OP_ALL, "STF", "Causes the program to skip the next instruction if the transmit flag is in the 0 state. When the transmit flag is in the 1 state, the trasnmit buffer register (TB) is ready to accept another character."},
|
||||||
|
{ 06612, OP_ALL, "RRB", "Transfers the contents of the receiver buffer (RB) (6, 7, 8, or 9 bits, right-justified) to the computer AC. RRB also resets the receive flag."},
|
||||||
|
{ 06614, OP_ALL, "SIM", "Sets the transmit idle mode (IM) flip-flop."},
|
||||||
|
{ 06621, OP_ALL, "SEF", "Causes the program to skip the next instruction if the receive end flag is 0. The receive end flag slip-flop is set when the receive logic has stopped receiving serial data from the communications equipment due to termination of th SERIAL CLOCK RECEIVE pulse train."},
|
||||||
|
{ 06622, OP_ALL, "CEF", "Clears the receive end flag"},
|
||||||
|
{ 06624, OP_ALL, "SRE", "Sets the ring enable (RE) flip-flop to a 1, which permits the ring flag to request a program interrupt."},
|
||||||
|
{ 06631, OP_ALL, "SRI", "Causes the program to skip the next instruction if the ring flag is 0. The ring flag is set when a ring input is received."},
|
||||||
|
{ 06632, OP_ALL, "CRF", "Clears the ring flag."},
|
||||||
|
{ 06634, OP_ALL, "STR", "Sets the terminal read (TR) flip-flop to the 1 state. This causes the terminal ready lead to the modem to be set on the ON state. The state changes to OFF for CTR"},
|
||||||
|
{ 06641, OP_ALL, "SSR", "Causes the program to skip the next instruction if the data-set-ready lead from the modem is in the ON state."},
|
||||||
|
{ 06642, OP_ALL, "CTR", "Clears the terminal ready (TR) flip-flop (see STR)"},
|
||||||
|
{ 06644, OP_ALL, "CRE", "Clears the ring enable (RE) flip-flop."},
|
||||||
|
{ 06651, OP_ALL, "SRF", "Causes the program to skip the next instruction if the receive flag is 0. The flag is set when a received character is ready for trasnfer to the AC and the flag is cleared when an RRB instruction is issued."},
|
||||||
|
{ 06652, OP_ALL, "CRA", "Clears the receive active (RA) flip-flop, taking the receive logic out of the active state. This inhibits any more receive flags until a new sync character is received."},
|
||||||
|
{ 06654, OP_ALL, "XOB", "Causes an exclusive OR of the AC with the buffer register (BR)."},
|
||||||
|
{ 06661, OP_ALL, "COB", "Clears the XOR buffer."},
|
||||||
|
{ 06662, OP_ALL, "ROB", "Transfers the buffer register (BR) content to the AC."},
|
||||||
|
{ 06664, OP_ALL, "IOB", "Transfers 1s from the AC to the buffer register (BR)."},
|
||||||
|
#else // DP01AA
|
||||||
|
#ifdef DF32
|
||||||
|
// 6600 Random Access Disc File (type DF32)
|
||||||
|
{ 06601, OP_ALL, "DCMA", "Clears memory address register, parity erorr and completion flags. This instruction clears the disk memory request flag and interrupt flags."},
|
||||||
|
{ 06603, OP_ALL, "DMAR", "The contents of the AC are loaded into the disk memory address register and the AC is cleared. Begin to read information from the disk into the specified core location. Clears parity error and completion flags. Clears interrupt flags."},
|
||||||
|
{ 06605, OP_ALL, "DMAW", "The contents of the AC are loaded into the disk memory address register and the AC is cleared. Begin to write information into the disk from the specified core location. Clears parity error and completion flags."},
|
||||||
|
// 6610
|
||||||
|
{ 06611, OP_ALL, "DCEA", "Clears the disk extended address and memory address extension register."},
|
||||||
|
{ 06612, OP_ALL, "DSAC", "Skips next instruction if address confirmed flag is a 1. AC is cleared."},
|
||||||
|
{ 06615, OP_ALL, "DEAL", "The disk extended-address extension registers are cleared and loaded with the track data held in the AC."},
|
||||||
|
{ 06616, OP_ALL, "DEAC", "Clear the AC then loads the contents of the disk extended-address register into the AC to allow program evaluation. Skip next instruction if address confirmed flag is a 1."},
|
||||||
|
// 6620
|
||||||
|
{ 06621, OP_ALL, "DFSE", "Skip next instruction if the completion flag is a 1. Indicates data transfer is complete."},
|
||||||
|
{ 06626, OP_ALL, "DMAC", "Clear the AC then loads contents of disk memory address register into the AC to allow program evaluation."},
|
||||||
|
#endif // DF32
|
||||||
|
#ifdef RF08
|
||||||
|
// 6600 Disk File and Control, Type RF08/Expander Disk File, Type RS08
|
||||||
|
// 6610
|
||||||
|
{ 06611, OP_ALL, "DCIM", "Clear the disk interrupt enable and core memory address extension register."},
|
||||||
|
{ 06615, OP_ALL, "DIML", "Clear the interrupt enable and memory address extension register, then load the interrupt enable and memory address extension registers with data held in the AC. Then clear the AC. NOTE: Transfers cannot occur across memory fields. Attempts to do so will cause the transfer to "wrap around" within the specified memory field."},
|
||||||
|
{ 06616, OP_ALL, "DIMA", "Clear the AC. Then load the contents of the status register (STR) into the AC to allow program evaluation."},
|
||||||
|
// 6620
|
||||||
|
{ 06621, OP_ALL, "DFSE", "Skip next instruction if there is a parity error, data request late, write lock status, or nonexistent disk flag set."},
|
||||||
|
{ 06623, OP_ALL, "DISK", "If either the error or data completion flag (or both) is set, the next instruction is skipped."},
|
||||||
|
#endif // RF08
|
||||||
|
// 6630 Card Reader and Control Type CR8/I [CR8/L] (see also 6670)
|
||||||
|
{ 06631, OP_ALL, "RCSF", "Generates an IOP pulse (IOP 1) to test the data-ready flag output. If the data ready flag is 1, the next sequential program instruction is skipped."},
|
||||||
|
{ 06632, OP_ALL, "RCRA", "Generates an IOP pulse (IOP 2) to read the alphanumeric data at the control-logic buffer register and clear the data ready flag."},
|
||||||
|
{ 06634, OP_ALL, "RCRB", "Generates an IOP pulse (IOP 4) to read the BCD data at the control logic buffer register and clear the data ready flag."},
|
||||||
|
#ifdef RF08
|
||||||
|
// 6640
|
||||||
|
{ 06641, OP_ALL, "DCXA", "Clear the high order 8-bits of the disk address register (DAR)."},
|
||||||
|
{ 06643, OP_ALL, "DXAL", "Clear the high order 8 bits of the DAR. Then load the DAR from data stored in the AC. Then clear the AC."},
|
||||||
|
{ 06645, OP_ALL, "DXAC", "Clear the AC; then load the contents of the high order 8-bit DAR into the AC."},
|
||||||
|
{ 06646, OP_ALL, "DMMT", "For maintenance purposes only with the appropriate maintenance cable connections and the disk disconnected from the RS08 logic, the (given) standard signals may be generated by IOT 6646 and associated AC bits. The AC is cleared and the maintenance register is initiated by issuing an IOT 6601 command."},
|
||||||
|
#else // RF08
|
||||||
|
// 6640
|
||||||
|
#endif // RF08
|
||||||
|
// 6650 Automatic Line Printer and Control Type 645
|
||||||
|
{ 06651, OP_ALL, "LSE", "Skip if line printer error flag is a 1."},
|
||||||
|
{ 06652, OP_ALL, "LCB", "Clear both sections of the printing buffer."},
|
||||||
|
{ 06654, OP_ALL, "LLB", "Load printing buffer from the content of AC6-11 and clear the AC"},
|
||||||
|
// 6660 Automatic Line Printer and Control Type 645 (continued)
|
||||||
|
{ 06661, OP_ALL, "LSD", "Skip if the printer done flag is a 1."},
|
||||||
|
{ 06662, OP_ALL, "LCF", "Clear line printer done and error flags."},
|
||||||
|
{ 06664, OP_ALL, "LPR", "Clear the format register, load the format register from the content of AC9-11, print the line contained in the section of the printer buffer loaded last, clear the AC, and advance the paper in accordance with the selected channel of the format tape if the content of AC8=1. If the content of AC8=0, the line is printed and paper advance is inhibited."},
|
||||||
|
#endif // DP01AA
|
||||||
|
// 6670 Card Reader and Control Type CR8/I [CR8/L] (see also 6630)
|
||||||
|
{ 06671, OP_ALL, "RCSD", "Generates an IOP pulse (IOP 1) to test the card-done flag output. If the card done flag is 1, the next sequential program instruction is skipped."},
|
||||||
|
{ 06672, OP_ALL, "RCSE", "Generates an IOP pulse (IOP 2) to advance the card, clear the card done flag, and produce a skip flag is reader is ready. If skip flag is generated, the next sequential program instruction is skipped."},
|
||||||
|
{ 06674, OP_ALL, "RCRD", "Generates an IOP pulse (IOP 4) to clear the card done flag."},
|
||||||
|
#ifdef TA8A
|
||||||
|
// 6700 -> 6707 TU60 DECassette Controller TA8A
|
||||||
|
{ 06700, OP_ALL, "KCLR", "Clear All; clear the status A and B register"},
|
||||||
|
{ 06701, OP_ALL, "KSDR", "Skip the next instruction if the data flag is set during read or write operations"},
|
||||||
|
{ 06702, OP_ALL, "KSEN", "Skip the next instruction if any of the following are true: a) tape is at EOT/BOT, b) the TU60 is not ready or the selected drive is empty"},
|
||||||
|
{ 06703, OP_ALL, "KSBF", "Skip the next instruction if the ready flag is set"},
|
||||||
|
{ 06704, OP_ALL, "KLSA", "Load status A from AC4-AC11, clear the AC, and load the complement of status A back into the AC"},
|
||||||
|
{ 06705, OP_ALL, "KSAF", "Skip on any flag or error condition"},
|
||||||
|
{ 06706, OP_ALL, "KGOA", "Assert the contents of the status A register and transfer data into the AC during a read operation or out of the AC to the Read/Write buffer during a write operation. This instruction has three functions: a) enables the command in the status A register to be executed by the TU60, b) for read operations, the first KGOA instruction causes the tape to start moving, and when the data flag sets, a second KGOA transfers the first byte from the read/write buffer to the AC. The data flag sets after each 8-bit byte is read from the TU60. c) for write operations, the status A register is set up for a write, and the AC contains the first byte to be written on tape. When the KGOA instruction is executed, the tape starts to move and the first byte is transferred to the TU60."},
|
||||||
|
{ 06707, OP_ALL, "KRSB", "Transfer the contents of the status B register into AC4-AC11."},
|
||||||
|
#endif
|
||||||
|
#ifdef TC58
|
||||||
|
// 6700 Automatic Magnetic Tape Control Type TC58
|
||||||
|
{ 06701, OP_ALL, "MTSF", "Skip on error flag or magnetic tape flag. The status of the error flag (EF) and the magnetic tape flag (MTF) are sampled. If either or both are set to 1, the content of the PC is incremented by one to skip the next sequential instruction."},
|
||||||
|
{ 06702, OP_ALL, "6702", "(no mnemonic assigned) Clear the accumulator."},
|
||||||
|
{ 06704, OP_ALL, "6704", "(no mnemonic assigned) Inclusively OR the contents of the status register into AC0-11"},
|
||||||
|
{ 06706, OP_ALL, "MTRS", "Read the contents of the status register into AC0-11."},
|
||||||
|
// 6710
|
||||||
|
{ 06711, OP_ALL, "MTCR", "Skip on tape control ready (TCR). If the tape control is ready to receive a command, the PC is incremented by one to skip the next sequential instruction."},
|
||||||
|
{ 06712, OP_ALL, "MTAF", "Clear the status and command registers, and the EF and MTF if tape control ready. If tape control not ready, clears MTF and EF flags only."},
|
||||||
|
{ 06714, OP_ALL, "MTCM", "Inclusively OR the contents of AC0-5, AC9-11 into the command register; JAM transfer bits 6, 7, 8 (command function)"},
|
||||||
|
{ 06716, OP_ALL, "MTLC", "Load the contents of AC0-1j1 into the command register."},
|
||||||
|
// 6720
|
||||||
|
{ 06721, OP_ALL, "MTTR", "Skip on tape transport ready (TTR). The next sequential instruction is skipped if the tape transport is ready."},
|
||||||
|
{ 06722, OP_ALL, "MTGO", "Set "go" bit to execute command in the command register if command is legal."},
|
||||||
|
{ 06724, OP_ALL, "MTRC", "Inclusively OR the contents of the contents of the command register into AC0-11."},
|
||||||
|
#endif // TC58
|
||||||
|
#ifdef TR02
|
||||||
|
// 6700 Incremental Magnetic Tape Controller, Type TR02
|
||||||
|
{ 06701, OP_ALL, "IRS", "When data is ready to be strobed into the AC from the read buffer (RB), the PC is incremented by one to skip the next sequential instruction. The read done flag is cleared only if the skip occurs."},
|
||||||
|
{ 06702, OP_ALL, "ISR", "The content of the status register (STR) is read into AC0-8. The AC should be cleared before it is read by this instruction."},
|
||||||
|
{ 06703, OP_ALL, "IWS", "If the write done flag is set, the next instruction is skipped and the write done flag is cleared."},
|
||||||
|
{ 06704, OP_ALL, "IMC", "The move command decoded from AC0-2 is generated. This instruction also clears the read done, write done, and gap detect flags. The indicated flag is set when the command has been executed."},
|
||||||
|
{ 06705, OP_ALL, "IGS", "If the gap detect flag is set, the next instruction is skipped and the gap detect flag is cleared."},
|
||||||
|
{ 06706, OP_ALL, "IWR", "The contents of the AC are loaded into the tape input data buffer (WB) and a write step command is generated. The write done flag is set when writing is completed."},
|
||||||
|
{ 06707, OP_ALL, "IRD", "The AC is cleared and the content of the read buffer (RB) is loaded into the AC. Data bits are transferred into AC6-11 (7-track) or AC4-11 (9-track). Parity error is transferred into AC0 which is 0 if there is no parity error."},
|
||||||
|
// 6710
|
||||||
|
{ 06711, OP_ALL, "IRSA", "When data is ready to be strobed into the AC from the read buffer (RB), the PC is incremented by one to skip the next sequential instruction. The read done flag is cleared only if the skip occurs."},
|
||||||
|
{ 06712, OP_ALL, "ISRA", "The content of the status register (STR) is read into AC0-8. The AC should be cleared before it is read by this instruction."},
|
||||||
|
{ 06713, OP_ALL, "IWSA", "If the write done flag is set, the next instruction is skipped and the write done flag is cleared."},
|
||||||
|
{ 06714, OP_ALL, "IMCA", "The move command decoded from AC0-2 is generated. This instruction also clears the read done, write done, and gap detect flags. The indicated flag is set when the command has been executed."},
|
||||||
|
{ 06715, OP_ALL, "IGSA", "If the gap detect flag is set, the next instruction is skipped and the gap detect flag is cleared."},
|
||||||
|
{ 06716, OP_ALL, "IWRA", "The contents of the AC are loaded into the tape input data buffer (WB) and a write step command is generated. The write done flag is set when writing is completed."},
|
||||||
|
{ 06717, OP_ALL, "IRDA", "The AC is cleared and the content of the read buffer (RB) is loaded into the AC. Data bits are transferred into AC6-11 (7-track) or AC4-11 (9-track). Parity error is transferred into AC0 which is 0 if there is no parity error."},
|
||||||
|
// 6720
|
||||||
|
#endif // TC58
|
||||||
|
// 6730
|
||||||
|
// 6740
|
||||||
|
// 6750
|
||||||
|
// 6760 DECtape Transport Type TU55 and DECtape Control Type TC01
|
||||||
|
{ 06761, OP_ALL, "DTRA", "The content of status register A is read into AC0-9 by an OR transfer. The bit assignments are: AC0-2 = Transport unit select numnber; AC3-4 = Motion; AC5 = Mode; AC6-8 = Function; AC9 = Enable/disable DECtape control flag."},
|
||||||
|
{ 06762, OP_ALL, "DCTA", "Clear status register A. All flags undisturbed."},
|
||||||
|
{ 06764, OP_ALL, "DTXA", "Status register A is loaded by an exclusive OR transfer from the content of the AC, and AC10 and AC11 are sampled. If AC10 = 0, the error flags are cleared. If AC11 = 0, the DECtape control flag is cleared."},
|
||||||
|
// 6770
|
||||||
|
{ 06771, OP_ALL, "DTSF", "Skip if error flag is a 1 or if DECtape control flag is a 1."},
|
||||||
|
{ 06772, OP_ALL, "DTRB", "The content of status register B is read into the AC by an OR transfer. The bit assignments are: AC0 = Error flag; AC1 = Mark track error; AC2 = End of tape ; AC3 = Select error ; AC4 = Parity error; AC5 = Timing error; AC6-8 = Memory field; AC9-10 = Unused; AC11 = DECtape flag."},
|
||||||
|
{ 06774, OP_ALL, "DTLB", "The memory field portion of status register B is loaded from the content of AC6-8."},
|
||||||
|
};
|
||||||
|
|
||||||
848
d8tape/main.c
Normal file
848
d8tape/main.c
Normal file
@ -0,0 +1,848 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* main.c
|
||||||
|
*
|
||||||
|
* (C) Copyright 2000 by Robert Krten, all rights reserved.
|
||||||
|
* Please see the LICENSE file for more information.
|
||||||
|
*
|
||||||
|
* This module represents the main module for the RIM/BIN
|
||||||
|
* dumper/disassembler/converter/reverse engineering tool.
|
||||||
|
*
|
||||||
|
* This program will dump a RIM/BIN-formatted image to stdout, or
|
||||||
|
* convert a tape from one format to another, or clean up a tape,
|
||||||
|
* or disassemble a tape with reverse-engineering aids.
|
||||||
|
*
|
||||||
|
* 2001 01 07 R. Krten created
|
||||||
|
* 2003 12 16 R. Krten added disassembler
|
||||||
|
* 2003 12 17 R. Krten made it RIM/BIN aware.
|
||||||
|
* 2007 10 25 R. Krten added reverse-engineering features
|
||||||
|
* 2007 11 04 R. Krten fixed header skip logic (see dumptape())
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __USAGE
|
||||||
|
|
||||||
|
%C [options] papertapefile [papertapefile...]
|
||||||
|
|
||||||
|
where [options] are optional parameters chosen from:
|
||||||
|
-b generate a BIN-formatted output (adds ".bin")
|
||||||
|
-d suppress disassembly (useful for conversion-only mode)
|
||||||
|
-r generate a RIM-formatted output (adds ".rim")
|
||||||
|
-T generate test pattern 0000=0000..7756=7756
|
||||||
|
-v verbose operation
|
||||||
|
|
||||||
|
Dumps the RIM- or BIN-formatted input file(s) specified on
|
||||||
|
the command line. If the "-r" and/or "-b" options are
|
||||||
|
present, also creates a RIM and/or BIN version of the output
|
||||||
|
by adding ".rim" and/or ".bin" (respectively) to the input
|
||||||
|
filename (can be used to "clean up" BIN and RIM images by
|
||||||
|
deleting excess data before and after the leader/trailer).
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "d8tape.h"
|
||||||
|
|
||||||
|
static void seg_add (uint16_t addr, int len);
|
||||||
|
static void seg_more (int len);
|
||||||
|
|
||||||
|
static void optproc (int, char **);
|
||||||
|
static int dumptape (unsigned char *t, int n);
|
||||||
|
static int dumprim (unsigned char *t, int n);
|
||||||
|
static int dumpbin (unsigned char *t, int n);
|
||||||
|
static int checkrim (unsigned char *t, int n);
|
||||||
|
static int checkbin (unsigned char *t, int n);
|
||||||
|
static void writebin (void);
|
||||||
|
static void writerim (void);
|
||||||
|
static int blank (short int *core, int size);
|
||||||
|
|
||||||
|
const char *progname = "d8tape";
|
||||||
|
const char *blankname= " ";
|
||||||
|
extern char *version; // version.c
|
||||||
|
|
||||||
|
int optb;
|
||||||
|
int optd;
|
||||||
|
int optr;
|
||||||
|
int optT;
|
||||||
|
int optv;
|
||||||
|
unsigned char *tape; // paper tape image
|
||||||
|
short int core [CORE_SIZE]; // in-core image (-1 means location never used)
|
||||||
|
uint16_t tags [CORE_SIZE]; // analysis tags
|
||||||
|
segment_t *segments; // used to accumulate runs of data (from origin for nwords)
|
||||||
|
int nsegments; // indicates how many segments we have
|
||||||
|
char *tapename;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* main
|
||||||
|
*
|
||||||
|
* Main simply calls the option processor, from which everything happens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
optproc (argc, argv);
|
||||||
|
exit (EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usageError
|
||||||
|
*
|
||||||
|
* This is the usage message
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
usageError ()
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\nUsage: %s [options] papertapefile [papertapefile...]\n\n", progname);
|
||||||
|
fprintf (stderr, "where [options] are optional parameters chosen from:\n");
|
||||||
|
fprintf (stderr, " -b generate a BIN-formatted output (adds \".bin\")\n");
|
||||||
|
fprintf (stderr, " -d suppress disassembly (useful for conversion-only mode)\n");
|
||||||
|
fprintf (stderr, " -r generate a RIM-formatted output (adds \".rim\")\n");
|
||||||
|
fprintf (stderr, " -v verbose operation\n");
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "Dumps the RIM- or BIN-formatted input file(s) specified on\n");
|
||||||
|
fprintf (stderr, "the command line. If the \"-r\" and/or \"-b\" options are\n");
|
||||||
|
fprintf (stderr, "present, also creates a RIM and/or BIN version of the output\n");
|
||||||
|
fprintf (stderr, "by adding \".rim\" and/or \".bin\" (respectively) to the input\n");
|
||||||
|
fprintf (stderr, "filename (can be used to \"clean up\" BIN and RIM images by\n");
|
||||||
|
fprintf (stderr, "deleting excess data before and after the leader/trailer).\n");
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "Disassembly conforms to PAL III input requirements\n");
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* optproc
|
||||||
|
*
|
||||||
|
* This is the option processor. It detects the command line options, and
|
||||||
|
* then processes the individual files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
optproc (int argc, char **argv)
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
int got_any;
|
||||||
|
int fd;
|
||||||
|
int i;
|
||||||
|
struct stat statbuf;
|
||||||
|
int sts;
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
usageError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear out option values to defaults
|
||||||
|
optb = optr = optT = 0;
|
||||||
|
|
||||||
|
// handle command line options
|
||||||
|
got_any = 0;
|
||||||
|
while ((opt = getopt (argc, argv, "bdrTv")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'b':
|
||||||
|
optb++;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
optd++;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
optr++;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
optT++;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
optv++;
|
||||||
|
if (optv > 1) {
|
||||||
|
fprintf (stderr, "Verbosity is %d\n", optv);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usageError ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle command line arguments
|
||||||
|
for (; optind < argc; optind++) {
|
||||||
|
got_any++;
|
||||||
|
tapename = argv [optind]; // snap tapename to global
|
||||||
|
|
||||||
|
// open the tape
|
||||||
|
fd = open (tapename, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
fprintf (stderr, "%s: couldn't open %s for O_RDONLY, errno %d\n", progname, tapename, errno);
|
||||||
|
perror (NULL);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fstat (fd, &statbuf); // get the size, so we can read it into memory
|
||||||
|
|
||||||
|
tape = calloc (1, statbuf.st_size);
|
||||||
|
if (tape == NULL) {
|
||||||
|
fprintf (stderr, "%s: can't allocate %ld bytes during processing of %s, errno %d (%s)\n", progname, (unsigned long)statbuf.st_size, tapename, errno, strerror (errno));
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize data areas
|
||||||
|
memset (core, 0xff, sizeof (core)); // set to -1 -- since we are only using 12 bits of each 16 bit word, -1 isn't a valid PDP-8 core value
|
||||||
|
memset (tags, 0, sizeof (tags)); // reset tags
|
||||||
|
nsegments = 0;
|
||||||
|
segments = NULL;
|
||||||
|
|
||||||
|
read (fd, tape, statbuf.st_size);
|
||||||
|
close (fd);
|
||||||
|
|
||||||
|
// dump the tape (this also reads the tape into "core" and disassembles)
|
||||||
|
sts = dumptape (tape, statbuf.st_size);
|
||||||
|
|
||||||
|
free (tape);
|
||||||
|
|
||||||
|
if (!sts) {
|
||||||
|
continue; // skip tape
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to RIM/BIN if required (-b and/or -r)
|
||||||
|
if (optb || optr) {
|
||||||
|
// see if there is any data there at all..
|
||||||
|
if (blank (core, CORE_SIZE)) {
|
||||||
|
fprintf (stderr, "%s: tape image from %s is empty, not creating a BIN version\n", progname, tapename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (optb) {
|
||||||
|
writebin ();
|
||||||
|
}
|
||||||
|
if (optr) {
|
||||||
|
writerim ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no arguments given, dump usage message
|
||||||
|
if (optT) {
|
||||||
|
memset (core, 0xff, sizeof (core)); // set to -1 (assumption; all 0xff's in an int is -1; pretty safe)
|
||||||
|
for (i = 0; i < 07600; i++) {
|
||||||
|
core [i] = ((i & 07700) >> 6) + ((i & 00077) << 6);
|
||||||
|
}
|
||||||
|
tapename = "test";
|
||||||
|
if (optb) {
|
||||||
|
writebin ();
|
||||||
|
}
|
||||||
|
if (optr) {
|
||||||
|
writerim ();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!got_any) {
|
||||||
|
usageError ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dumptape
|
||||||
|
*
|
||||||
|
* This function does some basic processing (detecting and skipping the
|
||||||
|
* header, killing off data past the trailer) and then determines via
|
||||||
|
* checkrim() and ckeckbin() the format of the tape. Depending on the
|
||||||
|
* type of tape, dumprim() or dumpbin() is called to read the tape into
|
||||||
|
* the "core" array and disassemble it.
|
||||||
|
*
|
||||||
|
* 20071104: Changed the 'skip header' logic to look for a character
|
||||||
|
* less than 0x80, not just not equal to, because a tape I received
|
||||||
|
* had the following:
|
||||||
|
* 0000000 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200
|
||||||
|
* *
|
||||||
|
* 0000100 300 100 000 000 000 050 001 000 002 000 003 000 000 000 000 054
|
||||||
|
*
|
||||||
|
* Notice the "300" (0xc0) at location 0100.
|
||||||
|
*
|
||||||
|
* Returns 0 on error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
dumptape (unsigned char *t, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// basic preprocessing; find header
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (t [i] == 0x80) { // got a header
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == n) {
|
||||||
|
fprintf (stderr, "%s: couldn't find a 0x80 leader on tape %s; tape ignored\n", progname, tapename);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip header
|
||||||
|
for (; i < n; i++) {
|
||||||
|
if (t [i] < 0x80) { // RK 20071104 was "!= 0x80";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == n) {
|
||||||
|
fprintf (stderr, "%s: no data content found after 0x80 leader on tape %s; tape ignored\n", progname, tapename);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point, we're positioned on the first-non-leader byte of the tape
|
||||||
|
if (n - i < 4) {
|
||||||
|
fprintf (stderr, "%s: tape %s is too short; tape ignored\n", progname, tapename);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip leader (t now points to start of tape; n indicates remaining # bytes)
|
||||||
|
if (optv) {
|
||||||
|
fprintf (stderr, "%s: tape %s skipped %d (0x%0X, 0%0o) bytes of header, original size %d new size %d\n", progname, tapename, i, i, i, n, n - i);
|
||||||
|
}
|
||||||
|
t += i;
|
||||||
|
n -= i;
|
||||||
|
|
||||||
|
// find first 0x80 -- trailer
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (t [i] == 0x80) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == n) {
|
||||||
|
fprintf (stderr, "%s: warning -- tape %s does not have a trailer\n", progname, tapename);
|
||||||
|
// find first data >= 0x80, then
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (t [i] >= 0x80) {
|
||||||
|
// at least stop on the first invalid character, then
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset end-of-tape to last character
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("%s: tape %s skipped %d bytes of trailer, new size is %d bytes\n", progname, tapename, n - i, i);
|
||||||
|
}
|
||||||
|
n = i;
|
||||||
|
|
||||||
|
// determine type of tape and dump it
|
||||||
|
if (checkrim (t, n)) {
|
||||||
|
if (!dumprim (t, n)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
} else if (checkbin (t, n)) {
|
||||||
|
if (!dumpbin (t, n)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf (stderr, "%s: tape %s is neither RIM nor BIN (first four bytes are 0%03o 0%03o 0%03o 0%03o)\n", progname, tapename, t [0], t [1], t [2], t [3]);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!optd) {
|
||||||
|
flow (); // perform flow analysis
|
||||||
|
disassemble (); // disassemble
|
||||||
|
printf ("\n$\n");
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* checkrim
|
||||||
|
* checkbin
|
||||||
|
*
|
||||||
|
* These two functions try to determine what format the tape is in.
|
||||||
|
* A zero return indicates the tape is not in the given format; a one
|
||||||
|
* indicates it is. The heuristics used here are fairly simple.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
checkrim (unsigned char *t, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (n % 4) {
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("%s: tape %s size (%d bytes) is not divisible by four; not a RIM tape\n", progname, tapename, n);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if it's a RIM-formatted tape; we're looking for 01xxxxxx 00xxxxxx 00xxxxxx 00xxxxxx
|
||||||
|
for (i = 0; i < n; i += 4) {
|
||||||
|
if ((t [i] & 0xC0) != 0x40 || (t [i + 1] & 0xC0) || (t [i + 2] & 0xC0) || (t [i + 3] & 0xC0)) {
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("%s: tape %s does not have the RIM signature at offset 0%04o; expected 01xxxxxx 00xxxxxx 00xxxxxx 00xxxxxx, got 0%04o 0%04o 0%04o 0%04o\n", progname, tapename, i, t [i], t [i + 1], t [i + 2], t [i + 3]);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
checkbin (unsigned char *t, int n)
|
||||||
|
{
|
||||||
|
if (n % 2) {
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("%s: tape %s size (%d bytes) is not divisible by two; not a BIN tape\n", progname, tapename, n);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if it's a BIN-formatted tape; 01xxxxxx 00xxxxxx (i.e., we at least expect an origin)
|
||||||
|
if ((t [0] & 0xC0) != 0x40 || (t [1] & 0xC0)) {
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("%s: tape %s does not have the BIN origin signature; expected header of 01xxxxxx 00xxxxxx, got 0%04o 0%04o\n", progname, tapename, t [0], t [1]);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From the PDP-8/I & PDP-8/L Small Computer Handbook (099-00272-A1983 / J-09-5)
|
||||||
|
* Appendix D, "Perforated-Tape Loader Sequences", page 383
|
||||||
|
*
|
||||||
|
* READIN MODE LOADER
|
||||||
|
* The readin mode (RIM) loader is a minimum length, basic perforated-tape
|
||||||
|
* reader program for the ASR33, it is initially stored in memory by manual use
|
||||||
|
* of the operator console keys and switches. The loader is permanently stored in
|
||||||
|
* 18 locations of page 37.
|
||||||
|
*
|
||||||
|
* A perforated tape to be read by the RIM loader must be in RIM format:
|
||||||
|
*
|
||||||
|
* Tape Channel
|
||||||
|
* 8 7 6 5 4 3 2 1 OCTAL Format
|
||||||
|
* --------------- ----- ------------------------
|
||||||
|
* 1 0 0 0 0 0 0 0 200 Leader-trailer code
|
||||||
|
* 0 1 -A1- -A2- 1AA Absolute address to
|
||||||
|
* 0 0 -A3- -A4- 0AA contain next 4 digits
|
||||||
|
* 0 0 -X1- -X2- 0XX Content of previous
|
||||||
|
* 0 0 -X3- -X4- 0XX 4-digit address
|
||||||
|
* 0 1 -A1- -A2- 1AA Address
|
||||||
|
* 0 0 -A3- -A4- 0AA
|
||||||
|
* 0 0 -X1- -X2- 0XX Content
|
||||||
|
* 0 0 -X3- -X4- 0XX
|
||||||
|
* (etc) (etc)
|
||||||
|
* 1 0 0 0 0 0 0 0 200 Leader-trailer code
|
||||||
|
*
|
||||||
|
* The RIM loader can only be used in conjunction with the ASR33 reader (not
|
||||||
|
* the high-speed perforated-tape reader). Because a tape in RIM format is, in
|
||||||
|
* effect, twice as long as it need be, it is suggested that the RIM loader be used
|
||||||
|
* only to read the binary loader when using the ASR33. (Note that PDP-8 diag-
|
||||||
|
* nostic program tapes are in RIM format.)
|
||||||
|
*
|
||||||
|
* The complete PDP-8/I RIM loader (SA=7756) is as follows:
|
||||||
|
*
|
||||||
|
* Absolute Octal
|
||||||
|
* Address Content Tag Instruction I Z Comments
|
||||||
|
* 7756, 6032 BEG, KCC /CLEAR AC AND FLAG
|
||||||
|
* 7757, 6031 KSF /SKIP IF FLAG = 1
|
||||||
|
* 7760, 5357 JMP .-1 /LOOKING FOR CHARACTER
|
||||||
|
* 7761, 6036 KRB /READ BUFFER
|
||||||
|
* 7762, 7106 CLL RTL
|
||||||
|
* 7763, 7006 RTL /CHANNEL 8 IN AC0
|
||||||
|
* 7764, 7510 SPA /CHECKING FOR LEADER
|
||||||
|
* 7765, 5357 JMP BEG+1 /FOUND LEADER
|
||||||
|
* 7766, 7006 RTL /OK, CHANNEL 7 IN LINK
|
||||||
|
* 7767, 6031 KSF
|
||||||
|
* 7770, 5367 JMP .-1
|
||||||
|
* 7771, 6034 KRS /READ, DO NOT CLEAR
|
||||||
|
* 7772, 7420 SNL /CHECKING FOR ADDRESS
|
||||||
|
* 7773, 3776 DCA I TEMP /STORE CONTENT
|
||||||
|
* 7774, 3376 DCA TEMP /STORE ADDRESS
|
||||||
|
* 7775, 5356 JMP BEG /NEXT WORD
|
||||||
|
* 7776, 0 TEMP, 0 /TEMP STORAGE
|
||||||
|
* 7777, 5XXX JMP X /JMP START OF BIN LOADER
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dumprim
|
||||||
|
*
|
||||||
|
* This is a finite-state-machine that runs through the tape reading the address
|
||||||
|
* and data records, stuffs them into core[], and disassembles the opcodes unless
|
||||||
|
* "-d" is specified.
|
||||||
|
*
|
||||||
|
* Note that disassembly is done after the complete tape has been read in, this
|
||||||
|
* allows us to do some flow analysis.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RIM_Initial 1 // waiting for address
|
||||||
|
#define RIM_Addr 2 // got top part of address, process bottom part
|
||||||
|
#define RIM_Data1 3 // got address, process top part of data
|
||||||
|
#define RIM_Data2 4 // got top part of data, process bottom part
|
||||||
|
|
||||||
|
static int
|
||||||
|
dumprim (unsigned char *t, int n)
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
int i;
|
||||||
|
uint16_t addr, data;
|
||||||
|
uint16_t cur_addr;
|
||||||
|
|
||||||
|
state = RIM_Initial;
|
||||||
|
|
||||||
|
cur_addr = 0xffff; // impossible address for PDP-8
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("[%03o] ", t [i]); fflush (stdout);
|
||||||
|
if ((i % 13) == 12) {
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (state) {
|
||||||
|
case RIM_Initial:
|
||||||
|
if (t [i] & 0100) { // indicates 1st part of address
|
||||||
|
addr = (t [i] & 0077) << 6; // store top part
|
||||||
|
state = RIM_Addr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RIM_Addr:
|
||||||
|
addr |= (t [i] & 0077);
|
||||||
|
state = RIM_Data1;
|
||||||
|
break;
|
||||||
|
case RIM_Data1:
|
||||||
|
data = (t [i] & 0077) << 6; // store top part
|
||||||
|
state = RIM_Data2;
|
||||||
|
break;
|
||||||
|
case RIM_Data2: // final decode complete, store data
|
||||||
|
data |= (t [i] & 0077);
|
||||||
|
core [addr] = data; // stash data into core image
|
||||||
|
|
||||||
|
// segment management -- if it's the next byte, add, else create new
|
||||||
|
if (addr == cur_addr) {
|
||||||
|
cur_addr++;
|
||||||
|
seg_more (1);
|
||||||
|
} else {
|
||||||
|
seg_add (addr, 1);
|
||||||
|
cur_addr = addr + 1;
|
||||||
|
}
|
||||||
|
state = RIM_Initial;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BIN format, from the same doc as above, page 384:
|
||||||
|
*
|
||||||
|
* BINARY LOADER
|
||||||
|
* The binary loader (BIN) is used to read machine language tapes (in binary
|
||||||
|
* format) produced by the program assembly language (PAL). A tape in binary
|
||||||
|
* format is about one-half the length of the comparable RIM format tape. It can,
|
||||||
|
* therefore, be read about twice as fast as a RIM tape and is, for this reason,
|
||||||
|
* the more desirable format to use with the 10 cps ASR33 reader or the Type
|
||||||
|
* PR8/I High-Speed Perforated-Tape Reader.
|
||||||
|
*
|
||||||
|
* The format of a binary tape is as follows:
|
||||||
|
*
|
||||||
|
* LEADER: about 2 feet of leader-trailer codes.
|
||||||
|
*
|
||||||
|
* BODY: characters representing the absolute, machine language program
|
||||||
|
* in easy-to-read binary (or octal) form. The section of tape may contain
|
||||||
|
* characters representing instructions (channel 8 and 7 not punched) or
|
||||||
|
* origin resettings (channel 8 not punched, channel 7 punched) and is
|
||||||
|
* concluded by 2 characters (channel 8 and 7 not punched) that represent
|
||||||
|
* a check sum for the entire section.
|
||||||
|
*
|
||||||
|
* TRAILER: same as leader.
|
||||||
|
*
|
||||||
|
* I.e.,
|
||||||
|
*
|
||||||
|
* Tape Channel
|
||||||
|
* 8 7 6 5 4 3 2 1 OCTAL Format
|
||||||
|
* --------------- ----- ------------------------
|
||||||
|
* 1 0 0 0 0 0 0 0 200 Leader
|
||||||
|
* 0 1 A A A A A A 1AA Address (top)
|
||||||
|
* 0 1 B B B B B B 1BB Address (bottom)
|
||||||
|
* 0 0 C C C C C C 0CC Data (top)
|
||||||
|
* 0 0 D D D D D D 0DD Data (bottom)
|
||||||
|
* 0 0 C C C C C C 0CC Data (top)
|
||||||
|
* 0 0 D D D D D D 0DD Data (bottom)
|
||||||
|
* . . . ... next data (2 bytes)
|
||||||
|
* 0 1 A A A A A A 1AA New address (top)
|
||||||
|
* 0 1 B B B B B B 1BB New address (bottom)
|
||||||
|
* . . . ... next data (2 bytes)
|
||||||
|
* 0 0 X X X X X X 0XX Checksum (top)
|
||||||
|
* 0 0 Y Y Y Y Y Y 0YY Checksum (bottom)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dumpbin
|
||||||
|
*
|
||||||
|
* This is a finite-state-machine that runs through the tape looking for the
|
||||||
|
* origin and subsequent data fields, stuffs them into the core[] array, and
|
||||||
|
* optionally disassembles the opcodes.
|
||||||
|
*
|
||||||
|
* Every time we hit an origin change, we create a new segment and accumulate
|
||||||
|
* bytes into it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BIN_Initial 1 // initial state; we require an origin to get out of it
|
||||||
|
#define BIN_Origin 2 // we got the top part of the origin, now need to get the bottom part
|
||||||
|
#define BIN_DataHW 3 // we have an address, so we are looking for another origin or the top part of the data
|
||||||
|
#define BIN_DataLW 4 // we have the top part of the data, now fetching the low part
|
||||||
|
|
||||||
|
static int
|
||||||
|
dumpbin (unsigned char *t, int n)
|
||||||
|
{
|
||||||
|
int tape_checksum; // checksum stored on tape
|
||||||
|
int calc_checksum; // calculated checksum
|
||||||
|
int i;
|
||||||
|
int state;
|
||||||
|
unsigned short int addr, data;
|
||||||
|
|
||||||
|
if (n < 4) {
|
||||||
|
fprintf (stderr, "%s: tape %s is too short; tape skipped\n", progname, tapename);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tape_checksum = ((t [n - 2] & 0x3f) << 6) + (t [n - 1] & 0x3f);
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("%s: tape %s expected checksum 0%04o\n", progname, tapename, tape_checksum);
|
||||||
|
}
|
||||||
|
n -= 2; // tape is now shorter by the two bytes
|
||||||
|
|
||||||
|
// now calculate checksum
|
||||||
|
calc_checksum = 0;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
calc_checksum += t [i];
|
||||||
|
}
|
||||||
|
calc_checksum &= 07777; // mask to 12 bits
|
||||||
|
if (optv > 1) {
|
||||||
|
printf ("%s: tape %s calculated checksum 0%04o\n", progname, tapename, calc_checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tape_checksum != calc_checksum) {
|
||||||
|
fprintf (stderr, "%s: tape %s calculated checksum [0%04o] != stored checksum [0%04o]; tape skipped\n", progname, tapename, calc_checksum, tape_checksum);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we can dump the binary data via the state machine
|
||||||
|
state = BIN_Initial;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("[%03o] ", t [i]); fflush (stdout);
|
||||||
|
if ((i % 13) == 12) {
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (state) {
|
||||||
|
case BIN_Initial:
|
||||||
|
if (t [i] & 0100) { // indicates origin setting code
|
||||||
|
addr = (t [i] & 0077) << 6; // store top part
|
||||||
|
state = BIN_Origin;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BIN_Origin:
|
||||||
|
addr += (t [i] & 0077); // store bottom part
|
||||||
|
state = BIN_DataHW;
|
||||||
|
seg_add (addr, 0);
|
||||||
|
break;
|
||||||
|
case BIN_DataHW:
|
||||||
|
if (t [i] & 0100) { // another origin; skip loading data and load address instead
|
||||||
|
addr = (t [i] & 0077) << 6;
|
||||||
|
state = BIN_Origin;
|
||||||
|
} else {
|
||||||
|
data = (t [i] & 0077) << 6; // store top part of data
|
||||||
|
state = BIN_DataLW;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BIN_DataLW:
|
||||||
|
data += (t [i] & 0077);
|
||||||
|
core [addr] = data;
|
||||||
|
seg_more (1);
|
||||||
|
addr++; // the magic of BIN-format is the autoincrement of the address
|
||||||
|
state = BIN_DataHW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (optv > 2) {
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* writebin
|
||||||
|
* writerim
|
||||||
|
*
|
||||||
|
* These two functions write the BIN and RIM format tapes to a file.
|
||||||
|
* The filename is constructed by appending ".bin" or ".rim" to the
|
||||||
|
* input filename.
|
||||||
|
*
|
||||||
|
* The header and trailer written are short, LEADER_LENGTH bytes.
|
||||||
|
*
|
||||||
|
* The writebin() uses a finit-state-machine to generate the origin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LEADER_LENGTH 16 // 16 chars of leader/trailer should be plenty
|
||||||
|
|
||||||
|
#define WBIN_Initial 1 // looking for first/next in-use core[] element
|
||||||
|
#define WBIN_Writing 2 // origin written, dumping consecutive words
|
||||||
|
|
||||||
|
static void
|
||||||
|
writebin (void)
|
||||||
|
{
|
||||||
|
char fname [PATH_MAX];
|
||||||
|
char leader [LEADER_LENGTH];
|
||||||
|
FILE *fp;
|
||||||
|
int i;
|
||||||
|
int cksum;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
// create filename and open it
|
||||||
|
sprintf (fname, "%s.bin", tapename);
|
||||||
|
if ((fp = fopen (fname, "w")) == NULL) {
|
||||||
|
fprintf (stderr, "%s: unable to open BIN output file %s for w, errno %d (%s); creation of output file skipped\n", progname, fname, errno, strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write leader
|
||||||
|
memset (leader, 0x80, sizeof (leader));
|
||||||
|
fwrite (leader, 1, sizeof (leader), fp);
|
||||||
|
|
||||||
|
// now scan through "core" and write the data out...
|
||||||
|
cksum = 0;
|
||||||
|
state = WBIN_Initial;
|
||||||
|
for (i = 0; i < CORE_SIZE; i++) {
|
||||||
|
switch (state) {
|
||||||
|
case WBIN_Initial: // transit out of WBIN_Initial on a "used" core position
|
||||||
|
if (core [i] != -1) {
|
||||||
|
state = WBIN_Writing;
|
||||||
|
fprintf (fp, "%c%c", 0x40 | ((i & 07700) >> 6), i & 00077); // write origin directive
|
||||||
|
fprintf (fp, "%c%c", (core [i] & 07700) >> 6, core [i] & 00077); // write data
|
||||||
|
cksum += (0x40 | ((i & 07700) >> 6)) + (i & 00077) + ((core [i] & 07700) >> 6) + (core [i] & 00077);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WBIN_Writing:
|
||||||
|
if (core [i] == -1) {
|
||||||
|
state = WBIN_Initial; // waiting again for a used core position
|
||||||
|
} else {
|
||||||
|
fprintf (fp, "%c%c", (core [i] & 07700) >> 6, core [i] & 00077);
|
||||||
|
cksum += ((core [i] & 07700) >> 6) + (core [i] & 00077);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now write the checksum
|
||||||
|
fprintf (fp, "%c%c", (cksum & 07700) >> 6, cksum & 00077);
|
||||||
|
|
||||||
|
// write trailer
|
||||||
|
fwrite (leader, 1, sizeof (leader), fp);
|
||||||
|
|
||||||
|
fclose (fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
writerim (void)
|
||||||
|
{
|
||||||
|
char fname [PATH_MAX];
|
||||||
|
char leader [LEADER_LENGTH];
|
||||||
|
FILE *fp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// create the filename and open it
|
||||||
|
sprintf (fname, "%s.rim", tapename);
|
||||||
|
if ((fp = fopen (fname, "w")) == NULL) {
|
||||||
|
fprintf (stderr, "%s: unable to open RIM output file %s for w, errno %d (%s); creation of output file skipped\n", progname, fname, errno, strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write leader
|
||||||
|
memset (leader, 0x80, sizeof (leader));
|
||||||
|
fwrite (leader, 1, sizeof (leader), fp);
|
||||||
|
|
||||||
|
for (i = 0; i < CORE_SIZE; i++) {
|
||||||
|
if (core [i] != -1) {
|
||||||
|
fprintf (fp, "%c%c%c%c", 0x40 + ((i & 07700) >> 6), i & 00077, (core [i] & 07700) >> 6, core [i] & 00077);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write trailer
|
||||||
|
fwrite (leader, 1, sizeof (leader), fp);
|
||||||
|
|
||||||
|
fclose (fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blank
|
||||||
|
*
|
||||||
|
* A utility routine to see if core[] is blank (returns 1).
|
||||||
|
* Used to avoid writing an empty tape.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
blank (short int *c, int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (c [i] != -1) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* seg_add (addr, len)
|
||||||
|
* seg_more (more)
|
||||||
|
*
|
||||||
|
* These functions manipulate the segment data stored
|
||||||
|
* in "segments[]" and "nsegments".
|
||||||
|
*
|
||||||
|
* seg_add creates a new segment with the given address
|
||||||
|
* and length.
|
||||||
|
*
|
||||||
|
* seg_more lengthens the current segment by "more"
|
||||||
|
* words.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
seg_add (uint16_t addr, int len)
|
||||||
|
{
|
||||||
|
if (optv > 3) {
|
||||||
|
printf ("seg_add (0%04o, %d (0%04o))\n", addr, len, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
segments = realloc (segments, (nsegments + 1) * sizeof (segments [0]));
|
||||||
|
if (segments == NULL) {
|
||||||
|
fprintf (stderr, "%s: couldn't realloc segments array to be %d elements (%ld bytes) long, errno %d (%s)\n", progname, nsegments + 1, (unsigned long)(nsegments + 1) * sizeof (segments [0]), errno, strerror (errno));
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
segments [nsegments].saddr = addr;
|
||||||
|
segments [nsegments].nwords = len;
|
||||||
|
nsegments++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
seg_more (int len)
|
||||||
|
{
|
||||||
|
if (optv > 3) {
|
||||||
|
printf ("seg_more (+%d (0%04o))\n", len, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nsegments) {
|
||||||
|
segments [nsegments - 1].nwords += len;
|
||||||
|
} else {
|
||||||
|
fprintf (stderr, "%s: seg_more called with no segments in existence\n", progname);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BIN
d8tape/test.bin
Normal file
BIN
d8tape/test.bin
Normal file
Binary file not shown.
806
d8tape/test.dump
Normal file
806
d8tape/test.dump
Normal file
@ -0,0 +1,806 @@
|
|||||||
|
00000/7402 hlt
|
||||||
|
00001/7402 hlt
|
||||||
|
00002/7402 hlt
|
||||||
|
00003/7402 hlt
|
||||||
|
00040/0001 and 1
|
||||||
|
00041/0000 and 0
|
||||||
|
00042/0000 and 0
|
||||||
|
00043/0000 and 0
|
||||||
|
00044/0000 and 0
|
||||||
|
00045/0000 and 0
|
||||||
|
00046/0000 and 0
|
||||||
|
00047/0000 and 0
|
||||||
|
00050/0000 and 0
|
||||||
|
00051/0000 and 0
|
||||||
|
00052/0000 and 0
|
||||||
|
00053/0000 and 0
|
||||||
|
00054/7777 cla mqa mql
|
||||||
|
00055/0000 and 0
|
||||||
|
00056/0000 and 0
|
||||||
|
00057/6251 iot 25,1
|
||||||
|
00060/6241 iot 24,1
|
||||||
|
00061/6251 iot 25,1
|
||||||
|
00062/5456 jmp i 56
|
||||||
|
00063/0000 and 0
|
||||||
|
00064/6252 iot 25,2
|
||||||
|
00065/6242 iot 24,2
|
||||||
|
00066/6252 iot 25,2
|
||||||
|
00067/5463 jmp i 63
|
||||||
|
00200/7300 cla cll
|
||||||
|
00201/7303 cla cll iac bsw
|
||||||
|
00202/3051 dca 51
|
||||||
|
00203/3052 dca 52
|
||||||
|
00204/6040 iot 4,0
|
||||||
|
00205/1177 tad 177
|
||||||
|
00206/4576 jms i 176
|
||||||
|
00207/0000 and 0
|
||||||
|
00210/7600 cla
|
||||||
|
00211/0000 and 0
|
||||||
|
00212/1600 tad i 200
|
||||||
|
00213/7410 skp
|
||||||
|
00214/7402 hlt
|
||||||
|
00215/7200 cla
|
||||||
|
00216/1051 tad 51
|
||||||
|
00217/0175 and 175
|
||||||
|
00220/1174 tad 174
|
||||||
|
00221/3225 dca 225
|
||||||
|
00222/7215 cla iac
|
||||||
|
00223/1173 tad 173
|
||||||
|
00224/7450 sna
|
||||||
|
00225/7402 hlt
|
||||||
|
00226/4572 jms i 172
|
||||||
|
00227/7006 rtl
|
||||||
|
00230/7004 ral
|
||||||
|
00231/0171 and 171
|
||||||
|
00232/1170 tad 170
|
||||||
|
00233/3057 dca 57
|
||||||
|
00234/6214 iot 21,4
|
||||||
|
00235/1170 tad 170
|
||||||
|
00236/3064 dca 64
|
||||||
|
00237/3050 dca 50
|
||||||
|
00240/5567 jmp i 167
|
||||||
|
00400/4566 jms i 166
|
||||||
|
00401/7777 cla mqa mql
|
||||||
|
00402/0435 and i 35
|
||||||
|
00403/4565 jms i 165
|
||||||
|
00404/7421 mql
|
||||||
|
00405/7501 mqa
|
||||||
|
00406/3441 dca i 41
|
||||||
|
00407/7501 mqa
|
||||||
|
00410/7001 iac
|
||||||
|
00411/4564 jms i 164
|
||||||
|
00412/2055 isz 55
|
||||||
|
00413/5204 jmp 404
|
||||||
|
00414/4565 jms i 165
|
||||||
|
00415/7421 mql
|
||||||
|
00416/7501 mqa
|
||||||
|
00417/7041 cma iac
|
||||||
|
00420/1441 tad i 41
|
||||||
|
00421/7450 sna
|
||||||
|
00422/5227 jmp 427
|
||||||
|
00423/3047 dca 47
|
||||||
|
00424/7501 mqa
|
||||||
|
00425/3046 dca 46
|
||||||
|
00426/4563 jms i 163
|
||||||
|
00427/7501 mqa
|
||||||
|
00430/7001 iac
|
||||||
|
00431/4564 jms i 164
|
||||||
|
00432/2055 isz 55
|
||||||
|
00433/5215 jmp 415
|
||||||
|
00434/4063 jms 63
|
||||||
|
00435/4566 jms i 166
|
||||||
|
00436/7776 spa sna szl cla osr hlt
|
||||||
|
00437/0472 and i 72
|
||||||
|
00440/4562 jms i 162
|
||||||
|
00441/7421 mql
|
||||||
|
00442/7501 mqa
|
||||||
|
00443/3441 dca i 41
|
||||||
|
00444/7501 mqa
|
||||||
|
00445/7001 iac
|
||||||
|
00446/4561 jms i 161
|
||||||
|
00447/2055 isz 55
|
||||||
|
00450/5241 jmp 441
|
||||||
|
00451/4562 jms i 162
|
||||||
|
00452/7421 mql
|
||||||
|
00453/7501 mqa
|
||||||
|
00454/7041 cma iac
|
||||||
|
00455/1441 tad i 41
|
||||||
|
00456/7450 sna
|
||||||
|
00457/5264 jmp 464
|
||||||
|
00460/3047 dca 47
|
||||||
|
00461/7501 mqa
|
||||||
|
00462/3046 dca 46
|
||||||
|
00463/4563 jms i 163
|
||||||
|
00464/7501 mqa
|
||||||
|
00465/7001 iac
|
||||||
|
00466/4561 jms i 161
|
||||||
|
00467/2055 isz 55
|
||||||
|
00470/5252 jmp 452
|
||||||
|
00471/4063 jms 63
|
||||||
|
00472/4566 jms i 166
|
||||||
|
00473/7775 cla mqa mql
|
||||||
|
00474/0532 and i 132
|
||||||
|
00475/4565 jms i 165
|
||||||
|
00476/7421 mql
|
||||||
|
00477/7501 mqa
|
||||||
|
00500/4560 jms i 160
|
||||||
|
00501/3441 dca i 41
|
||||||
|
00502/7501 mqa
|
||||||
|
00503/7001 iac
|
||||||
|
00504/4564 jms i 164
|
||||||
|
00505/2055 isz 55
|
||||||
|
00506/5276 jmp 476
|
||||||
|
00507/4565 jms i 165
|
||||||
|
00510/7421 mql
|
||||||
|
00511/7501 mqa
|
||||||
|
00512/4560 jms i 160
|
||||||
|
00513/7041 cma iac
|
||||||
|
00514/1441 tad i 41
|
||||||
|
00515/7450 sna
|
||||||
|
00516/5324 jmp 524
|
||||||
|
00517/3047 dca 47
|
||||||
|
00520/7501 mqa
|
||||||
|
00521/4560 jms i 160
|
||||||
|
00522/3046 dca 46
|
||||||
|
00523/4563 jms i 163
|
||||||
|
00524/7501 mqa
|
||||||
|
00525/7001 iac
|
||||||
|
00526/4564 jms i 164
|
||||||
|
00527/2055 isz 55
|
||||||
|
00530/5310 jmp 510
|
||||||
|
00531/4063 jms 63
|
||||||
|
00532/4566 jms i 166
|
||||||
|
00533/7774 spa sna szl cla osr
|
||||||
|
00534/0572 and i 172
|
||||||
|
00535/4562 jms i 162
|
||||||
|
00536/7421 mql
|
||||||
|
00537/7501 mqa
|
||||||
|
00540/4560 jms i 160
|
||||||
|
00541/3441 dca i 41
|
||||||
|
00542/7501 mqa
|
||||||
|
00543/7001 iac
|
||||||
|
00544/4561 jms i 161
|
||||||
|
00545/2055 isz 55
|
||||||
|
00546/5336 jmp 536
|
||||||
|
00547/4562 jms i 162
|
||||||
|
00550/7421 mql
|
||||||
|
00551/7501 mqa
|
||||||
|
00552/4560 jms i 160
|
||||||
|
00553/7041 cma iac
|
||||||
|
00554/1441 tad i 41
|
||||||
|
00555/7450 sna
|
||||||
|
00556/5364 jmp 564
|
||||||
|
00557/3047 dca 47
|
||||||
|
00560/7501 mqa
|
||||||
|
00561/4560 jms i 160
|
||||||
|
00562/3046 dca 46
|
||||||
|
00563/4563 jms i 163
|
||||||
|
00564/7501 mqa
|
||||||
|
00565/7001 iac
|
||||||
|
00566/4561 jms i 161
|
||||||
|
00567/2055 isz 55
|
||||||
|
00570/5350 jmp 550
|
||||||
|
00571/4063 jms 63
|
||||||
|
00572/4566 jms i 166
|
||||||
|
00573/7773 cla mqa mql
|
||||||
|
00574/0634 and i 434
|
||||||
|
00575/4565 jms i 165
|
||||||
|
00576/7421 mql
|
||||||
|
00577/7501 mqa
|
||||||
|
00600/4560 jms i 160
|
||||||
|
00601/7040 cma
|
||||||
|
00602/3441 dca i 41
|
||||||
|
00603/7501 mqa
|
||||||
|
00604/7001 iac
|
||||||
|
00605/4564 jms i 164
|
||||||
|
00606/2055 isz 55
|
||||||
|
00607/5777 jmp i 777
|
||||||
|
00610/4565 jms i 165
|
||||||
|
00611/7421 mql
|
||||||
|
00612/7501 mqa
|
||||||
|
00613/4560 jms i 160
|
||||||
|
00614/7001 iac
|
||||||
|
00615/1441 tad i 41
|
||||||
|
00616/7450 sna
|
||||||
|
00617/5226 jmp 626
|
||||||
|
00620/3047 dca 47
|
||||||
|
00621/7501 mqa
|
||||||
|
00622/4560 jms i 160
|
||||||
|
00623/7040 cma
|
||||||
|
00624/3046 dca 46
|
||||||
|
00625/4563 jms i 163
|
||||||
|
00626/7501 mqa
|
||||||
|
00627/7001 iac
|
||||||
|
00630/4564 jms i 164
|
||||||
|
00631/2055 isz 55
|
||||||
|
00632/5211 jmp 611
|
||||||
|
00633/4063 jms 63
|
||||||
|
00634/4566 jms i 166
|
||||||
|
00635/7772 spa sna szl cla hlt
|
||||||
|
00636/0676 and i 676
|
||||||
|
00637/4562 jms i 162
|
||||||
|
00640/7421 mql
|
||||||
|
00641/7501 mqa
|
||||||
|
00642/4560 jms i 160
|
||||||
|
00643/7040 cma
|
||||||
|
00644/3441 dca i 41
|
||||||
|
00645/7501 mqa
|
||||||
|
00646/7001 iac
|
||||||
|
00647/4561 jms i 161
|
||||||
|
00650/2055 isz 55
|
||||||
|
00651/5240 jmp 640
|
||||||
|
00652/4562 jms i 162
|
||||||
|
00653/7421 mql
|
||||||
|
00654/7501 mqa
|
||||||
|
00655/4560 jms i 160
|
||||||
|
00656/7001 iac
|
||||||
|
00657/1441 tad i 41
|
||||||
|
00660/7450 sna
|
||||||
|
00661/5270 jmp 670
|
||||||
|
00662/3047 dca 47
|
||||||
|
00663/7501 mqa
|
||||||
|
00664/4560 jms i 160
|
||||||
|
00665/7040 cma
|
||||||
|
00666/3046 dca 46
|
||||||
|
00667/4563 jms i 163
|
||||||
|
00670/7501 mqa
|
||||||
|
00671/7001 iac
|
||||||
|
00672/4561 jms i 161
|
||||||
|
00673/2055 isz 55
|
||||||
|
00674/5253 jmp 653
|
||||||
|
00675/4063 jms 63
|
||||||
|
00676/4566 jms i 166
|
||||||
|
00677/7771 cla mqa mql
|
||||||
|
00700/0727 and i 727
|
||||||
|
00701/4565 jms i 165
|
||||||
|
00702/7421 mql
|
||||||
|
00703/4557 jms i 157
|
||||||
|
00704/3441 dca i 41
|
||||||
|
00705/4564 jms i 164
|
||||||
|
00706/2055 isz 55
|
||||||
|
00707/5303 jmp 703
|
||||||
|
00710/4565 jms i 165
|
||||||
|
00711/7421 mql
|
||||||
|
00712/4557 jms i 157
|
||||||
|
00713/7041 cma iac
|
||||||
|
00714/1441 tad i 41
|
||||||
|
00715/7450 sna
|
||||||
|
00716/5323 jmp 723
|
||||||
|
00717/3047 dca 47
|
||||||
|
00720/7501 mqa
|
||||||
|
00721/3046 dca 46
|
||||||
|
00722/4563 jms i 163
|
||||||
|
00723/4564 jms i 164
|
||||||
|
00724/2055 isz 55
|
||||||
|
00725/5312 jmp 712
|
||||||
|
00726/4063 jms 63
|
||||||
|
00727/4566 jms i 166
|
||||||
|
00730/7770 spa sna szl cla
|
||||||
|
00731/1000 tad 0
|
||||||
|
00732/4562 jms i 162
|
||||||
|
00733/7421 mql
|
||||||
|
00734/4557 jms i 157
|
||||||
|
00735/3441 dca i 41
|
||||||
|
00736/4561 jms i 161
|
||||||
|
00737/2055 isz 55
|
||||||
|
00740/5334 jmp 734
|
||||||
|
00741/4562 jms i 162
|
||||||
|
00742/7421 mql
|
||||||
|
00743/4557 jms i 157
|
||||||
|
00744/7041 cma iac
|
||||||
|
00745/1441 tad i 41
|
||||||
|
00746/7450 sna
|
||||||
|
00747/5354 jmp 754
|
||||||
|
00750/3047 dca 47
|
||||||
|
00751/7501 mqa
|
||||||
|
00752/3046 dca 46
|
||||||
|
00753/4563 jms i 163
|
||||||
|
00754/4561 jms i 161
|
||||||
|
00755/2055 isz 55
|
||||||
|
00756/5343 jmp 743
|
||||||
|
00757/4063 jms 63
|
||||||
|
00760/5556 jmp i 156
|
||||||
|
00777/0576 and i 176
|
||||||
|
01000/2051 isz 51
|
||||||
|
01001/7410 skp
|
||||||
|
01002/5200 jmp 1000
|
||||||
|
01003/7200 cla
|
||||||
|
01004/1177 tad 177
|
||||||
|
01005/4576 jms i 176
|
||||||
|
01006/0000 and 0
|
||||||
|
01007/1600 tad i 1000
|
||||||
|
01010/0000 and 0
|
||||||
|
01011/7600 cla
|
||||||
|
01012/4572 jms i 172
|
||||||
|
01013/7500 sma
|
||||||
|
01014/4555 jms i 155
|
||||||
|
01015/4554 jms i 154
|
||||||
|
01016/1044 tad 44
|
||||||
|
01017/1051 tad 51
|
||||||
|
01020/4553 jms i 153
|
||||||
|
01021/4554 jms i 154
|
||||||
|
01022/1051 tad 51
|
||||||
|
01023/1057 tad 57
|
||||||
|
01024/7112 cll rtr
|
||||||
|
01025/7010 rar
|
||||||
|
01026/0175 and 175
|
||||||
|
01027/1152 tad 152
|
||||||
|
01030/4551 jms i 151
|
||||||
|
01031/4554 jms i 154
|
||||||
|
01032/1055 tad 55
|
||||||
|
01033/1052 tad 52
|
||||||
|
01034/4553 jms i 153
|
||||||
|
01035/4550 jms i 150
|
||||||
|
01036/4572 jms i 172
|
||||||
|
01037/7006 rtl
|
||||||
|
01040/7420 snl
|
||||||
|
01041/5547 jmp i 147
|
||||||
|
01042/7402 hlt
|
||||||
|
01043/5547 jmp i 147
|
||||||
|
01044/0516 and i 116
|
||||||
|
01045/0440 and i 40
|
||||||
|
01046/2001 isz 1
|
||||||
|
01047/2323 isz 1123
|
||||||
|
01050/4000 jms 0
|
||||||
|
01051/4006 jms 6
|
||||||
|
01052/1105 tad 105
|
||||||
|
01053/1404 tad i 4
|
||||||
|
01054/4000 jms 0
|
||||||
|
01055/4005 jms 5
|
||||||
|
01056/2222 isz 1022
|
||||||
|
01057/1722 tad i 1122
|
||||||
|
01060/2340 isz 1140
|
||||||
|
01061/0000 and 0
|
||||||
|
01062/0000 and 0
|
||||||
|
01063/7300 cla cll
|
||||||
|
01064/2050 isz 50
|
||||||
|
01065/1050 tad 50
|
||||||
|
01066/1662 tad i 1062
|
||||||
|
01067/7440 sza
|
||||||
|
01070/7402 hlt
|
||||||
|
01071/4572 jms i 172
|
||||||
|
01072/0146 and 146
|
||||||
|
01073/7450 sna
|
||||||
|
01074/5304 jmp 1104
|
||||||
|
01075/1662 tad i 1062
|
||||||
|
01076/7650 sna cla
|
||||||
|
01077/5304 jmp 1104
|
||||||
|
01100/2262 isz 1062
|
||||||
|
01101/1662 tad i 1062
|
||||||
|
01102/3262 dca 1062
|
||||||
|
01103/5662 jmp i 1062
|
||||||
|
01104/2262 isz 1062
|
||||||
|
01105/2262 isz 1062
|
||||||
|
01106/5662 jmp i 1062
|
||||||
|
01107/0000 and 0
|
||||||
|
01110/3042 dca 42
|
||||||
|
01111/1051 tad 51
|
||||||
|
01112/0145 and 145
|
||||||
|
01113/7040 cma
|
||||||
|
01114/3043 dca 43
|
||||||
|
01115/1042 tad 42
|
||||||
|
01116/7104 cll ral
|
||||||
|
01117/7430 szl
|
||||||
|
01120/7001 iac
|
||||||
|
01121/2043 isz 43
|
||||||
|
01122/5316 jmp 1116
|
||||||
|
01123/5707 jmp i 1107
|
||||||
|
01124/0000 and 0
|
||||||
|
01125/7200 cla
|
||||||
|
01126/1144 tad 144
|
||||||
|
01127/3042 dca 42
|
||||||
|
01130/7701 cla mqa
|
||||||
|
01131/3043 dca 43
|
||||||
|
01132/1043 tad 43
|
||||||
|
01133/2042 isz 42
|
||||||
|
01134/5332 jmp 1132
|
||||||
|
01135/1143 tad 143
|
||||||
|
01136/7421 mql
|
||||||
|
01137/7501 mqa
|
||||||
|
01140/5724 jmp i 1124
|
||||||
|
01141/0000 and 0
|
||||||
|
01142/7701 cla mqa
|
||||||
|
01143/3042 dca 42
|
||||||
|
01144/1042 tad 42
|
||||||
|
01145/7104 cll ral
|
||||||
|
01146/7104 cll ral
|
||||||
|
01147/1042 tad 42
|
||||||
|
01150/1042 tad 42
|
||||||
|
01151/1042 tad 42
|
||||||
|
01152/7104 cll ral
|
||||||
|
01153/7104 cll ral
|
||||||
|
01154/1042 tad 42
|
||||||
|
01155/1143 tad 143
|
||||||
|
01156/7421 mql
|
||||||
|
01157/7501 mqa
|
||||||
|
01160/5741 jmp i 1141
|
||||||
|
01200/0000 and 0
|
||||||
|
01201/7200 cla
|
||||||
|
01202/1052 tad 52
|
||||||
|
01203/0145 and 145
|
||||||
|
01204/7640 sza cla
|
||||||
|
01205/5212 jmp 1212
|
||||||
|
01206/4063 jms 63
|
||||||
|
01207/4554 jms i 154
|
||||||
|
01210/1246 tad 1246
|
||||||
|
01211/4056 jms 56
|
||||||
|
01212/1051 tad 51
|
||||||
|
01213/4553 jms i 153
|
||||||
|
01214/4542 jms i 142
|
||||||
|
01215/1052 tad 52
|
||||||
|
01216/4553 jms i 153
|
||||||
|
01217/4542 jms i 142
|
||||||
|
01220/1050 tad 50
|
||||||
|
01221/4553 jms i 153
|
||||||
|
01222/4542 jms i 142
|
||||||
|
01223/6214 iot 21,4
|
||||||
|
01224/7112 cll rtr
|
||||||
|
01225/7010 rar
|
||||||
|
01226/1152 tad 152
|
||||||
|
01227/4551 jms i 151
|
||||||
|
01230/1041 tad 41
|
||||||
|
01231/4553 jms i 153
|
||||||
|
01232/4542 jms i 142
|
||||||
|
01233/1046 tad 46
|
||||||
|
01234/4553 jms i 153
|
||||||
|
01235/4542 jms i 142
|
||||||
|
01236/1047 tad 47
|
||||||
|
01237/1046 tad 46
|
||||||
|
01240/4553 jms i 153
|
||||||
|
01241/4550 jms i 150
|
||||||
|
01242/2052 isz 52
|
||||||
|
01243/7410 skp
|
||||||
|
01244/5242 jmp 1242
|
||||||
|
01245/5600 jmp i 1200
|
||||||
|
01246/3720 dca i 1320
|
||||||
|
01247/0123 and 123
|
||||||
|
01250/2340 isz 1340
|
||||||
|
01251/0522 and i 122
|
||||||
|
01252/2223 isz 1223
|
||||||
|
01253/4024 jms 24
|
||||||
|
01254/0523 and i 123
|
||||||
|
01255/2440 isz i 40
|
||||||
|
01256/0104 and 104
|
||||||
|
01257/0422 and i 22
|
||||||
|
01260/2340 isz 1340
|
||||||
|
01261/0530 and i 130
|
||||||
|
01262/2004 isz 4
|
||||||
|
01263/4022 jms 22
|
||||||
|
01264/0326 and 1326
|
||||||
|
01265/0437 and i 37
|
||||||
|
01266/0000 and 0
|
||||||
|
01267/0000 and 0
|
||||||
|
01270/3333 dca 1333
|
||||||
|
01271/6214 iot 21,4
|
||||||
|
01272/1170 tad 170
|
||||||
|
01273/3331 dca 1331
|
||||||
|
01274/6224 iot 22,4
|
||||||
|
01275/1170 tad 170
|
||||||
|
01276/3277 dca 1277
|
||||||
|
01277/7402 hlt
|
||||||
|
01300/1667 tad i 1267
|
||||||
|
01301/1170 tad 170
|
||||||
|
01302/3316 dca 1316
|
||||||
|
01303/2267 isz 1267
|
||||||
|
01304/1667 tad i 1267
|
||||||
|
01305/3334 dca 1334
|
||||||
|
01306/2267 isz 1267
|
||||||
|
01307/1667 tad i 1267
|
||||||
|
01310/1170 tad 170
|
||||||
|
01311/3322 dca 1322
|
||||||
|
01312/2267 isz 1267
|
||||||
|
01313/1667 tad i 1267
|
||||||
|
01314/3335 dca 1335
|
||||||
|
01315/2267 isz 1267
|
||||||
|
01316/7402 hlt
|
||||||
|
01317/1734 tad i 1334
|
||||||
|
01320/2334 isz 1334
|
||||||
|
01321/7000 nop
|
||||||
|
01322/7402 hlt
|
||||||
|
01323/3735 dca i 1335
|
||||||
|
01324/2335 isz 1335
|
||||||
|
01325/7000 nop
|
||||||
|
01326/2333 isz 1333
|
||||||
|
01327/5316 jmp 1316
|
||||||
|
01330/7200 cla
|
||||||
|
01331/7402 hlt
|
||||||
|
01332/5667 jmp i 1267
|
||||||
|
01333/0000 and 0
|
||||||
|
01334/0000 and 0
|
||||||
|
01335/0000 and 0
|
||||||
|
01400/0000 and 0
|
||||||
|
01401/7104 cll ral
|
||||||
|
01402/3042 dca 42
|
||||||
|
01403/1141 tad 141
|
||||||
|
01404/3043 dca 43
|
||||||
|
01405/1042 tad 42
|
||||||
|
01406/7006 rtl
|
||||||
|
01407/7004 ral
|
||||||
|
01410/3042 dca 42
|
||||||
|
01411/1042 tad 42
|
||||||
|
01412/0175 and 175
|
||||||
|
01413/1152 tad 152
|
||||||
|
01414/4551 jms i 151
|
||||||
|
01415/2043 isz 43
|
||||||
|
01416/5205 jmp 1405
|
||||||
|
01417/5600 jmp i 1400
|
||||||
|
01420/0000 and 0
|
||||||
|
01421/7200 cla
|
||||||
|
01422/1620 tad i 1420
|
||||||
|
01423/3042 dca 42
|
||||||
|
01424/2220 isz 1420
|
||||||
|
01425/1442 tad i 42
|
||||||
|
01426/7002 bsw
|
||||||
|
01427/4234 jms 1434
|
||||||
|
01430/1442 tad i 42
|
||||||
|
01431/4234 jms 1434
|
||||||
|
01432/2042 isz 42
|
||||||
|
01433/5225 jmp 1425
|
||||||
|
01434/0000 and 0
|
||||||
|
01435/0140 and 140
|
||||||
|
01436/7450 sna
|
||||||
|
01437/5620 jmp i 1420
|
||||||
|
01440/1137 tad 137
|
||||||
|
01441/7440 sza
|
||||||
|
01442/5245 jmp 1445
|
||||||
|
01443/4550 jms i 150
|
||||||
|
01444/5634 jmp i 1434
|
||||||
|
01445/7510 spa
|
||||||
|
01446/1136 tad 136
|
||||||
|
01447/1135 tad 135
|
||||||
|
01450/4551 jms i 151
|
||||||
|
01451/5634 jmp i 1434
|
||||||
|
01452/0000 and 0
|
||||||
|
01453/7200 cla
|
||||||
|
01454/1134 tad 134
|
||||||
|
01455/4551 jms i 151
|
||||||
|
01456/5652 jmp i 1452
|
||||||
|
01457/0000 and 0
|
||||||
|
01460/7200 cla
|
||||||
|
01461/1133 tad 133
|
||||||
|
01462/4551 jms i 151
|
||||||
|
01463/5657 jmp i 1457
|
||||||
|
01464/0000 and 0
|
||||||
|
01465/7200 cla
|
||||||
|
01466/1147 tad 147
|
||||||
|
01467/4551 jms i 151
|
||||||
|
01470/1132 tad 132
|
||||||
|
01471/4551 jms i 151
|
||||||
|
01472/5664 jmp i 1464
|
||||||
|
01473/0000 and 0
|
||||||
|
01474/6041 iot 4,1
|
||||||
|
01475/5274 jmp 1474
|
||||||
|
01476/0131 and 131
|
||||||
|
01477/6046 iot 4,6
|
||||||
|
01500/7200 cla
|
||||||
|
01501/5673 jmp i 1473
|
||||||
|
01502/0000 and 0
|
||||||
|
01503/7215 cla iac
|
||||||
|
01504/1173 tad 173
|
||||||
|
01505/7440 sza
|
||||||
|
01506/5311 jmp 1511
|
||||||
|
01507/1040 tad 40
|
||||||
|
01510/7410 skp
|
||||||
|
01511/7604 cla osr
|
||||||
|
01512/5702 jmp i 1502
|
||||||
|
01513/0000 and 0
|
||||||
|
01514/3042 dca 42
|
||||||
|
01515/7001 iac
|
||||||
|
01516/1041 tad 41
|
||||||
|
01517/3041 dca 41
|
||||||
|
01520/1042 tad 42
|
||||||
|
01521/5713 jmp i 1513
|
||||||
|
01522/0000 and 0
|
||||||
|
01523/3042 dca 42
|
||||||
|
01524/7040 cma
|
||||||
|
01525/1041 tad 41
|
||||||
|
01526/3041 dca 41
|
||||||
|
01527/1042 tad 42
|
||||||
|
01530/5722 jmp i 1522
|
||||||
|
01531/0000 and 0
|
||||||
|
01532/4347 jms 1547
|
||||||
|
01533/1053 tad 53
|
||||||
|
01534/3041 dca 41
|
||||||
|
01535/1051 tad 51
|
||||||
|
01536/1041 tad 41
|
||||||
|
01537/5731 jmp i 1531
|
||||||
|
01540/0000 and 0
|
||||||
|
01541/4347 jms 1547
|
||||||
|
01542/1054 tad 54
|
||||||
|
01543/3041 dca 41
|
||||||
|
01544/1051 tad 51
|
||||||
|
01545/1041 tad 41
|
||||||
|
01546/5740 jmp i 1540
|
||||||
|
01547/0000 and 0
|
||||||
|
01550/4056 jms 56
|
||||||
|
01551/7300 cla cll
|
||||||
|
01552/1057 tad 57
|
||||||
|
01553/7041 cma iac
|
||||||
|
01554/1064 tad 64
|
||||||
|
01555/7650 sna cla
|
||||||
|
01556/5362 jmp 1562
|
||||||
|
01557/3053 dca 53
|
||||||
|
01560/3055 dca 55
|
||||||
|
01561/5370 jmp 1570
|
||||||
|
01562/1130 tad 130
|
||||||
|
01563/3053 dca 53
|
||||||
|
01564/1054 tad 54
|
||||||
|
01565/7040 cma
|
||||||
|
01566/1053 tad 53
|
||||||
|
01567/3055 dca 55
|
||||||
|
01570/5747 jmp i 1547
|
||||||
|
01600/0000 and 0
|
||||||
|
01601/0000 and 0
|
||||||
|
01602/0000 and 0
|
||||||
|
01603/0000 and 0
|
||||||
|
01604/0000 and 0
|
||||||
|
01605/0000 and 0
|
||||||
|
01606/0000 and 0
|
||||||
|
01607/0000 and 0
|
||||||
|
01610/0000 and 0
|
||||||
|
01611/0000 and 0
|
||||||
|
01612/0000 and 0
|
||||||
|
01613/0000 and 0
|
||||||
|
01614/0000 and 0
|
||||||
|
01615/0000 and 0
|
||||||
|
01616/0000 and 0
|
||||||
|
01617/0000 and 0
|
||||||
|
01620/0000 and 0
|
||||||
|
01621/0000 and 0
|
||||||
|
01622/0000 and 0
|
||||||
|
01623/0000 and 0
|
||||||
|
01624/0000 and 0
|
||||||
|
01625/0000 and 0
|
||||||
|
01626/0000 and 0
|
||||||
|
01627/0000 and 0
|
||||||
|
01630/0000 and 0
|
||||||
|
01631/0000 and 0
|
||||||
|
01632/0000 and 0
|
||||||
|
01633/0000 and 0
|
||||||
|
01634/0000 and 0
|
||||||
|
01635/0000 and 0
|
||||||
|
01636/0000 and 0
|
||||||
|
01637/0000 and 0
|
||||||
|
01640/0000 and 0
|
||||||
|
01641/0000 and 0
|
||||||
|
01642/0000 and 0
|
||||||
|
01643/0000 and 0
|
||||||
|
01644/0000 and 0
|
||||||
|
01645/0000 and 0
|
||||||
|
01646/0000 and 0
|
||||||
|
01647/0000 and 0
|
||||||
|
01650/0000 and 0
|
||||||
|
01651/0000 and 0
|
||||||
|
01652/0000 and 0
|
||||||
|
01653/0000 and 0
|
||||||
|
01654/0000 and 0
|
||||||
|
01655/0000 and 0
|
||||||
|
01656/0000 and 0
|
||||||
|
01657/0000 and 0
|
||||||
|
01660/0000 and 0
|
||||||
|
01661/0000 and 0
|
||||||
|
01662/0000 and 0
|
||||||
|
01663/0000 and 0
|
||||||
|
01664/0000 and 0
|
||||||
|
01665/0000 and 0
|
||||||
|
01666/0000 and 0
|
||||||
|
01667/0000 and 0
|
||||||
|
01670/0000 and 0
|
||||||
|
01671/0000 and 0
|
||||||
|
01672/0000 and 0
|
||||||
|
01673/0000 and 0
|
||||||
|
01674/0000 and 0
|
||||||
|
01675/0000 and 0
|
||||||
|
01676/0000 and 0
|
||||||
|
01677/0000 and 0
|
||||||
|
01700/0000 and 0
|
||||||
|
01701/0000 and 0
|
||||||
|
01702/0000 and 0
|
||||||
|
01703/0000 and 0
|
||||||
|
01704/0000 and 0
|
||||||
|
01705/0000 and 0
|
||||||
|
01706/0000 and 0
|
||||||
|
01707/0000 and 0
|
||||||
|
01710/0000 and 0
|
||||||
|
01711/0000 and 0
|
||||||
|
01712/0000 and 0
|
||||||
|
01713/0000 and 0
|
||||||
|
01714/0000 and 0
|
||||||
|
01715/0000 and 0
|
||||||
|
01716/0000 and 0
|
||||||
|
01717/0000 and 0
|
||||||
|
01720/0000 and 0
|
||||||
|
01721/0000 and 0
|
||||||
|
01722/0000 and 0
|
||||||
|
01723/0000 and 0
|
||||||
|
01724/0000 and 0
|
||||||
|
01725/0000 and 0
|
||||||
|
01726/0000 and 0
|
||||||
|
01727/0000 and 0
|
||||||
|
01730/0000 and 0
|
||||||
|
01731/0000 and 0
|
||||||
|
01732/0000 and 0
|
||||||
|
01733/0000 and 0
|
||||||
|
01734/0000 and 0
|
||||||
|
01735/0000 and 0
|
||||||
|
01736/0000 and 0
|
||||||
|
01737/0000 and 0
|
||||||
|
01740/0000 and 0
|
||||||
|
01741/0000 and 0
|
||||||
|
01742/0000 and 0
|
||||||
|
01743/0000 and 0
|
||||||
|
01744/0000 and 0
|
||||||
|
01745/0000 and 0
|
||||||
|
01746/0000 and 0
|
||||||
|
01747/0000 and 0
|
||||||
|
01750/0000 and 0
|
||||||
|
01751/0000 and 0
|
||||||
|
01752/0000 and 0
|
||||||
|
01753/0000 and 0
|
||||||
|
01754/0000 and 0
|
||||||
|
01755/0000 and 0
|
||||||
|
01756/0000 and 0
|
||||||
|
01757/0000 and 0
|
||||||
|
01760/0000 and 0
|
||||||
|
01761/0000 and 0
|
||||||
|
01762/0000 and 0
|
||||||
|
01763/0000 and 0
|
||||||
|
01764/0000 and 0
|
||||||
|
01765/0000 and 0
|
||||||
|
01766/0000 and 0
|
||||||
|
01767/0000 and 0
|
||||||
|
01770/0000 and 0
|
||||||
|
01771/0000 and 0
|
||||||
|
01772/0000 and 0
|
||||||
|
01773/0000 and 0
|
||||||
|
01774/0000 and 0
|
||||||
|
01775/0000 and 0
|
||||||
|
01776/0000 and 0
|
||||||
|
01777/0000 and 0
|
||||||
|
00130/2000 isz 0
|
||||||
|
00131/0177 and 177
|
||||||
|
00132/0212 and 12
|
||||||
|
00133/0207 and 7
|
||||||
|
00134/0240 and 40
|
||||||
|
00135/0237 and 37
|
||||||
|
00136/0100 and 100
|
||||||
|
00137/7741 cla mqa
|
||||||
|
00140/0077 and 77
|
||||||
|
00141/7774 spa sna szl cla osr
|
||||||
|
00142/1452 tad i 52
|
||||||
|
00143/1751 tad i 151
|
||||||
|
00144/7743 cla mqa
|
||||||
|
00145/0017 and 17
|
||||||
|
00146/1700 tad i 100
|
||||||
|
00147/0215 and 15
|
||||||
|
00150/1464 tad i 64
|
||||||
|
00151/1473 tad i 73
|
||||||
|
00152/0260 and 60
|
||||||
|
00153/1400 tad i 0
|
||||||
|
00154/1420 tad i 20
|
||||||
|
00155/1457 tad i 57
|
||||||
|
00156/1000 tad 0
|
||||||
|
00157/1141 tad 141
|
||||||
|
00160/1107 tad 107
|
||||||
|
00161/1522 tad i 122
|
||||||
|
00162/1540 tad i 140
|
||||||
|
00163/1200 tad 0
|
||||||
|
00164/1513 tad i 113
|
||||||
|
00165/1531 tad i 131
|
||||||
|
00166/1062 tad 62
|
||||||
|
00167/0400 and i 0
|
||||||
|
00170/6201 iot 20,1
|
||||||
|
00171/0070 and 70
|
||||||
|
00172/1502 tad i 102
|
||||||
|
00173/7770 spa sna szl cla
|
||||||
|
00174/6440 iot 44,0
|
||||||
|
00175/0007 and 7
|
||||||
|
00176/1267 tad 67
|
||||||
|
00177/7600 cla
|
||||||
|
07751/0200 and 7600
|
||||||
|
07752/6032 iot 3,2
|
||||||
|
07753/1352 tad 7752
|
||||||
|
07754/3356 dca 7756
|
||||||
|
07755/5751 jmp i 7751
|
||||||
|
07756/5353 jmp 7753
|
||||||
|
CHKSUM: Computed: 3145, input: 3145 -- PASS
|
||||||
1120
d8tape/test.list
Normal file
1120
d8tape/test.list
Normal file
File diff suppressed because it is too large
Load Diff
1566
d8tape/test.lst
Normal file
1566
d8tape/test.lst
Normal file
File diff suppressed because it is too large
Load Diff
921
d8tape/test.pal
Normal file
921
d8tape/test.pal
Normal file
@ -0,0 +1,921 @@
|
|||||||
|
TITLE "simple MEMORY test"
|
||||||
|
/
|
||||||
|
/ start at 200
|
||||||
|
/
|
||||||
|
/ switch definitions
|
||||||
|
/
|
||||||
|
/ <0> 0=BELL at EOP / 1=silent
|
||||||
|
/ <1> 0=RUN / 1=STOP and restore loaders
|
||||||
|
/ <2:5> 0=all tests / !0=exec this test only
|
||||||
|
/ <6:8> unused
|
||||||
|
/ <9:11> FIELD to test, 0...7
|
||||||
|
/
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
/ macro definitions
|
||||||
|
|
||||||
|
DEFINE SDF N <
|
||||||
|
N^10+CDF >
|
||||||
|
|
||||||
|
DEFINE SIF N <
|
||||||
|
N^10+CIF >
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
*0
|
||||||
|
INIT, HLT / should never get here
|
||||||
|
HLT / should never get here
|
||||||
|
HLT / should never get here
|
||||||
|
HLT / should never get here
|
||||||
|
|
||||||
|
*40
|
||||||
|
SSR, 0001 / software switch register
|
||||||
|
PTR, 0 / memory ptr
|
||||||
|
TMP1, 0 / for print routines
|
||||||
|
TMP2, 0 / ditto
|
||||||
|
TMP3, 0 / ditto
|
||||||
|
TMP4, 0 / ditto
|
||||||
|
EXP, 0 / expected data
|
||||||
|
RCV, 0 / received data
|
||||||
|
TEST, 0 / test number
|
||||||
|
PASSES, 0 / pass count
|
||||||
|
ERRORS, 0 / error count
|
||||||
|
MEMBEG, 0 / start location (computed)
|
||||||
|
MEMEND, 7777 / last location to test
|
||||||
|
MEMCNT, 0 / -count of locations (computed)
|
||||||
|
|
||||||
|
R3L=7014 / on HD6120 only
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ set DF to test value
|
||||||
|
|
||||||
|
SETTDF, 0 / return address
|
||||||
|
SDF 5 / (replaced during init)
|
||||||
|
SDF 4 /
|
||||||
|
SDF 5 /
|
||||||
|
JMP I SETTDF / return
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ set DF to current value
|
||||||
|
|
||||||
|
SETCDF, 0 / return address
|
||||||
|
SIF 5 / (replaced during init)
|
||||||
|
SIF 4 /
|
||||||
|
SIF 5 /
|
||||||
|
JMP I SETCDF / return
|
||||||
|
|
||||||
|
PAGE
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
*200
|
||||||
|
START, CLA CLL / zero
|
||||||
|
CLA CLL IAC BSW / AC=100
|
||||||
|
DCA PASSES / init passcount
|
||||||
|
DCA ERRORS / init errorcount
|
||||||
|
TFL / enable printing
|
||||||
|
|
||||||
|
TAD [-200 / this many words in bootstrap
|
||||||
|
JMS I [CPMEM / copy memory
|
||||||
|
0^10 / src field
|
||||||
|
7600 / last page
|
||||||
|
0^10 / dst field
|
||||||
|
LOADER / copy to here
|
||||||
|
SKP / should return here
|
||||||
|
HLT / should not happen
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
LOOP, CLA / zero
|
||||||
|
TAD PASSES / get passcount
|
||||||
|
AND [0007 / low 3 bits
|
||||||
|
TAD [6440 / make into led IOT
|
||||||
|
DCA LEDS / store below
|
||||||
|
CLA IAC R3L / generate 0010 on HD6120 only
|
||||||
|
TAD [-10 / expected
|
||||||
|
SNA / skip if matches
|
||||||
|
LEDS, HLT / SBC6120 cpu, light leds
|
||||||
|
|
||||||
|
JMS I [READSR / get switch register
|
||||||
|
RTL ; RAL / shift left 3
|
||||||
|
AND [0070 / mask to 3b field
|
||||||
|
TAD [CDF / make CDF <N> instr
|
||||||
|
DCA SETTDF+1 / store into setup routine
|
||||||
|
RDF / get current DF
|
||||||
|
TAD [CDF / make CDF <N> instr
|
||||||
|
DCA SETCDF+1 / store into restore routine
|
||||||
|
DCA TEST / init test number
|
||||||
|
JMP I [TST1 / start
|
||||||
|
|
||||||
|
PAGE
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 1 - incr count pattern, incr address
|
||||||
|
/
|
||||||
|
/ pattern is (0000...7777) + PASSES
|
||||||
|
|
||||||
|
TST1, JMS I [CHKTST / check test number
|
||||||
|
-1 / should be this one
|
||||||
|
TST2 / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
TST1A, MQL ; MQA / save pattern in MQ
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST1A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
TST1B, MQL ; MQA / save pattern in MQ
|
||||||
|
CIA / invert pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST1C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST1C, MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST1B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 2 - incr count pattern, decr address
|
||||||
|
/
|
||||||
|
/ pattern is (0000...7777) + PASSES
|
||||||
|
|
||||||
|
TST2, JMS I [CHKTST / check test number
|
||||||
|
-2 / should be this one
|
||||||
|
TST3 / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
TST2A, MQL ; MQA / save pattern in MQ
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST2A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
TST2B, MQL ; MQA / save pattern in MQ
|
||||||
|
CIA / invert pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST2C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST2C, MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST2B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 3 - incr/shifted count pattern, incr addr
|
||||||
|
/
|
||||||
|
/ pattern is (0000...7777) rotl (PASSES%16) + PASSES
|
||||||
|
|
||||||
|
TST3, JMS I [CHKTST / check test number
|
||||||
|
-3 / should be this one
|
||||||
|
TST4 / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
TST3A, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST3A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
TST3B, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
CIA / invert pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST3C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST3C, MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST3B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 4 - incr/shifted count pattern, decr addr
|
||||||
|
/
|
||||||
|
/ pattern is (0000...7777) rotl (PASSES%16) + PASSES
|
||||||
|
|
||||||
|
TST4, JMS I [CHKTST / check test number
|
||||||
|
-4 / should be this one
|
||||||
|
TST5 / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
TST4A, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST4A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
TST4B, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
CIA / invert pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST4C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST4C, MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST4B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 5 - decr/shifted count pattern, incr addr
|
||||||
|
/
|
||||||
|
/ pattern is (7777...0000) rotl (PASSES%16) + PASSES
|
||||||
|
|
||||||
|
TST5, JMS I [CHKTST / check test number
|
||||||
|
-5 / should be this one
|
||||||
|
TST6 / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
TST5A, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
CMA / and invert
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST5A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
TST5B, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
IAC / invert pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST5C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
CMA / and invert
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST5C, MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST5B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 6 - decr/shifted count pattern, decr addr
|
||||||
|
/
|
||||||
|
/ pattern is (7777...0000) rotl (PASSES%16) + PASSES
|
||||||
|
|
||||||
|
TST6, JMS I [CHKTST / check test number
|
||||||
|
-6 / should be this one
|
||||||
|
TST7 / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
TST6A, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
CMA / and invert
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST6A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
TST6B, MQL ; MQA / save pattern in MQ
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
IAC / invert pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST6C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
JMS I [ROTPAT / rotate AC left by PASSES%16
|
||||||
|
CMA / and invert
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST6C, MQA ; IAC / restore pattern and bump
|
||||||
|
JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST6B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 7 - random data pattern, incr addr
|
||||||
|
/
|
||||||
|
/ pattern is (AC<-29*AC+1001) + PASSES
|
||||||
|
|
||||||
|
TST7, JMS I [CHKTST / check test number
|
||||||
|
-7 / should be this one
|
||||||
|
TST10 / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
MQL / save seed in MQ, clear AC
|
||||||
|
TST7A, JMS I [RAND2 / AC,MQ <- 29*MQ+1001
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST7A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPI / setup data field
|
||||||
|
MQL / save seed in MQ, clear AC
|
||||||
|
TST7B, JMS I [RAND2 / AC,MQ <- 29*MQ+1001
|
||||||
|
CIA / negate pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST7C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST7C, JMS I [PTRINC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST7B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
/ TEST 10 - random data pattern, decr addr
|
||||||
|
/
|
||||||
|
/ pattern is (AC<-29*AC+1001) + PASSES
|
||||||
|
|
||||||
|
TST10, JMS I [CHKTST / check test number
|
||||||
|
-10 / should be this one
|
||||||
|
EOP / return here to skip test
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
MQL / save seed in MQ, clear AC
|
||||||
|
TST10A, JMS I [RAND2 / AC,MQ <- 29*MQ+1001
|
||||||
|
DCA I PTR / store data pattern
|
||||||
|
JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST10A / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS I [SETUPD / setup data field
|
||||||
|
MQL / save seed in MQ, clear AC
|
||||||
|
TST10B, JMS I [RAND2 / AC,MQ <- 29*MQ+1001
|
||||||
|
CIA / negate pattern for test
|
||||||
|
TAD I PTR / get data pattern
|
||||||
|
SNA / OK if AC is zero
|
||||||
|
JMP TST10C / jump if OK
|
||||||
|
DCA RCV / save received
|
||||||
|
MQA / get pattern
|
||||||
|
DCA EXP / save expected
|
||||||
|
JMS I [PRTERR / ***ERROR***
|
||||||
|
TST10C, JMS I [PTRDEC / bump ptr
|
||||||
|
ISZ MEMCNT / bump count
|
||||||
|
JMP TST10B / loop if hasn't wrapped
|
||||||
|
|
||||||
|
JMS SETCDF / back to normal
|
||||||
|
JMP I [EOP / done
|
||||||
|
|
||||||
|
PAGE
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
/////// END OF PASS ///////
|
||||||
|
|
||||||
|
EOP, ISZ PASSES / count passes
|
||||||
|
SKP / don't let it be zero
|
||||||
|
JMP .-2 / again
|
||||||
|
|
||||||
|
CLA / zero
|
||||||
|
TAD [-200 / restore bootstrap from saved
|
||||||
|
JMS I [CPMEM / copy memory
|
||||||
|
0^10 / src field
|
||||||
|
LOADER / copy to here
|
||||||
|
0^10 / dst field
|
||||||
|
7600 / last page
|
||||||
|
|
||||||
|
JMS I [READSR / get switches
|
||||||
|
SMA / skip on SR<0> set
|
||||||
|
JMS I [PRBEL / ring BELL if bit0 clear
|
||||||
|
JMS I [PRAST / print message
|
||||||
|
EOPM1 / from here
|
||||||
|
TAD PASSES / get passcount
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PRAST / print message
|
||||||
|
EOPM2 / from here
|
||||||
|
TAD SETTDF+1 / field we are testing
|
||||||
|
CLL RTR ; RAR / shift right three bits
|
||||||
|
AND [0007 / one digit
|
||||||
|
TAD [0260 / make ascii
|
||||||
|
JMS I [PRCHR / print
|
||||||
|
JMS I [PRAST / print message
|
||||||
|
EOPM3 / from here
|
||||||
|
TAD ERRORS / get errorcount
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PREOL / print end of line
|
||||||
|
|
||||||
|
JMS I [READSR / get switches again
|
||||||
|
RTL / isolate SR<1> halt switch
|
||||||
|
SNL / skip if set
|
||||||
|
JMP I [LOOP / keep going
|
||||||
|
HLT / halt
|
||||||
|
JMP I [LOOP / restart
|
||||||
|
|
||||||
|
EOPM1, TEXT "END PASS "
|
||||||
|
EOPM2, TEXT " FIELD "
|
||||||
|
EOPM3, TEXT " ERRORS "
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ check test number sequence
|
||||||
|
/
|
||||||
|
/ first word is negative of expected test number
|
||||||
|
/ second word is addr of where to go to if skipping this test
|
||||||
|
/
|
||||||
|
/ uses indirect data address mode
|
||||||
|
|
||||||
|
CHKTST, 0 / return address
|
||||||
|
CLA CLL / clear AC LK
|
||||||
|
ISZ TEST / bump test number
|
||||||
|
TAD TEST / and get it to AC
|
||||||
|
TAD I CHKTST / add negative of expected number
|
||||||
|
SZA / should be zero...
|
||||||
|
HLT / ***ERROR***
|
||||||
|
JMS I [READSR / get switches
|
||||||
|
AND [1700 / mask to bits 2-5 only
|
||||||
|
SNA / skip if not zero
|
||||||
|
JMP CHK2 / zero - execute all tests
|
||||||
|
TAD I CHKTST / compare current:selected
|
||||||
|
SNA CLA / skip if not equal
|
||||||
|
JMP CHK2 / jmp if equal; execute test
|
||||||
|
ISZ CHKTST / point to skip-test address
|
||||||
|
TAD I CHKTST / get address
|
||||||
|
DCA CHKTST / store as return
|
||||||
|
JMP I CHKTST / return
|
||||||
|
CHK2, ISZ CHKTST / point to skip-test address
|
||||||
|
ISZ CHKTST / point to normal return
|
||||||
|
JMP I CHKTST / return
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ circular rotate AC left by PASSES%16
|
||||||
|
/
|
||||||
|
/ return with AC updated
|
||||||
|
/ uses TMP1-2
|
||||||
|
|
||||||
|
SAVEAC=TMP1
|
||||||
|
COUNT=TMP2
|
||||||
|
|
||||||
|
ROTPAT, 0 / return address
|
||||||
|
DCA SAVEAC / save AC
|
||||||
|
TAD PASSES / get passcount
|
||||||
|
AND [17 / mask to low 4 bits
|
||||||
|
CMA / change to 7777..7760 range
|
||||||
|
DCA COUNT / save counter
|
||||||
|
TAD SAVEAC / get value
|
||||||
|
ROT1, CLL RAL / LK|AC<<1
|
||||||
|
SZL / check bit shifted out
|
||||||
|
IAC / was 1, insert into bit11
|
||||||
|
ISZ COUNT / count
|
||||||
|
JMP ROT1 / loop if more
|
||||||
|
JMP I ROTPAT / return
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ generate random number
|
||||||
|
/
|
||||||
|
/ return with AC,MQ <- 29*MQ + 1001
|
||||||
|
/ uses TMP1-2
|
||||||
|
|
||||||
|
COUNT=TMP1
|
||||||
|
MULT=TMP2
|
||||||
|
|
||||||
|
RAND1, 0 / return address
|
||||||
|
CLA / zap
|
||||||
|
TAD [-35 / -29
|
||||||
|
DCA COUNT / init multiplier
|
||||||
|
CLA MQA / AC <- MQ
|
||||||
|
DCA MULT / init multiplicand
|
||||||
|
RAND1A, TAD MULT / add multiplicand
|
||||||
|
ISZ COUNT / decr multiplier
|
||||||
|
JMP RAND1A / loop
|
||||||
|
TAD [1751 / +1001
|
||||||
|
MQL ; MQA / MQ <- AC ; AC <- MQ
|
||||||
|
JMP I RAND1 / return
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ generate random number
|
||||||
|
/
|
||||||
|
/ return with AC,MQ <- 29*MQ + 1001
|
||||||
|
/ uses TMP1-2
|
||||||
|
|
||||||
|
MULT=TMP1
|
||||||
|
|
||||||
|
RAND2, 0 / return address
|
||||||
|
CLA MQA / AC <- MQ
|
||||||
|
DCA MULT / init multiplicand
|
||||||
|
TAD MULT / *1
|
||||||
|
CLL RAL / *2
|
||||||
|
CLL RAL / *4
|
||||||
|
TAD MULT / *5
|
||||||
|
TAD MULT / *6
|
||||||
|
TAD MULT / *7
|
||||||
|
CLL RAL / *14
|
||||||
|
CLL RAL / *28
|
||||||
|
TAD MULT / *29
|
||||||
|
TAD [1751 / +1001
|
||||||
|
MQL ; MQA / MQ <- AC ; AC <- MQ
|
||||||
|
JMP I RAND2 / return
|
||||||
|
|
||||||
|
PAGE
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ print error message
|
||||||
|
/
|
||||||
|
/ return with AC=0
|
||||||
|
|
||||||
|
PRTERR, 0 / return address
|
||||||
|
CLA / zero
|
||||||
|
TAD ERRORS / get error count
|
||||||
|
AND [17 / get low four bits
|
||||||
|
SZA CLA / test
|
||||||
|
JMP PRTER1 / skip print
|
||||||
|
JMS SETCDF / back to current DF
|
||||||
|
JMS I [PRAST / print text
|
||||||
|
PRTER2 / header
|
||||||
|
JMS SETTDF / back to test DF
|
||||||
|
PRTER1, TAD PASSES / get passcount
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PRSPA / print a space
|
||||||
|
TAD ERRORS / get error count
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PRSPA / print space
|
||||||
|
TAD TEST / get test number
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PRSPA / print a space
|
||||||
|
RDF / get data field
|
||||||
|
CLL RTR ; RAR / shift right three bits
|
||||||
|
TAD [0260 / make ascii
|
||||||
|
JMS I [PRCHR / print
|
||||||
|
TAD PTR / get test address
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PRSPA / print a space
|
||||||
|
TAD EXP / get expected
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PRSPA / print a space
|
||||||
|
TAD RCV / received data
|
||||||
|
TAD EXP / add back expected
|
||||||
|
JMS I [PROCT / print octal
|
||||||
|
JMS I [PREOL / end of line
|
||||||
|
ISZ ERRORS / count errors
|
||||||
|
SKP /
|
||||||
|
JMP .-2 / don't let go to zero
|
||||||
|
JMP I PRTERR / return
|
||||||
|
|
||||||
|
PRTER2, TEXT "_PASS ERRS TEST ADDRS EXPD RCVD_"
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ copy memory from SRC to DST for COUNT
|
||||||
|
/
|
||||||
|
/ call: TAD (-COUNT
|
||||||
|
/ JMS CPMEM
|
||||||
|
/ SRCFIELD<6:8>
|
||||||
|
/ SRCADDRESS<0:11>
|
||||||
|
/ DSTFIELD<6:8>
|
||||||
|
/ DSTADDRESS<0:11>
|
||||||
|
/ return with AC=0
|
||||||
|
/ uses indirect data address mode
|
||||||
|
|
||||||
|
CPMEM, 0 / return address
|
||||||
|
DCA CPMEMX / save count
|
||||||
|
RDF / get current DF
|
||||||
|
TAD [CDF / make into CDF<D>
|
||||||
|
DCA CPMEM9 / save for return
|
||||||
|
RIF / get current IF
|
||||||
|
TAD [CDF / make into CDF<I>
|
||||||
|
DCA .+1 / store
|
||||||
|
HLT / replaced with CDF<I>
|
||||||
|
TAD I CPMEM / get SRCFIELD
|
||||||
|
TAD [CDF / make into CDF<S>
|
||||||
|
DCA CPMEM7 / store
|
||||||
|
ISZ CPMEM / bump
|
||||||
|
TAD I CPMEM / get SRCADDR
|
||||||
|
DCA CPMEMS / store
|
||||||
|
ISZ CPMEM / bump
|
||||||
|
TAD I CPMEM / get DSTFIELD
|
||||||
|
TAD [CDF / make into CDF<T>
|
||||||
|
DCA CPMEM8 / store
|
||||||
|
ISZ CPMEM / bump
|
||||||
|
TAD I CPMEM / get DSTADDR
|
||||||
|
DCA CPMEMD / store
|
||||||
|
ISZ CPMEM / bump
|
||||||
|
CPMEM7, HLT / replaced with CDF<S>
|
||||||
|
TAD I CPMEMS / get src data
|
||||||
|
ISZ CPMEMS / bump ptr
|
||||||
|
NOP / allow for zero
|
||||||
|
CPMEM8, HLT / replaced with CDF<T>
|
||||||
|
DCA I CPMEMD / store dst data
|
||||||
|
ISZ CPMEMD / bump ptr
|
||||||
|
NOP / allow for zero
|
||||||
|
ISZ CPMEMX / count words
|
||||||
|
JMP CPMEM7 / loop
|
||||||
|
CLA / zero
|
||||||
|
CPMEM9, HLT / replaced with CDF<D>
|
||||||
|
JMP I CPMEM / return
|
||||||
|
|
||||||
|
CPMEMX, 0 / -count of words
|
||||||
|
CPMEMS, 0 / source address
|
||||||
|
CPMEMD, 0 / target address
|
||||||
|
|
||||||
|
PAGE
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ octal print routine of AC (4 digit)
|
||||||
|
/
|
||||||
|
/ return with AC=0
|
||||||
|
/ uses TMP1-2
|
||||||
|
|
||||||
|
VALUE=TMP1
|
||||||
|
COUNT=TMP2
|
||||||
|
|
||||||
|
PROCT, 0 / return address
|
||||||
|
CLL RAL / rotate into L,AC<0:10>
|
||||||
|
DCA VALUE / save number
|
||||||
|
TAD [-4 / digit count
|
||||||
|
DCA COUNT / save
|
||||||
|
PROCT1, TAD VALUE / rotate number left 3
|
||||||
|
RTL ; RAL /
|
||||||
|
DCA VALUE / save other bits
|
||||||
|
TAD VALUE /
|
||||||
|
AND [0007 / mask digit
|
||||||
|
TAD [0260 / make ascii
|
||||||
|
JMS I [PRCHR / print one char
|
||||||
|
ISZ COUNT / count digits
|
||||||
|
JMP PROCT1 / loop
|
||||||
|
JMP I PROCT / return
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ text print routine, addr of string in next word
|
||||||
|
/ string is two 6b characters per word
|
||||||
|
/ 00(@) to terminate string, 37(_) prints CRLF sequence
|
||||||
|
/
|
||||||
|
/ return with AC=0
|
||||||
|
/ uses TMP1
|
||||||
|
/ uses indirect data address mode
|
||||||
|
|
||||||
|
STPTR=TMP1
|
||||||
|
|
||||||
|
PRAST, 0 / return address
|
||||||
|
CLA / zero
|
||||||
|
TAD I PRAST / get ptr to string
|
||||||
|
DCA STPTR / store ptr
|
||||||
|
ISZ PRAST / bump addr +1
|
||||||
|
PRAST1, TAD I STPTR / get two chars
|
||||||
|
BSW / move upper 6b to low
|
||||||
|
JMS PRAST2 / go print
|
||||||
|
TAD I STPTR / get two chars
|
||||||
|
JMS PRAST2 / go print
|
||||||
|
ISZ STPTR / bump ptr
|
||||||
|
JMP PRAST1 / loop
|
||||||
|
|
||||||
|
/ print one 6b char in AC<6:11> as 8b ascii
|
||||||
|
|
||||||
|
PRAST2, 0 / return address
|
||||||
|
AND [77 / mask low 6b
|
||||||
|
SNA / skip if not 00
|
||||||
|
JMP I PRAST / return from caller
|
||||||
|
TAD [-37 / check for 37
|
||||||
|
SZA / skip if 37
|
||||||
|
JMP PRAST3 / jmp if not 37
|
||||||
|
JMS I [PREOL / print CRLF
|
||||||
|
JMP I PRAST2 / return
|
||||||
|
PRAST3, SPA / skip if 40..77
|
||||||
|
TAD [100 / 01..36 maps to 301..336
|
||||||
|
TAD [237 / 40..77 maps to 240..277
|
||||||
|
JMS I [PRCHR / print character
|
||||||
|
JMP I PRAST2 / return
|
||||||
|
|
||||||
|
/ TEXT ~@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_~ / 00..37 -> 300..337
|
||||||
|
/ TEXT ~ !"#$%&'()*+,-./0123456789:;<=>?~ / 40..77 -> 240..277
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ print a SPACE
|
||||||
|
/
|
||||||
|
/ return with AC=0
|
||||||
|
|
||||||
|
PRSPA, 0 / return address
|
||||||
|
CLA / zero
|
||||||
|
TAD [240 / SP
|
||||||
|
JMS I [PRCHR / print one char
|
||||||
|
JMP I PRSPA / return
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ print a BELL
|
||||||
|
/
|
||||||
|
/ return with AC=0
|
||||||
|
|
||||||
|
PRBEL, 0 / return address
|
||||||
|
CLA / zero
|
||||||
|
TAD [207 / BELL
|
||||||
|
JMS I [PRCHR / print one char
|
||||||
|
JMP I PRBEL / return
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ print a CRLF sequence
|
||||||
|
/
|
||||||
|
/ return with AC=0
|
||||||
|
|
||||||
|
PREOL, 0 / return address
|
||||||
|
CLA / zero
|
||||||
|
TAD [215 / CR
|
||||||
|
JMS I [PRCHR / print one char
|
||||||
|
TAD [212 / CR
|
||||||
|
JMS I [PRCHR / print one char
|
||||||
|
JMP I PREOL / return
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ print one character from AC
|
||||||
|
/
|
||||||
|
/ return with AC=0
|
||||||
|
|
||||||
|
PRCHR, 0 / return address
|
||||||
|
TSF / wait for done
|
||||||
|
JMP .-1 / loop until done
|
||||||
|
AND [177 / mask to 7 bits
|
||||||
|
TLS / print character
|
||||||
|
CLA / zero
|
||||||
|
JMP I PRCHR / return
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ get h/w or s/w switch register, as appropriate
|
||||||
|
/
|
||||||
|
/ return with AC=SR
|
||||||
|
|
||||||
|
READSR, 0 / return address
|
||||||
|
CLA IAC R3L / generate 0010 on HD6120 only
|
||||||
|
TAD [-10 / expected
|
||||||
|
SZA / skip if matches
|
||||||
|
JMP .+3 / non-6120 cpu, go do LAS
|
||||||
|
TAD SSR / load s/w switches
|
||||||
|
SKP / skip over next
|
||||||
|
LAS / load h/w switches
|
||||||
|
JMP I READSR / return
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ ptr <- ptr+1
|
||||||
|
/ uses TMP1
|
||||||
|
|
||||||
|
SAVEAC=TMP1
|
||||||
|
|
||||||
|
PTRINC, 0 / return address
|
||||||
|
DCA SAVEAC / save AC
|
||||||
|
IAC / +1
|
||||||
|
TAD PTR / PTR+1
|
||||||
|
DCA PTR / save
|
||||||
|
TAD SAVEAC / restore AC
|
||||||
|
JMP I PTRINC / return
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ ptr <- ptr-1
|
||||||
|
/ uses TMP1
|
||||||
|
|
||||||
|
SAVEAC=TMP1
|
||||||
|
|
||||||
|
PTRDEC, 0 / return address
|
||||||
|
DCA SAVEAC / save AC
|
||||||
|
CMA / -1
|
||||||
|
TAD PTR / PTR-1
|
||||||
|
DCA PTR / save
|
||||||
|
TAD SAVEAC / restore AC
|
||||||
|
JMP I PTRDEC / return
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
/
|
||||||
|
/ set DF to current test field, adjust PTR as necessary
|
||||||
|
/
|
||||||
|
/ setup MEMBEG,MEMCNT depending upon DF selected
|
||||||
|
/ setup PTR to MEMBEG or MEMEND
|
||||||
|
/ return with AC=PASSES
|
||||||
|
|
||||||
|
SETUPI, 0 / return address
|
||||||
|
JMS SETUPX / common setup
|
||||||
|
TAD MEMBEG / starting test location
|
||||||
|
DCA PTR / into memory ptr
|
||||||
|
TAD PASSES / get passcount into AC
|
||||||
|
TAD PTR / start at ptr
|
||||||
|
JMP I SETUPI / return
|
||||||
|
|
||||||
|
SETUPD, 0 / return address
|
||||||
|
JMS SETUPX / common setup
|
||||||
|
TAD MEMEND / ending test location
|
||||||
|
DCA PTR / into memory ptr
|
||||||
|
TAD PASSES / get passcount into AC
|
||||||
|
TAD PTR / start at ptr
|
||||||
|
JMP I SETUPD / return
|
||||||
|
|
||||||
|
SETUPX, 0 / return address
|
||||||
|
JMS SETTDF / set test data field
|
||||||
|
CLA CLL / clear AC and LK
|
||||||
|
TAD SETTDF+1 / get test DF
|
||||||
|
CIA / negate for test
|
||||||
|
TAD SETCDF+1 / get current DF
|
||||||
|
SNA CLA / skip if not equal; clr AC
|
||||||
|
JMP SETUP1 / jmp if equal
|
||||||
|
DCA MEMBEG / set MEMBEG to 0000
|
||||||
|
DCA MEMCNT / set MEMCNT to -10000
|
||||||
|
JMP SETUP2 / continue
|
||||||
|
SETUP1, TAD [MEMTST / first free location
|
||||||
|
DCA MEMBEG / set MEMBEG to MEMTST
|
||||||
|
TAD MEMEND / MEMEND
|
||||||
|
CMA / -(MEMEND+1)
|
||||||
|
TAD MEMBEG / MEMBEG-(MEMEND+1)
|
||||||
|
DCA MEMCNT / into MEMCNT
|
||||||
|
SETUP2, JMP I SETUPX / return
|
||||||
|
|
||||||
|
EJECT
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
PAGE / start of next page
|
||||||
|
LOADER, ZBLOCK 200 /
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
PAGE / start of next page
|
||||||
|
MEMTST, / dummy
|
||||||
|
|
||||||
|
/ ------------------------------------------------------------
|
||||||
|
|
||||||
|
/ autostart program after download via RIMLDR
|
||||||
|
|
||||||
|
*0 / page 0
|
||||||
|
LITBAS / force all literals out
|
||||||
|
*7751 / align to RIMLDR location
|
||||||
|
START / addr of program start
|
||||||
|
KCC / first instr in std RIMLDR
|
||||||
|
TAD .-1 / get KCC instr
|
||||||
|
DCA .+2 / restore into RIMLDR
|
||||||
|
JMP I .-4 / start program
|
||||||
|
JMP .-3 / overlay first word of RIMLDR
|
||||||
|
|
||||||
|
$ / the end
|
||||||
BIN
d8tape/verify.bin
Normal file
BIN
d8tape/verify.bin
Normal file
Binary file not shown.
806
d8tape/verify.dump
Normal file
806
d8tape/verify.dump
Normal file
@ -0,0 +1,806 @@
|
|||||||
|
00000/7402 hlt
|
||||||
|
00001/7402 hlt
|
||||||
|
00002/7402 hlt
|
||||||
|
00003/7402 hlt
|
||||||
|
00040/0001 and 1
|
||||||
|
00041/0000 and 0
|
||||||
|
00042/0000 and 0
|
||||||
|
00043/0000 and 0
|
||||||
|
00044/0000 and 0
|
||||||
|
00045/0000 and 0
|
||||||
|
00046/0000 and 0
|
||||||
|
00047/0000 and 0
|
||||||
|
00050/0000 and 0
|
||||||
|
00051/0000 and 0
|
||||||
|
00052/0000 and 0
|
||||||
|
00053/0000 and 0
|
||||||
|
00054/7777 cla mqa mql
|
||||||
|
00055/0000 and 0
|
||||||
|
00056/0000 and 0
|
||||||
|
00057/6251 iot 25,1
|
||||||
|
00060/6241 iot 24,1
|
||||||
|
00061/6251 iot 25,1
|
||||||
|
00062/5456 jmp i 56
|
||||||
|
00063/0000 and 0
|
||||||
|
00064/6252 iot 25,2
|
||||||
|
00065/6242 iot 24,2
|
||||||
|
00066/6252 iot 25,2
|
||||||
|
00067/5463 jmp i 63
|
||||||
|
00200/7300 cla cll
|
||||||
|
00201/7303 cla cll iac bsw
|
||||||
|
00202/3051 dca 51
|
||||||
|
00203/3052 dca 52
|
||||||
|
00204/6040 iot 4,0
|
||||||
|
00205/1177 tad 177
|
||||||
|
00206/4576 jms i 176
|
||||||
|
00207/0000 and 0
|
||||||
|
00210/7600 cla
|
||||||
|
00211/0000 and 0
|
||||||
|
00212/1600 tad i 200
|
||||||
|
00213/7410 skp
|
||||||
|
00214/7402 hlt
|
||||||
|
00215/7200 cla
|
||||||
|
00216/1051 tad 51
|
||||||
|
00217/0175 and 175
|
||||||
|
00220/1174 tad 174
|
||||||
|
00221/3225 dca 225
|
||||||
|
00222/7215 cla iac
|
||||||
|
00223/1173 tad 173
|
||||||
|
00224/7450 sna
|
||||||
|
00225/7402 hlt
|
||||||
|
00226/4572 jms i 172
|
||||||
|
00227/7006 rtl
|
||||||
|
00230/7004 ral
|
||||||
|
00231/0171 and 171
|
||||||
|
00232/1170 tad 170
|
||||||
|
00233/3057 dca 57
|
||||||
|
00234/6214 iot 21,4
|
||||||
|
00235/1170 tad 170
|
||||||
|
00236/3064 dca 64
|
||||||
|
00237/3050 dca 50
|
||||||
|
00240/5567 jmp i 167
|
||||||
|
00400/4566 jms i 166
|
||||||
|
00401/7777 cla mqa mql
|
||||||
|
00402/0435 and i 35
|
||||||
|
00403/4565 jms i 165
|
||||||
|
00404/7421 mql
|
||||||
|
00405/7501 mqa
|
||||||
|
00406/3441 dca i 41
|
||||||
|
00407/7501 mqa
|
||||||
|
00410/7001 iac
|
||||||
|
00411/4564 jms i 164
|
||||||
|
00412/2055 isz 55
|
||||||
|
00413/5204 jmp 404
|
||||||
|
00414/4565 jms i 165
|
||||||
|
00415/7421 mql
|
||||||
|
00416/7501 mqa
|
||||||
|
00417/7041 cma iac
|
||||||
|
00420/1441 tad i 41
|
||||||
|
00421/7450 sna
|
||||||
|
00422/5227 jmp 427
|
||||||
|
00423/3047 dca 47
|
||||||
|
00424/7501 mqa
|
||||||
|
00425/3046 dca 46
|
||||||
|
00426/4563 jms i 163
|
||||||
|
00427/7501 mqa
|
||||||
|
00430/7001 iac
|
||||||
|
00431/4564 jms i 164
|
||||||
|
00432/2055 isz 55
|
||||||
|
00433/5215 jmp 415
|
||||||
|
00434/4063 jms 63
|
||||||
|
00435/4566 jms i 166
|
||||||
|
00436/7776 spa sna szl cla osr hlt
|
||||||
|
00437/0472 and i 72
|
||||||
|
00440/4562 jms i 162
|
||||||
|
00441/7421 mql
|
||||||
|
00442/7501 mqa
|
||||||
|
00443/3441 dca i 41
|
||||||
|
00444/7501 mqa
|
||||||
|
00445/7001 iac
|
||||||
|
00446/4561 jms i 161
|
||||||
|
00447/2055 isz 55
|
||||||
|
00450/5241 jmp 441
|
||||||
|
00451/4562 jms i 162
|
||||||
|
00452/7421 mql
|
||||||
|
00453/7501 mqa
|
||||||
|
00454/7041 cma iac
|
||||||
|
00455/1441 tad i 41
|
||||||
|
00456/7450 sna
|
||||||
|
00457/5264 jmp 464
|
||||||
|
00460/3047 dca 47
|
||||||
|
00461/7501 mqa
|
||||||
|
00462/3046 dca 46
|
||||||
|
00463/4563 jms i 163
|
||||||
|
00464/7501 mqa
|
||||||
|
00465/7001 iac
|
||||||
|
00466/4561 jms i 161
|
||||||
|
00467/2055 isz 55
|
||||||
|
00470/5252 jmp 452
|
||||||
|
00471/4063 jms 63
|
||||||
|
00472/4566 jms i 166
|
||||||
|
00473/7775 cla mqa mql
|
||||||
|
00474/0532 and i 132
|
||||||
|
00475/4565 jms i 165
|
||||||
|
00476/7421 mql
|
||||||
|
00477/7501 mqa
|
||||||
|
00500/4560 jms i 160
|
||||||
|
00501/3441 dca i 41
|
||||||
|
00502/7501 mqa
|
||||||
|
00503/7001 iac
|
||||||
|
00504/4564 jms i 164
|
||||||
|
00505/2055 isz 55
|
||||||
|
00506/5276 jmp 476
|
||||||
|
00507/4565 jms i 165
|
||||||
|
00510/7421 mql
|
||||||
|
00511/7501 mqa
|
||||||
|
00512/4560 jms i 160
|
||||||
|
00513/7041 cma iac
|
||||||
|
00514/1441 tad i 41
|
||||||
|
00515/7450 sna
|
||||||
|
00516/5324 jmp 524
|
||||||
|
00517/3047 dca 47
|
||||||
|
00520/7501 mqa
|
||||||
|
00521/4560 jms i 160
|
||||||
|
00522/3046 dca 46
|
||||||
|
00523/4563 jms i 163
|
||||||
|
00524/7501 mqa
|
||||||
|
00525/7001 iac
|
||||||
|
00526/4564 jms i 164
|
||||||
|
00527/2055 isz 55
|
||||||
|
00530/5310 jmp 510
|
||||||
|
00531/4063 jms 63
|
||||||
|
00532/4566 jms i 166
|
||||||
|
00533/7774 spa sna szl cla osr
|
||||||
|
00534/0572 and i 172
|
||||||
|
00535/4562 jms i 162
|
||||||
|
00536/7421 mql
|
||||||
|
00537/7501 mqa
|
||||||
|
00540/4560 jms i 160
|
||||||
|
00541/3441 dca i 41
|
||||||
|
00542/7501 mqa
|
||||||
|
00543/7001 iac
|
||||||
|
00544/4561 jms i 161
|
||||||
|
00545/2055 isz 55
|
||||||
|
00546/5336 jmp 536
|
||||||
|
00547/4562 jms i 162
|
||||||
|
00550/7421 mql
|
||||||
|
00551/7501 mqa
|
||||||
|
00552/4560 jms i 160
|
||||||
|
00553/7041 cma iac
|
||||||
|
00554/1441 tad i 41
|
||||||
|
00555/7450 sna
|
||||||
|
00556/5364 jmp 564
|
||||||
|
00557/3047 dca 47
|
||||||
|
00560/7501 mqa
|
||||||
|
00561/4560 jms i 160
|
||||||
|
00562/3046 dca 46
|
||||||
|
00563/4563 jms i 163
|
||||||
|
00564/7501 mqa
|
||||||
|
00565/7001 iac
|
||||||
|
00566/4561 jms i 161
|
||||||
|
00567/2055 isz 55
|
||||||
|
00570/5350 jmp 550
|
||||||
|
00571/4063 jms 63
|
||||||
|
00572/4566 jms i 166
|
||||||
|
00573/7773 cla mqa mql
|
||||||
|
00574/0634 and i 434
|
||||||
|
00575/4565 jms i 165
|
||||||
|
00576/7421 mql
|
||||||
|
00577/7501 mqa
|
||||||
|
00600/4560 jms i 160
|
||||||
|
00601/7040 cma
|
||||||
|
00602/3441 dca i 41
|
||||||
|
00603/7501 mqa
|
||||||
|
00604/7001 iac
|
||||||
|
00605/4564 jms i 164
|
||||||
|
00606/2055 isz 55
|
||||||
|
00607/5777 jmp i 777
|
||||||
|
00610/4565 jms i 165
|
||||||
|
00611/7421 mql
|
||||||
|
00612/7501 mqa
|
||||||
|
00613/4560 jms i 160
|
||||||
|
00614/7001 iac
|
||||||
|
00615/1441 tad i 41
|
||||||
|
00616/7450 sna
|
||||||
|
00617/5226 jmp 626
|
||||||
|
00620/3047 dca 47
|
||||||
|
00621/7501 mqa
|
||||||
|
00622/4560 jms i 160
|
||||||
|
00623/7040 cma
|
||||||
|
00624/3046 dca 46
|
||||||
|
00625/4563 jms i 163
|
||||||
|
00626/7501 mqa
|
||||||
|
00627/7001 iac
|
||||||
|
00630/4564 jms i 164
|
||||||
|
00631/2055 isz 55
|
||||||
|
00632/5211 jmp 611
|
||||||
|
00633/4063 jms 63
|
||||||
|
00634/4566 jms i 166
|
||||||
|
00635/7772 spa sna szl cla hlt
|
||||||
|
00636/0676 and i 676
|
||||||
|
00637/4562 jms i 162
|
||||||
|
00640/7421 mql
|
||||||
|
00641/7501 mqa
|
||||||
|
00642/4560 jms i 160
|
||||||
|
00643/7040 cma
|
||||||
|
00644/3441 dca i 41
|
||||||
|
00645/7501 mqa
|
||||||
|
00646/7001 iac
|
||||||
|
00647/4561 jms i 161
|
||||||
|
00650/2055 isz 55
|
||||||
|
00651/5240 jmp 640
|
||||||
|
00652/4562 jms i 162
|
||||||
|
00653/7421 mql
|
||||||
|
00654/7501 mqa
|
||||||
|
00655/4560 jms i 160
|
||||||
|
00656/7001 iac
|
||||||
|
00657/1441 tad i 41
|
||||||
|
00660/7450 sna
|
||||||
|
00661/5270 jmp 670
|
||||||
|
00662/3047 dca 47
|
||||||
|
00663/7501 mqa
|
||||||
|
00664/4560 jms i 160
|
||||||
|
00665/7040 cma
|
||||||
|
00666/3046 dca 46
|
||||||
|
00667/4563 jms i 163
|
||||||
|
00670/7501 mqa
|
||||||
|
00671/7001 iac
|
||||||
|
00672/4561 jms i 161
|
||||||
|
00673/2055 isz 55
|
||||||
|
00674/5253 jmp 653
|
||||||
|
00675/4063 jms 63
|
||||||
|
00676/4566 jms i 166
|
||||||
|
00677/7771 cla mqa mql
|
||||||
|
00700/0727 and i 727
|
||||||
|
00701/4565 jms i 165
|
||||||
|
00702/7421 mql
|
||||||
|
00703/4557 jms i 157
|
||||||
|
00704/3441 dca i 41
|
||||||
|
00705/4564 jms i 164
|
||||||
|
00706/2055 isz 55
|
||||||
|
00707/5303 jmp 703
|
||||||
|
00710/4565 jms i 165
|
||||||
|
00711/7421 mql
|
||||||
|
00712/4557 jms i 157
|
||||||
|
00713/7041 cma iac
|
||||||
|
00714/1441 tad i 41
|
||||||
|
00715/7450 sna
|
||||||
|
00716/5323 jmp 723
|
||||||
|
00717/3047 dca 47
|
||||||
|
00720/7501 mqa
|
||||||
|
00721/3046 dca 46
|
||||||
|
00722/4563 jms i 163
|
||||||
|
00723/4564 jms i 164
|
||||||
|
00724/2055 isz 55
|
||||||
|
00725/5312 jmp 712
|
||||||
|
00726/4063 jms 63
|
||||||
|
00727/4566 jms i 166
|
||||||
|
00730/7770 spa sna szl cla
|
||||||
|
00731/1000 tad 0
|
||||||
|
00732/4562 jms i 162
|
||||||
|
00733/7421 mql
|
||||||
|
00734/4557 jms i 157
|
||||||
|
00735/3441 dca i 41
|
||||||
|
00736/4561 jms i 161
|
||||||
|
00737/2055 isz 55
|
||||||
|
00740/5334 jmp 734
|
||||||
|
00741/4562 jms i 162
|
||||||
|
00742/7421 mql
|
||||||
|
00743/4557 jms i 157
|
||||||
|
00744/7041 cma iac
|
||||||
|
00745/1441 tad i 41
|
||||||
|
00746/7450 sna
|
||||||
|
00747/5354 jmp 754
|
||||||
|
00750/3047 dca 47
|
||||||
|
00751/7501 mqa
|
||||||
|
00752/3046 dca 46
|
||||||
|
00753/4563 jms i 163
|
||||||
|
00754/4561 jms i 161
|
||||||
|
00755/2055 isz 55
|
||||||
|
00756/5343 jmp 743
|
||||||
|
00757/4063 jms 63
|
||||||
|
00760/5556 jmp i 156
|
||||||
|
00777/0576 and i 176
|
||||||
|
01000/2051 isz 51
|
||||||
|
01001/7410 skp
|
||||||
|
01002/5200 jmp 1000
|
||||||
|
01003/7200 cla
|
||||||
|
01004/1177 tad 177
|
||||||
|
01005/4576 jms i 176
|
||||||
|
01006/0000 and 0
|
||||||
|
01007/1600 tad i 1000
|
||||||
|
01010/0000 and 0
|
||||||
|
01011/7600 cla
|
||||||
|
01012/4572 jms i 172
|
||||||
|
01013/7500 sma
|
||||||
|
01014/4555 jms i 155
|
||||||
|
01015/4554 jms i 154
|
||||||
|
01016/1044 tad 44
|
||||||
|
01017/1051 tad 51
|
||||||
|
01020/4553 jms i 153
|
||||||
|
01021/4554 jms i 154
|
||||||
|
01022/1051 tad 51
|
||||||
|
01023/1057 tad 57
|
||||||
|
01024/7112 cll rtr
|
||||||
|
01025/7010 rar
|
||||||
|
01026/0175 and 175
|
||||||
|
01027/1152 tad 152
|
||||||
|
01030/4551 jms i 151
|
||||||
|
01031/4554 jms i 154
|
||||||
|
01032/1055 tad 55
|
||||||
|
01033/1052 tad 52
|
||||||
|
01034/4553 jms i 153
|
||||||
|
01035/4550 jms i 150
|
||||||
|
01036/4572 jms i 172
|
||||||
|
01037/7006 rtl
|
||||||
|
01040/7420 snl
|
||||||
|
01041/5547 jmp i 147
|
||||||
|
01042/7402 hlt
|
||||||
|
01043/5547 jmp i 147
|
||||||
|
01044/0516 and i 116
|
||||||
|
01045/0440 and i 40
|
||||||
|
01046/2001 isz 1
|
||||||
|
01047/2323 isz 1123
|
||||||
|
01050/4000 jms 0
|
||||||
|
01051/4006 jms 6
|
||||||
|
01052/1105 tad 105
|
||||||
|
01053/1404 tad i 4
|
||||||
|
01054/4000 jms 0
|
||||||
|
01055/4005 jms 5
|
||||||
|
01056/2222 isz 1022
|
||||||
|
01057/1722 tad i 1122
|
||||||
|
01060/2340 isz 1140
|
||||||
|
01061/0000 and 0
|
||||||
|
01062/0000 and 0
|
||||||
|
01063/7300 cla cll
|
||||||
|
01064/2050 isz 50
|
||||||
|
01065/1050 tad 50
|
||||||
|
01066/1662 tad i 1062
|
||||||
|
01067/7440 sza
|
||||||
|
01070/7402 hlt
|
||||||
|
01071/4572 jms i 172
|
||||||
|
01072/0146 and 146
|
||||||
|
01073/7450 sna
|
||||||
|
01074/5304 jmp 1104
|
||||||
|
01075/1662 tad i 1062
|
||||||
|
01076/7650 sna cla
|
||||||
|
01077/5304 jmp 1104
|
||||||
|
01100/2262 isz 1062
|
||||||
|
01101/1662 tad i 1062
|
||||||
|
01102/3262 dca 1062
|
||||||
|
01103/5662 jmp i 1062
|
||||||
|
01104/2262 isz 1062
|
||||||
|
01105/2262 isz 1062
|
||||||
|
01106/5662 jmp i 1062
|
||||||
|
01107/0000 and 0
|
||||||
|
01110/3042 dca 42
|
||||||
|
01111/1051 tad 51
|
||||||
|
01112/0145 and 145
|
||||||
|
01113/7040 cma
|
||||||
|
01114/3043 dca 43
|
||||||
|
01115/1042 tad 42
|
||||||
|
01116/7104 cll ral
|
||||||
|
01117/7430 szl
|
||||||
|
01120/7001 iac
|
||||||
|
01121/2043 isz 43
|
||||||
|
01122/5316 jmp 1116
|
||||||
|
01123/5707 jmp i 1107
|
||||||
|
01124/0000 and 0
|
||||||
|
01125/7200 cla
|
||||||
|
01126/1144 tad 144
|
||||||
|
01127/3042 dca 42
|
||||||
|
01130/7701 cla mqa
|
||||||
|
01131/3043 dca 43
|
||||||
|
01132/1043 tad 43
|
||||||
|
01133/2042 isz 42
|
||||||
|
01134/5332 jmp 1132
|
||||||
|
01135/1143 tad 143
|
||||||
|
01136/7421 mql
|
||||||
|
01137/7501 mqa
|
||||||
|
01140/5724 jmp i 1124
|
||||||
|
01141/0000 and 0
|
||||||
|
01142/7701 cla mqa
|
||||||
|
01143/3042 dca 42
|
||||||
|
01144/1042 tad 42
|
||||||
|
01145/7104 cll ral
|
||||||
|
01146/7104 cll ral
|
||||||
|
01147/1042 tad 42
|
||||||
|
01150/1042 tad 42
|
||||||
|
01151/1042 tad 42
|
||||||
|
01152/7104 cll ral
|
||||||
|
01153/7104 cll ral
|
||||||
|
01154/1042 tad 42
|
||||||
|
01155/1143 tad 143
|
||||||
|
01156/7421 mql
|
||||||
|
01157/7501 mqa
|
||||||
|
01160/5741 jmp i 1141
|
||||||
|
01200/0000 and 0
|
||||||
|
01201/7200 cla
|
||||||
|
01202/1052 tad 52
|
||||||
|
01203/0145 and 145
|
||||||
|
01204/7640 sza cla
|
||||||
|
01205/5212 jmp 1212
|
||||||
|
01206/4063 jms 63
|
||||||
|
01207/4554 jms i 154
|
||||||
|
01210/1246 tad 1246
|
||||||
|
01211/4056 jms 56
|
||||||
|
01212/1051 tad 51
|
||||||
|
01213/4553 jms i 153
|
||||||
|
01214/4542 jms i 142
|
||||||
|
01215/1052 tad 52
|
||||||
|
01216/4553 jms i 153
|
||||||
|
01217/4542 jms i 142
|
||||||
|
01220/1050 tad 50
|
||||||
|
01221/4553 jms i 153
|
||||||
|
01222/4542 jms i 142
|
||||||
|
01223/6214 iot 21,4
|
||||||
|
01224/7112 cll rtr
|
||||||
|
01225/7010 rar
|
||||||
|
01226/1152 tad 152
|
||||||
|
01227/4551 jms i 151
|
||||||
|
01230/1041 tad 41
|
||||||
|
01231/4553 jms i 153
|
||||||
|
01232/4542 jms i 142
|
||||||
|
01233/1046 tad 46
|
||||||
|
01234/4553 jms i 153
|
||||||
|
01235/4542 jms i 142
|
||||||
|
01236/1047 tad 47
|
||||||
|
01237/1046 tad 46
|
||||||
|
01240/4553 jms i 153
|
||||||
|
01241/4550 jms i 150
|
||||||
|
01242/2052 isz 52
|
||||||
|
01243/7410 skp
|
||||||
|
01244/5242 jmp 1242
|
||||||
|
01245/5600 jmp i 1200
|
||||||
|
01246/3720 dca i 1320
|
||||||
|
01247/0123 and 123
|
||||||
|
01250/2340 isz 1340
|
||||||
|
01251/0522 and i 122
|
||||||
|
01252/2223 isz 1223
|
||||||
|
01253/4024 jms 24
|
||||||
|
01254/0523 and i 123
|
||||||
|
01255/2440 isz i 40
|
||||||
|
01256/0104 and 104
|
||||||
|
01257/0422 and i 22
|
||||||
|
01260/2340 isz 1340
|
||||||
|
01261/0530 and i 130
|
||||||
|
01262/2004 isz 4
|
||||||
|
01263/4022 jms 22
|
||||||
|
01264/0326 and 1326
|
||||||
|
01265/0437 and i 37
|
||||||
|
01266/0000 and 0
|
||||||
|
01267/0000 and 0
|
||||||
|
01270/3333 dca 1333
|
||||||
|
01271/6214 iot 21,4
|
||||||
|
01272/1170 tad 170
|
||||||
|
01273/3331 dca 1331
|
||||||
|
01274/6224 iot 22,4
|
||||||
|
01275/1170 tad 170
|
||||||
|
01276/3277 dca 1277
|
||||||
|
01277/7402 hlt
|
||||||
|
01300/1667 tad i 1267
|
||||||
|
01301/1170 tad 170
|
||||||
|
01302/3316 dca 1316
|
||||||
|
01303/2267 isz 1267
|
||||||
|
01304/1667 tad i 1267
|
||||||
|
01305/3334 dca 1334
|
||||||
|
01306/2267 isz 1267
|
||||||
|
01307/1667 tad i 1267
|
||||||
|
01310/1170 tad 170
|
||||||
|
01311/3322 dca 1322
|
||||||
|
01312/2267 isz 1267
|
||||||
|
01313/1667 tad i 1267
|
||||||
|
01314/3335 dca 1335
|
||||||
|
01315/2267 isz 1267
|
||||||
|
01316/7402 hlt
|
||||||
|
01317/1734 tad i 1334
|
||||||
|
01320/2334 isz 1334
|
||||||
|
01321/7000 nop
|
||||||
|
01322/7402 hlt
|
||||||
|
01323/3735 dca i 1335
|
||||||
|
01324/2335 isz 1335
|
||||||
|
01325/7000 nop
|
||||||
|
01326/2333 isz 1333
|
||||||
|
01327/5316 jmp 1316
|
||||||
|
01330/7200 cla
|
||||||
|
01331/7402 hlt
|
||||||
|
01332/5667 jmp i 1267
|
||||||
|
01333/0000 and 0
|
||||||
|
01334/0000 and 0
|
||||||
|
01335/0000 and 0
|
||||||
|
01400/0000 and 0
|
||||||
|
01401/7104 cll ral
|
||||||
|
01402/3042 dca 42
|
||||||
|
01403/1141 tad 141
|
||||||
|
01404/3043 dca 43
|
||||||
|
01405/1042 tad 42
|
||||||
|
01406/7006 rtl
|
||||||
|
01407/7004 ral
|
||||||
|
01410/3042 dca 42
|
||||||
|
01411/1042 tad 42
|
||||||
|
01412/0175 and 175
|
||||||
|
01413/1152 tad 152
|
||||||
|
01414/4551 jms i 151
|
||||||
|
01415/2043 isz 43
|
||||||
|
01416/5205 jmp 1405
|
||||||
|
01417/5600 jmp i 1400
|
||||||
|
01420/0000 and 0
|
||||||
|
01421/7200 cla
|
||||||
|
01422/1620 tad i 1420
|
||||||
|
01423/3042 dca 42
|
||||||
|
01424/2220 isz 1420
|
||||||
|
01425/1442 tad i 42
|
||||||
|
01426/7002 bsw
|
||||||
|
01427/4234 jms 1434
|
||||||
|
01430/1442 tad i 42
|
||||||
|
01431/4234 jms 1434
|
||||||
|
01432/2042 isz 42
|
||||||
|
01433/5225 jmp 1425
|
||||||
|
01434/0000 and 0
|
||||||
|
01435/0140 and 140
|
||||||
|
01436/7450 sna
|
||||||
|
01437/5620 jmp i 1420
|
||||||
|
01440/1137 tad 137
|
||||||
|
01441/7440 sza
|
||||||
|
01442/5245 jmp 1445
|
||||||
|
01443/4550 jms i 150
|
||||||
|
01444/5634 jmp i 1434
|
||||||
|
01445/7510 spa
|
||||||
|
01446/1136 tad 136
|
||||||
|
01447/1135 tad 135
|
||||||
|
01450/4551 jms i 151
|
||||||
|
01451/5634 jmp i 1434
|
||||||
|
01452/0000 and 0
|
||||||
|
01453/7200 cla
|
||||||
|
01454/1134 tad 134
|
||||||
|
01455/4551 jms i 151
|
||||||
|
01456/5652 jmp i 1452
|
||||||
|
01457/0000 and 0
|
||||||
|
01460/7200 cla
|
||||||
|
01461/1133 tad 133
|
||||||
|
01462/4551 jms i 151
|
||||||
|
01463/5657 jmp i 1457
|
||||||
|
01464/0000 and 0
|
||||||
|
01465/7200 cla
|
||||||
|
01466/1147 tad 147
|
||||||
|
01467/4551 jms i 151
|
||||||
|
01470/1132 tad 132
|
||||||
|
01471/4551 jms i 151
|
||||||
|
01472/5664 jmp i 1464
|
||||||
|
01473/0000 and 0
|
||||||
|
01474/6041 iot 4,1
|
||||||
|
01475/5274 jmp 1474
|
||||||
|
01476/0131 and 131
|
||||||
|
01477/6046 iot 4,6
|
||||||
|
01500/7200 cla
|
||||||
|
01501/5673 jmp i 1473
|
||||||
|
01502/0000 and 0
|
||||||
|
01503/7215 cla iac
|
||||||
|
01504/1173 tad 173
|
||||||
|
01505/7440 sza
|
||||||
|
01506/5311 jmp 1511
|
||||||
|
01507/1040 tad 40
|
||||||
|
01510/7410 skp
|
||||||
|
01511/7604 cla osr
|
||||||
|
01512/5702 jmp i 1502
|
||||||
|
01513/0000 and 0
|
||||||
|
01514/3042 dca 42
|
||||||
|
01515/7001 iac
|
||||||
|
01516/1041 tad 41
|
||||||
|
01517/3041 dca 41
|
||||||
|
01520/1042 tad 42
|
||||||
|
01521/5713 jmp i 1513
|
||||||
|
01522/0000 and 0
|
||||||
|
01523/3042 dca 42
|
||||||
|
01524/7040 cma
|
||||||
|
01525/1041 tad 41
|
||||||
|
01526/3041 dca 41
|
||||||
|
01527/1042 tad 42
|
||||||
|
01530/5722 jmp i 1522
|
||||||
|
01531/0000 and 0
|
||||||
|
01532/4347 jms 1547
|
||||||
|
01533/1053 tad 53
|
||||||
|
01534/3041 dca 41
|
||||||
|
01535/1051 tad 51
|
||||||
|
01536/1041 tad 41
|
||||||
|
01537/5731 jmp i 1531
|
||||||
|
01540/0000 and 0
|
||||||
|
01541/4347 jms 1547
|
||||||
|
01542/1054 tad 54
|
||||||
|
01543/3041 dca 41
|
||||||
|
01544/1051 tad 51
|
||||||
|
01545/1041 tad 41
|
||||||
|
01546/5740 jmp i 1540
|
||||||
|
01547/0000 and 0
|
||||||
|
01550/4056 jms 56
|
||||||
|
01551/7300 cla cll
|
||||||
|
01552/1057 tad 57
|
||||||
|
01553/7041 cma iac
|
||||||
|
01554/1064 tad 64
|
||||||
|
01555/7650 sna cla
|
||||||
|
01556/5362 jmp 1562
|
||||||
|
01557/3053 dca 53
|
||||||
|
01560/3055 dca 55
|
||||||
|
01561/5370 jmp 1570
|
||||||
|
01562/1130 tad 130
|
||||||
|
01563/3053 dca 53
|
||||||
|
01564/1054 tad 54
|
||||||
|
01565/7040 cma
|
||||||
|
01566/1053 tad 53
|
||||||
|
01567/3055 dca 55
|
||||||
|
01570/5747 jmp i 1547
|
||||||
|
01600/0000 and 0
|
||||||
|
01601/0000 and 0
|
||||||
|
01602/0000 and 0
|
||||||
|
01603/0000 and 0
|
||||||
|
01604/0000 and 0
|
||||||
|
01605/0000 and 0
|
||||||
|
01606/0000 and 0
|
||||||
|
01607/0000 and 0
|
||||||
|
01610/0000 and 0
|
||||||
|
01611/0000 and 0
|
||||||
|
01612/0000 and 0
|
||||||
|
01613/0000 and 0
|
||||||
|
01614/0000 and 0
|
||||||
|
01615/0000 and 0
|
||||||
|
01616/0000 and 0
|
||||||
|
01617/0000 and 0
|
||||||
|
01620/0000 and 0
|
||||||
|
01621/0000 and 0
|
||||||
|
01622/0000 and 0
|
||||||
|
01623/0000 and 0
|
||||||
|
01624/0000 and 0
|
||||||
|
01625/0000 and 0
|
||||||
|
01626/0000 and 0
|
||||||
|
01627/0000 and 0
|
||||||
|
01630/0000 and 0
|
||||||
|
01631/0000 and 0
|
||||||
|
01632/0000 and 0
|
||||||
|
01633/0000 and 0
|
||||||
|
01634/0000 and 0
|
||||||
|
01635/0000 and 0
|
||||||
|
01636/0000 and 0
|
||||||
|
01637/0000 and 0
|
||||||
|
01640/0000 and 0
|
||||||
|
01641/0000 and 0
|
||||||
|
01642/0000 and 0
|
||||||
|
01643/0000 and 0
|
||||||
|
01644/0000 and 0
|
||||||
|
01645/0000 and 0
|
||||||
|
01646/0000 and 0
|
||||||
|
01647/0000 and 0
|
||||||
|
01650/0000 and 0
|
||||||
|
01651/0000 and 0
|
||||||
|
01652/0000 and 0
|
||||||
|
01653/0000 and 0
|
||||||
|
01654/0000 and 0
|
||||||
|
01655/0000 and 0
|
||||||
|
01656/0000 and 0
|
||||||
|
01657/0000 and 0
|
||||||
|
01660/0000 and 0
|
||||||
|
01661/0000 and 0
|
||||||
|
01662/0000 and 0
|
||||||
|
01663/0000 and 0
|
||||||
|
01664/0000 and 0
|
||||||
|
01665/0000 and 0
|
||||||
|
01666/0000 and 0
|
||||||
|
01667/0000 and 0
|
||||||
|
01670/0000 and 0
|
||||||
|
01671/0000 and 0
|
||||||
|
01672/0000 and 0
|
||||||
|
01673/0000 and 0
|
||||||
|
01674/0000 and 0
|
||||||
|
01675/0000 and 0
|
||||||
|
01676/0000 and 0
|
||||||
|
01677/0000 and 0
|
||||||
|
01700/0000 and 0
|
||||||
|
01701/0000 and 0
|
||||||
|
01702/0000 and 0
|
||||||
|
01703/0000 and 0
|
||||||
|
01704/0000 and 0
|
||||||
|
01705/0000 and 0
|
||||||
|
01706/0000 and 0
|
||||||
|
01707/0000 and 0
|
||||||
|
01710/0000 and 0
|
||||||
|
01711/0000 and 0
|
||||||
|
01712/0000 and 0
|
||||||
|
01713/0000 and 0
|
||||||
|
01714/0000 and 0
|
||||||
|
01715/0000 and 0
|
||||||
|
01716/0000 and 0
|
||||||
|
01717/0000 and 0
|
||||||
|
01720/0000 and 0
|
||||||
|
01721/0000 and 0
|
||||||
|
01722/0000 and 0
|
||||||
|
01723/0000 and 0
|
||||||
|
01724/0000 and 0
|
||||||
|
01725/0000 and 0
|
||||||
|
01726/0000 and 0
|
||||||
|
01727/0000 and 0
|
||||||
|
01730/0000 and 0
|
||||||
|
01731/0000 and 0
|
||||||
|
01732/0000 and 0
|
||||||
|
01733/0000 and 0
|
||||||
|
01734/0000 and 0
|
||||||
|
01735/0000 and 0
|
||||||
|
01736/0000 and 0
|
||||||
|
01737/0000 and 0
|
||||||
|
01740/0000 and 0
|
||||||
|
01741/0000 and 0
|
||||||
|
01742/0000 and 0
|
||||||
|
01743/0000 and 0
|
||||||
|
01744/0000 and 0
|
||||||
|
01745/0000 and 0
|
||||||
|
01746/0000 and 0
|
||||||
|
01747/0000 and 0
|
||||||
|
01750/0000 and 0
|
||||||
|
01751/0000 and 0
|
||||||
|
01752/0000 and 0
|
||||||
|
01753/0000 and 0
|
||||||
|
01754/0000 and 0
|
||||||
|
01755/0000 and 0
|
||||||
|
01756/0000 and 0
|
||||||
|
01757/0000 and 0
|
||||||
|
01760/0000 and 0
|
||||||
|
01761/0000 and 0
|
||||||
|
01762/0000 and 0
|
||||||
|
01763/0000 and 0
|
||||||
|
01764/0000 and 0
|
||||||
|
01765/0000 and 0
|
||||||
|
01766/0000 and 0
|
||||||
|
01767/0000 and 0
|
||||||
|
01770/0000 and 0
|
||||||
|
01771/0000 and 0
|
||||||
|
01772/0000 and 0
|
||||||
|
01773/0000 and 0
|
||||||
|
01774/0000 and 0
|
||||||
|
01775/0000 and 0
|
||||||
|
01776/0000 and 0
|
||||||
|
01777/0000 and 0
|
||||||
|
00130/2000 isz 0
|
||||||
|
00131/0177 and 177
|
||||||
|
00132/0212 and 12
|
||||||
|
00133/0207 and 7
|
||||||
|
00134/0240 and 40
|
||||||
|
00135/0237 and 37
|
||||||
|
00136/0100 and 100
|
||||||
|
00137/7741 cla mqa
|
||||||
|
00140/0077 and 77
|
||||||
|
00141/7774 spa sna szl cla osr
|
||||||
|
00142/1452 tad i 52
|
||||||
|
00143/1751 tad i 151
|
||||||
|
00144/7743 cla mqa
|
||||||
|
00145/0017 and 17
|
||||||
|
00146/1700 tad i 100
|
||||||
|
00147/0215 and 15
|
||||||
|
00150/1464 tad i 64
|
||||||
|
00151/1473 tad i 73
|
||||||
|
00152/0260 and 60
|
||||||
|
00153/1400 tad i 0
|
||||||
|
00154/1420 tad i 20
|
||||||
|
00155/1457 tad i 57
|
||||||
|
00156/1000 tad 0
|
||||||
|
00157/1141 tad 141
|
||||||
|
00160/1107 tad 107
|
||||||
|
00161/1522 tad i 122
|
||||||
|
00162/1540 tad i 140
|
||||||
|
00163/1200 tad 0
|
||||||
|
00164/1513 tad i 113
|
||||||
|
00165/1531 tad i 131
|
||||||
|
00166/1062 tad 62
|
||||||
|
00167/0400 and i 0
|
||||||
|
00170/6201 iot 20,1
|
||||||
|
00171/0070 and 70
|
||||||
|
00172/1502 tad i 102
|
||||||
|
00173/7770 spa sna szl cla
|
||||||
|
00174/6440 iot 44,0
|
||||||
|
00175/0007 and 7
|
||||||
|
00176/1267 tad 67
|
||||||
|
00177/7600 cla
|
||||||
|
07751/0200 and 7600
|
||||||
|
07752/6032 iot 3,2
|
||||||
|
07753/1352 tad 7752
|
||||||
|
07754/3356 dca 7756
|
||||||
|
07755/5751 jmp i 7751
|
||||||
|
07756/5353 jmp 7753
|
||||||
|
CHKSUM: Computed: 3145, input: 3145 -- PASS
|
||||||
1120
d8tape/verify.list
Normal file
1120
d8tape/verify.list
Normal file
File diff suppressed because it is too large
Load Diff
1584
d8tape/verify.lst
Normal file
1584
d8tape/verify.lst
Normal file
File diff suppressed because it is too large
Load Diff
1120
d8tape/verify.pal
Normal file
1120
d8tape/verify.pal
Normal file
File diff suppressed because it is too large
Load Diff
1
d8tape/version.c
Normal file
1
d8tape/version.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
const char *version="0.347";
|
||||||
355
diffrom/diffrom.pl
Normal file
355
diffrom/diffrom.pl
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
# Copyright (c) 2005 Don North
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# o Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# o Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# o Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
require 5.008;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
diffrom.pl - Compare two .hex/.bin format PROM files
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
diffrom.pl
|
||||||
|
S<[--help]>
|
||||||
|
S<[--debug]>
|
||||||
|
S<[--verbose]>
|
||||||
|
S<FILE1>
|
||||||
|
S<FILE2>
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Compares two PROM files, byte by byte. Format is determined
|
||||||
|
by file extension: .hex for Intel hex format, .bin for binary.
|
||||||
|
Outputs a list of all bytes that differ (if any).
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
The following options are available:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<--help>
|
||||||
|
|
||||||
|
Output this manpage and exit the program.
|
||||||
|
|
||||||
|
=item B<--debug>
|
||||||
|
|
||||||
|
Enable debug mode; print input file records as parsed.
|
||||||
|
|
||||||
|
=item B<--verbose>
|
||||||
|
|
||||||
|
Verbose status; outputs a message if files are equal.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 ERRORS
|
||||||
|
|
||||||
|
The following diagnostic error messages can be produced on STDERR.
|
||||||
|
The meaning should be fairly self explanatory.
|
||||||
|
|
||||||
|
C<Aborted due to command line errors> -- bad option or missing file(s)
|
||||||
|
|
||||||
|
C<Can't open input file '$file'> -- bad filename or unreadable file
|
||||||
|
|
||||||
|
C<File '%s': Unknown record type '%s' ignored> -- bad record type in hex file
|
||||||
|
|
||||||
|
C<File '%s': Bad data count, exp=0x%02X rcv=0x%02X, line='%s'> - bad record length in hex file
|
||||||
|
|
||||||
|
C<File '%s': Bad checksum, exp=0x%02X rcv=0x%02X, line='%s'> - checksum error in hex file
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
Some examples of common usage:
|
||||||
|
|
||||||
|
diffrom.pl --help
|
||||||
|
|
||||||
|
diffrom.pl --verbose file1.bin file2.hex
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Don North - donorth <ak6dn _at_ mindspring _dot_ com>
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
Modification history:
|
||||||
|
|
||||||
|
2005-05-05 v1.0 donorth - Initial version.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external standard modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, $ENV{PERL5LIB}) if defined($ENV{PERL5LIB}); # cygwin bugfix
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v1.0'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
my $MODE = 'OCT'; # or 'OCT' or 'DEC' or 'BIN'
|
||||||
|
my $SIZE = 'BYTE'; # or 'WORD'
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help" => \$HELP,
|
||||||
|
"debug" => \$DEBUG,
|
||||||
|
"verbose" => \$VERBOSE,
|
||||||
|
"bin" => sub { $MODE = 'BIN'; },
|
||||||
|
"oct" => sub { $MODE = 'OCT'; },
|
||||||
|
"dec" => sub { $MODE = 'DEC'; },
|
||||||
|
"hex" => sub { $MODE = 'HEX'; },
|
||||||
|
"byte" => sub { $SIZE = 'BYTE'; },
|
||||||
|
"word" => sub { $SIZE = 'WORD'; },
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# say hello
|
||||||
|
printf STDERR "diffrom.pl %s by Don North (perl %g)\n", $VERSION, $] if $VERBOSE;
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR && scalar(@ARGV) >= 1) {
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
FILE1 first ROM file
|
||||||
|
FILE2 second ROM file
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# compute checksum (twos complement of the sum of bytes)
|
||||||
|
sub chksum (@) { my $sum = 0; map($sum += $_, @_); (-$sum) & 0xFF; }
|
||||||
|
|
||||||
|
# compute checksum (sum of bytes)
|
||||||
|
sub binsum (@) { my $sum = 0; map($sum += $_, @_); $sum; }
|
||||||
|
|
||||||
|
# convert string of byte hex characters to an array of numbers
|
||||||
|
sub hexa ($) {
|
||||||
|
my ($dat) = @_;
|
||||||
|
my @dat = ();
|
||||||
|
while ($dat) { push(@dat,hex(substr($dat,0,2))); $dat = substr($dat,2); }
|
||||||
|
return @dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
# read a hex file into an array
|
||||||
|
sub readhex ($$) {
|
||||||
|
|
||||||
|
my ($file,$buf) = @_;
|
||||||
|
|
||||||
|
my $extadr = 0; # extended address offset
|
||||||
|
my $chksum = 0; # total device checksum
|
||||||
|
|
||||||
|
# read the input hex-format stream into a buffer
|
||||||
|
open(HEX, "< $file") || die "Can't open input file '$file'\n";
|
||||||
|
while (my $line = scalar(<HEX>)) {
|
||||||
|
$line =~ s/[\015\012]+$//; # strip EOLs
|
||||||
|
if ($line =~ m/^:([0-9A-F]{2})([0-9A-F]{4})([0][0-3])([0-9A-F]{0,})([0-9A-F]{2})$/i) {
|
||||||
|
# 00 data record: :NNAAAA00DDDDD...DDDDCC
|
||||||
|
# 01 end record: :NNAAAA01CC
|
||||||
|
# 02 extended address record: :NNAAAA02EEEECC
|
||||||
|
# 03 start record: :NNAAAA03SSSSCC
|
||||||
|
my ($typ,$cnt,$adr,$chk,@dat) = (hex($3),hex($1),hex($2),hex($5),hexa($4));
|
||||||
|
|
||||||
|
# validate data byte count
|
||||||
|
unless (@dat == $cnt) {
|
||||||
|
printf STDERR "File '%s': Bad data count, exp=0x%02X rcv=0x%02X, line='%s'\n",
|
||||||
|
$file, $cnt, scalar(@dat), $line;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# compute checksum, validate
|
||||||
|
my $cmp = &chksum($typ, $cnt, $adr, $adr>>8, @dat);
|
||||||
|
unless ($cmp == $chk) {
|
||||||
|
printf STDERR "File '%s': Bad checksum, exp=0x%02X rcv=0x%02X, line='%s'\n",
|
||||||
|
$file, $cmp, $chk, $line;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# print what we read if debugging
|
||||||
|
printf STDERR "file=%s lin=%s typ=%d cnt=0x%02X adr=0x%04X chk=0x%02X dat=%s\n",
|
||||||
|
$file, $line, $typ, $cnt, $adr, $chk,
|
||||||
|
join('',map(sprintf("%02X",$_),@dat)) if $DEBUG;
|
||||||
|
|
||||||
|
# process each record type
|
||||||
|
if ($typ == 0) {
|
||||||
|
# data record
|
||||||
|
for (my $idx = 0; $idx < $cnt; $idx++) {
|
||||||
|
$chksum += ($$buf[$extadr+$adr+$idx] = $dat[$idx]); }
|
||||||
|
} elsif ($typ == 2) {
|
||||||
|
# save extended address
|
||||||
|
$extadr = ($dat[0]<<12)|($dat[1]<<4);
|
||||||
|
} elsif ($typ == 1) {
|
||||||
|
# exit if hit last
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printf STDERR "File '%s': Unknown record type '%s' ignored\n", $file, $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
} # while (my $line)
|
||||||
|
close(HEX);
|
||||||
|
|
||||||
|
# print stats if requested
|
||||||
|
printf STDERR "File '%s': size=0x%X (%dx8), checksum=0x%X\n",
|
||||||
|
$file, (scalar(@$buf))x2, $chksum if $VERBOSE;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# read a binary file into an array
|
||||||
|
sub readbin ($$) {
|
||||||
|
|
||||||
|
my ($file,$buf) = @_;
|
||||||
|
|
||||||
|
# read the input hex-format stream into a buffer
|
||||||
|
my $dat = undef;
|
||||||
|
open(BIN, "< $file") || die "Can't open input file '$file'\n";
|
||||||
|
read(BIN, $dat, 1<<20);
|
||||||
|
close(BIN);
|
||||||
|
@$buf = unpack("C*", $dat);
|
||||||
|
|
||||||
|
# print stats if requested
|
||||||
|
printf STDERR "File '%s': size=0x%X (%dx8), checksum=0x%X\n",
|
||||||
|
$file, (scalar(@$buf))x2, &binsum(@$buf) if $VERBOSE;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# read a file into an array
|
||||||
|
sub readfile ($$) {
|
||||||
|
|
||||||
|
my ($file,$buf) = @_;
|
||||||
|
|
||||||
|
&readhex($file, $buf) if $file =~ m/[.]hex$/i;
|
||||||
|
&readbin($file, $buf) if $file =~ m/[.]bin$/i;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
my @buf1 = (); # first ROM file
|
||||||
|
my @buf2 = (); # second ROM file
|
||||||
|
|
||||||
|
# if exactly two files specified do the compare
|
||||||
|
if (@ARGV == 2) {
|
||||||
|
|
||||||
|
# read the two files
|
||||||
|
&readfile(shift(@ARGV), \@buf1);
|
||||||
|
&readfile(shift(@ARGV), \@buf2);
|
||||||
|
|
||||||
|
# compare the two files
|
||||||
|
my $err = 0;
|
||||||
|
my $len = @buf1 >= @buf2 ? @buf1 : @buf2;
|
||||||
|
for (my $adr = 0; $adr < $len; $adr += $SIZE eq 'BYTE' ? 1 : 2) {
|
||||||
|
# get bytes/words
|
||||||
|
my $dat1 = $SIZE eq 'BYTE' ? $buf1[$adr] : ($buf1[$adr+1]<<8)|($buf1[$adr+0]<<0);
|
||||||
|
my $dat2 = $SIZE eq 'BYTE' ? $buf2[$adr] : ($buf2[$adr+1]<<8)|($buf2[$adr+0]<<0);
|
||||||
|
# check if same
|
||||||
|
next if $dat1 == $dat2;
|
||||||
|
# print if different
|
||||||
|
if ($SIZE eq 'BYTE') {
|
||||||
|
if ($MODE eq 'HEX') {
|
||||||
|
printf "Addr=0x%04X File1=0x%02X File2=0x%02X\n", $adr, $dat1, $dat2;
|
||||||
|
} elsif ($MODE eq 'DEC') {
|
||||||
|
printf "Addr=%-5u File1=%-3u File2=%-3u\n", $adr, $dat1, $dat2;
|
||||||
|
} elsif ($MODE eq 'OCT') {
|
||||||
|
printf "Addr=%06o File1=%03o File2=%03o\n", $adr, $dat1, $dat2;
|
||||||
|
} elsif ($MODE eq 'BIN') {
|
||||||
|
printf "Addr=0b%016b File1=0b%08b File2=0b%08b\n", $adr, $dat1, $dat2;
|
||||||
|
}
|
||||||
|
} elsif ($SIZE eq 'WORD') {
|
||||||
|
if ($MODE eq 'HEX') {
|
||||||
|
printf "Addr=0x%04X File1=0x%04X File2=0x%04X\n", $adr, $dat1, $dat2;
|
||||||
|
} elsif ($MODE eq 'DEC') {
|
||||||
|
printf "Addr=%-5u File1=%-5u File2=%-5u\n", $adr, $dat1, $dat2;
|
||||||
|
} elsif ($MODE eq 'OCT') {
|
||||||
|
printf "Addr=%06o File1=%06o File2=%06o\n", $adr, $dat1, $dat2;
|
||||||
|
} elsif ($MODE eq 'BIN') {
|
||||||
|
printf "Addr=0b%016b File1=0b%016b File2=0b%016b\n", $adr, $dat1, $dat2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$err++;
|
||||||
|
}
|
||||||
|
printf "Files are %s\n", $err ? "different" : "identical" if $err || $VERBOSE;
|
||||||
|
|
||||||
|
exit($err ? 1 : 0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# if just one (or three or more) than just print stats and exit
|
||||||
|
while (@ARGV) {
|
||||||
|
# read the file
|
||||||
|
&readfile(shift(@ARGV), \@buf1);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# the end
|
||||||
334
dumpbin8x/dumpbin8x.pl
Normal file
334
dumpbin8x/dumpbin8x.pl
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
#!/usr/local/bin/perl -w
|
||||||
|
|
||||||
|
require 5.005;
|
||||||
|
|
||||||
|
# add additional search libraries
|
||||||
|
BEGIN { unshift(@INC, $ENV{'PERL5LIB'}) if exists($ENV{'PERL5LIB'}); }
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v0.0d0'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
my $VERILOG = 0; # set to 1 for verilog format output
|
||||||
|
my $DISASSEMBLY = 1; # set to 1 for disassembled output
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help!" => \$HELP,
|
||||||
|
"debug!" => \$DEBUG,
|
||||||
|
"verbose!" => \$VERBOSE,
|
||||||
|
"verilog" => \$VERILOG,
|
||||||
|
"disassembly!" => \$DISASSEMBLY,
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# say hello
|
||||||
|
printf STDERR "%s %s by Don North (perl %g)\n", $0, $VERSION, $] if $VERBOSE;
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR && scalar(@ARGV) >= 1) {
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--[no]help output manpage and exit
|
||||||
|
--[no]debug enable debug mode
|
||||||
|
--[no]verbose verbose status reporting
|
||||||
|
--verilog verilog format output
|
||||||
|
--[no]disassembly disassembly comments
|
||||||
|
FILENAME a filename...
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# loop on all input files
|
||||||
|
foreach my $filename (@ARGV) {
|
||||||
|
|
||||||
|
# open .bin papertape image file
|
||||||
|
printf STDERR "Processing file %s ...\n", $filename if $VERBOSE;
|
||||||
|
unless (open(INP, "< $filename")) {
|
||||||
|
printf STDERR "ERROR: cannot open input file %s\n", $filename;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
binmode(INP);
|
||||||
|
|
||||||
|
# file source header
|
||||||
|
if ($VERILOG) {
|
||||||
|
printf STDOUT " //\n";
|
||||||
|
printf STDOUT " // File: %s\n", $filename;
|
||||||
|
printf STDOUT " //\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($addr,$field,$newfield,$chksum,$seen) = (0,0,0,0,0);
|
||||||
|
my ($state,$hibyte,$lobyte) = ('JUNK',-1,-1);
|
||||||
|
|
||||||
|
# process content bytes
|
||||||
|
while (!eof(*INP) && $state ne 'DONE') {
|
||||||
|
|
||||||
|
# get next input byte
|
||||||
|
my $byte = get_byte(*INP);
|
||||||
|
|
||||||
|
# RUBOUT deletes next byte
|
||||||
|
if (is_rubout($byte)) {
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %03o\n", 'RUB', $byte if $VERBOSE;
|
||||||
|
$byte = get_byte(*INP);
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %03o\n", 'RUB', $byte if $VERBOSE;
|
||||||
|
$byte = get_byte(*INP);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for field set (not included in checksum)
|
||||||
|
if (is_field($byte)) {
|
||||||
|
$newfield = ($byte>>3)&7;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# make a printable string out of a character
|
||||||
|
sub make_str ($) { my ($t) = @_; return $t < 0x20 || $t > 0x7E ? sprintf("%03o",$t) : sprintf("'%c'",$t); }
|
||||||
|
|
||||||
|
# state machine
|
||||||
|
if ($state eq 'JUNK') {
|
||||||
|
# skipping junk
|
||||||
|
if (is_leader($byte)) { $state = 'SKIP'; }
|
||||||
|
($addr,$field,$newfield,$chksum,$seen) = (0,0,0,0,0);
|
||||||
|
($hibyte,$lobyte) = (-1,-1);
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %s\n", $state, make_str($byte) if $VERBOSE;
|
||||||
|
} elsif ($state eq 'SKIP') {
|
||||||
|
# eating leader
|
||||||
|
if (is_leader($byte)) {
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %03o\n", $state, $byte if $VERBOSE;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$hibyte = $byte;
|
||||||
|
$state = 'HI';
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %03o\n", $state, $byte if $VERBOSE;
|
||||||
|
} elsif ($state eq 'HI') {
|
||||||
|
# first byte
|
||||||
|
$lobyte = $byte;
|
||||||
|
$state = 'LO';
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %03o\n", $state, $byte if $VERBOSE;
|
||||||
|
} elsif ($state eq 'LO') {
|
||||||
|
# second byte
|
||||||
|
my $word = (($hibyte<<6) | $lobyte) & 07777;
|
||||||
|
if (is_leader($byte)) {
|
||||||
|
# this is the final checksum
|
||||||
|
printf STDOUT " //\n // " if $VERILOG;
|
||||||
|
printf STDOUT "CHKSUM: Computed: %04o, input: %04o -- %s\n",
|
||||||
|
$chksum, $word, $chksum == $word ? "PASS" : "FAIL";
|
||||||
|
printf STDOUT " //\n" if $VERILOG;
|
||||||
|
$state = 'DONE';
|
||||||
|
} else {
|
||||||
|
# this is address or data
|
||||||
|
$chksum = ($chksum + $hibyte + $lobyte) & 07777;
|
||||||
|
if (is_address($hibyte)) {
|
||||||
|
# address word
|
||||||
|
printf STDOUT " //\n" if $VERILOG && $seen;
|
||||||
|
$addr = $word;
|
||||||
|
$seen = 0;
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %04o\n", 'ADDR', $word if $VERBOSE;
|
||||||
|
} else {
|
||||||
|
# data word
|
||||||
|
if ($VERILOG) {
|
||||||
|
printf STDOUT " memory[15'o%o%04o] = 12'o%04o;", $field, $addr, $word;
|
||||||
|
printf STDOUT " // %s", decode_inst($word, $addr) if $DISASSEMBLY;
|
||||||
|
printf STDOUT "\n";
|
||||||
|
} else {
|
||||||
|
printf STDOUT "%o%04o/%04o", $field, $addr, $word;
|
||||||
|
printf STDOUT " %s", decode_inst($word, $addr);
|
||||||
|
printf STDOUT "\n";
|
||||||
|
}
|
||||||
|
$addr = ($addr+1) & 07777;
|
||||||
|
$seen = 1;
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %04o\n", 'DATA', $word if $VERBOSE;
|
||||||
|
}
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %o\n", 'FLD', $newfield if $field != $newfield && $VERBOSE;
|
||||||
|
$field = $newfield;
|
||||||
|
$hibyte = $byte;
|
||||||
|
$state = 'HI';
|
||||||
|
printf STDOUT " // " if $VERILOG && $VERBOSE;
|
||||||
|
printf STDOUT " %-4s %03o\n", $state, $byte if $VERBOSE;
|
||||||
|
}
|
||||||
|
} else { # invalid transition
|
||||||
|
$state = '????';
|
||||||
|
die "invalid transition";
|
||||||
|
}
|
||||||
|
|
||||||
|
} # while $state
|
||||||
|
|
||||||
|
close(INP);
|
||||||
|
|
||||||
|
} # foreach $filename
|
||||||
|
|
||||||
|
exit;
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# read next byte from input file, honor pushbacks
|
||||||
|
|
||||||
|
my @buffer = ();
|
||||||
|
|
||||||
|
sub get_byte {
|
||||||
|
|
||||||
|
local (*FILE) = @_;
|
||||||
|
|
||||||
|
my ($cnt,$byte) = (-1,-1);
|
||||||
|
|
||||||
|
if (defined($buffer[fileno(FILE)]) && @{$buffer[fileno(FILE)]}) {
|
||||||
|
|
||||||
|
# prior pushback data exists, use it
|
||||||
|
$byte = pop(@{$buffer[fileno(FILE)]});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# no prior pushback data exists, must do a file read
|
||||||
|
$cnt = read(FILE, $byte, 1);
|
||||||
|
$byte = !defined($cnt) || $cnt != 1 ? -1 : ord($byte);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
printf STDOUT "get_char: byte=%03o char='%s' cnt=%d\n", $byte, chr($byte), $cnt if $DEBUG;
|
||||||
|
|
||||||
|
# printf STDERR "|%s|\n", join('',map($byte&(1<<(7-$_))?'*':'.',(0..7))) if $DEBUG;
|
||||||
|
|
||||||
|
return $byte;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# push back a byte to an input file
|
||||||
|
|
||||||
|
sub unget_byte {
|
||||||
|
|
||||||
|
my ($byte) = shift;
|
||||||
|
local (*FILE) = shift;
|
||||||
|
|
||||||
|
push(@{$buffer[fileno(FILE)]}, $byte);
|
||||||
|
|
||||||
|
return $byte;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# paper tape format support routines
|
||||||
|
|
||||||
|
sub is_leader { my ($c) = @_; return ($c & 0377) == 0200; }
|
||||||
|
sub is_field { my ($c) = @_; return ($c & 0307) == 0300; }
|
||||||
|
sub is_address { my ($c) = @_; return ($c & 0300) == 0100; }
|
||||||
|
sub is_data { my ($c) = @_; return ($c & 0300) == 0000; }
|
||||||
|
sub is_rubout { my ($c) = @_; return ($c & 0377) == 0377; }
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# pdp-8 instruction disassembler
|
||||||
|
|
||||||
|
sub decode_inst {
|
||||||
|
|
||||||
|
my ($inst, $addr) = @_;
|
||||||
|
|
||||||
|
my $str = '';
|
||||||
|
my @opc = ( "and", "tad", "isz", "dca", "jms", "jmp", "iot", "opr" );
|
||||||
|
|
||||||
|
if ($inst <= 05777) { # 0..5 memory reference
|
||||||
|
|
||||||
|
$str = sprintf("%s%s %o", $opc[($inst>>9)&07],
|
||||||
|
($inst & 00400) ? " i" : "",
|
||||||
|
($inst & 00200) ? ($addr & 07600) | ($inst & 00177) : ($inst & 00177));
|
||||||
|
|
||||||
|
} elsif (($inst & 07000) == 06000) { # 6 i/o transfer
|
||||||
|
|
||||||
|
$str = sprintf("iot %o,%o", ($inst>>3)&077, $inst&07);
|
||||||
|
|
||||||
|
} elsif (($inst & 07400) == 07000) { # 7 operate group 1
|
||||||
|
|
||||||
|
# sequence 1
|
||||||
|
if (($inst & 00200) == 00200) { $str .= " cla"; }
|
||||||
|
if (($inst & 00100) == 00100) { $str .= " cll"; }
|
||||||
|
# sequence 2
|
||||||
|
if (($inst & 00040) == 00040) { $str .= " cma"; }
|
||||||
|
if (($inst & 00020) == 00020) { $str .= " cml"; }
|
||||||
|
# sequence 3
|
||||||
|
if (($inst & 00001) == 00001) { $str .= " iac"; }
|
||||||
|
# sequence 4
|
||||||
|
if (($inst & 00016) == 00010) { $str .= " rar"; }
|
||||||
|
if (($inst & 00016) == 00004) { $str .= " ral"; }
|
||||||
|
if (($inst & 00016) == 00012) { $str .= " rtr"; }
|
||||||
|
if (($inst & 00016) == 00006) { $str .= " rtl"; }
|
||||||
|
if (($inst & 00016) == 00002) { $str .= " bsw"; }
|
||||||
|
# else
|
||||||
|
if (($inst & 00377) == 00000) { $str .= " nop"; }
|
||||||
|
# done
|
||||||
|
|
||||||
|
} elsif (($inst & 07401) == 07400) { # 7 operate group 2
|
||||||
|
|
||||||
|
# sequence 1
|
||||||
|
if (($inst & 00110) == 00100) { $str .= " sma"; }
|
||||||
|
if (($inst & 00050) == 00040) { $str .= " sza"; }
|
||||||
|
if (($inst & 00030) == 00020) { $str .= " snl"; }
|
||||||
|
if (($inst & 00110) == 00110) { $str .= " spa"; }
|
||||||
|
if (($inst & 00050) == 00050) { $str .= " sna"; }
|
||||||
|
if (($inst & 00030) == 00030) { $str .= " szl"; }
|
||||||
|
if (($inst & 00170) == 00010) { $str .= " skp"; }
|
||||||
|
# sequence 2
|
||||||
|
if (($inst & 00200) == 00200) { $str .= " cla"; }
|
||||||
|
# sequence 3
|
||||||
|
if (($inst & 00004) == 00004) { $str .= " osr"; }
|
||||||
|
if (($inst & 00002) == 00002) { $str .= " hlt"; }
|
||||||
|
# done
|
||||||
|
|
||||||
|
} elsif (($inst & 07401) == 07401) { # 7 mq microinstructions
|
||||||
|
|
||||||
|
# sequence 1
|
||||||
|
if (($inst & 00200) == 00200) { $str .= " cla"; }
|
||||||
|
# sequence 2
|
||||||
|
if (($inst & 00100) == 00100) { $str .= " mqa"; }
|
||||||
|
if (($inst & 00020) == 00020) { $str .= " mql"; }
|
||||||
|
# sequence 3
|
||||||
|
# else
|
||||||
|
if (($inst & 00376) == 00000) { $str .= " nop"; }
|
||||||
|
# done
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# remove leading spaces, if any
|
||||||
|
$str =~ s/^\s+//;
|
||||||
|
return $str;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# the end
|
||||||
236
enet2hex/enet2hex.pl
Normal file
236
enet2hex/enet2hex.pl
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
# Copyright (c) 2005 Don North
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# o Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# o Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# o Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
require 5.008;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
enet2hex.pl - Build .hex image of a DEC ethernet MAC prom
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
enet2hex.pl
|
||||||
|
S<[--help]>
|
||||||
|
S<[--debug]>
|
||||||
|
S<[--verbose]>
|
||||||
|
S<[--macaddr=NN-NN-NN-NN-NN-NN]>
|
||||||
|
S<[--bytes=N]>
|
||||||
|
>HEXFILE
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Builds the image of a 'standard' DEC Ethernet MAC address
|
||||||
|
(station address) 32x8 PROM (82S123 equiv).
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
The following options are available:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<--help>
|
||||||
|
|
||||||
|
Output this manpage and exit the program.
|
||||||
|
|
||||||
|
=item B<--debug>
|
||||||
|
|
||||||
|
Enable debug mode; print input file records as parsed.
|
||||||
|
|
||||||
|
=item B<--verbose>
|
||||||
|
|
||||||
|
Verbose status; output status messages during processing.
|
||||||
|
|
||||||
|
=item B<--macaddr=NN-NN-NN-NN-NN-NN>
|
||||||
|
|
||||||
|
The MAC address (in hex format) to be used.
|
||||||
|
|
||||||
|
=item B<--bytes=N>
|
||||||
|
|
||||||
|
For hex format output files, output N bytes per line (default 16).
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 ERRORS
|
||||||
|
|
||||||
|
The following diagnostic error messages can be produced on STDERR.
|
||||||
|
The meaning should be fairly self explanatory.
|
||||||
|
|
||||||
|
C<Aborted due to command line errors> -- bad option or missing file(s)
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
Some examples of common usage:
|
||||||
|
|
||||||
|
enet2hex.pl --help
|
||||||
|
|
||||||
|
enet2hex.pl --verbose --macaddr=01-23-45-67-89-AB > mac.hex
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Don North - donorth <ak6dn _at_ mindspring _dot_ com>
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
Modification history:
|
||||||
|
|
||||||
|
2005-08-05 v1.0 donorth - Initial version.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external standard modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, $ENV{PERL5LIB}) if defined($ENV{PERL5LIB}); # cygwin bugfix
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v1.0'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
my $romsize = 32; # number of rom addresses
|
||||||
|
my $bytesper = -1; # bytes per block in output file
|
||||||
|
my $macaddr = ''; # mac address
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help" => \$HELP,
|
||||||
|
"debug" => \$DEBUG,
|
||||||
|
"verbose" => \$VERBOSE,
|
||||||
|
"bytes=i" => \$bytesper,
|
||||||
|
"macaddr=s" => \$macaddr,
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# say hello
|
||||||
|
printf STDERR "enet2hex.pl %s by Don North (perl %g)\n", $VERSION, $] if $VERBOSE;
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR && scalar(@ARGV) == 0 && $macaddr ne '') {
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
--bytes=N bytes per block on output
|
||||||
|
--macaddr=NN-NN-NN-NN-NN-NN mac address
|
||||||
|
> OUTFILE output .hex/.txt/.bin file
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# compute checksum (twos complement of the sum of bytes)
|
||||||
|
|
||||||
|
sub chksum (@) { my $sum = 0; map($sum += $_, @_); (-$sum) & 0xFF; }
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# split the mac address info six hex fields
|
||||||
|
my @macaddr = map(hex($_)&0xFF, split(/-/, $macaddr));
|
||||||
|
|
||||||
|
# check supplied MAC address for validity
|
||||||
|
die "Invalid MAC address '$macaddr' format"
|
||||||
|
unless @macaddr == 6 && $macaddr eq join('-',map(sprintf("%02X",$_),@macaddr));
|
||||||
|
|
||||||
|
# echo what was input and we parsed
|
||||||
|
printf STDERR "MAC ADDR = %02X-%02X-%02X-%02X-%02X-%02X\n", @macaddr if $VERBOSE;
|
||||||
|
|
||||||
|
# compute checksum of the MAC address using 16b shift/add w/endaround carry
|
||||||
|
my $macchk = 0; # init value
|
||||||
|
for (my $idx = 0; $idx < $#macaddr; $idx += 2) { # loop on words
|
||||||
|
$macchk *= 2; # shift left 1
|
||||||
|
$macchk = ($macchk + ($macchk>>16))&0xFFFF; # end around carry
|
||||||
|
$macchk += ($macaddr[$idx+0]<<8) + $macaddr[$idx+1]; # add two bytes
|
||||||
|
$macchk = ($macchk + ($macchk>>16))&0xFFFF; # end around carry
|
||||||
|
}
|
||||||
|
printf STDERR "MAC checksum is %06o (0x%04X)\n", ($macchk) x 2 if $VERBOSE;
|
||||||
|
|
||||||
|
# split checksum into high/low bytes
|
||||||
|
my @macchk = (($macchk>>8)&0xFF, ($macchk>>0)&0xFF);
|
||||||
|
|
||||||
|
# build the entire device
|
||||||
|
my @buf = (@macaddr, @macchk, reverse(@macchk), reverse(@macaddr),
|
||||||
|
@macaddr, @macchk, (0xFF,0x00,0x55,0xAA)x2);
|
||||||
|
|
||||||
|
# print checksum of entire device
|
||||||
|
my $chksum = 0; map($chksum += $_, @buf);
|
||||||
|
printf STDERR "ROM checksum is %06o (0x%04X)\n", $chksum, $chksum if $VERBOSE;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# output the entire PROM buffer as an intel hex file
|
||||||
|
|
||||||
|
$bytesper = 16 if $bytesper <= 0;
|
||||||
|
|
||||||
|
for (my $idx = 0; $idx < $romsize; $idx += $bytesper) {
|
||||||
|
my $cnt = $idx+$bytesper <= $romsize ? $bytesper : $romsize-$idx; # N bytes or whatever is left
|
||||||
|
my @dat = @buf[$idx..($idx+$cnt-1)]; # get the data
|
||||||
|
my $dat = join('', map(sprintf("%02X",$_),@dat)); # map to ascii text
|
||||||
|
printf ":%02X%04X%02X%s%02X\n", $cnt, $idx, 0x00, $dat, &chksum($cnt, $idx>>0, $idx>>8, 0x00, @dat);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ":%02X%04X%02X%s%02X\n", 0x00, 0x0000, 0x01, '', &chksum(0x0, 0x0000>>0, 0x0000>>8, 0x01);
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
exit;
|
||||||
|
|
||||||
|
# the end
|
||||||
969
hex2mac/hex2mac.pl
Normal file
969
hex2mac/hex2mac.pl
Normal file
@ -0,0 +1,969 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
#!/usr/local/bin/perl -w
|
||||||
|
|
||||||
|
# Copyright (c) 2005-2016 Don North
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# o Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# o Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# o Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
require 5.008;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
hex2mac.pl - Disassembles PDP11 hex/binary files
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
hex2mac.pl
|
||||||
|
S<[--help]>
|
||||||
|
S<[--debug]>
|
||||||
|
S<[--verbose]>
|
||||||
|
S<[--option=STRING]>
|
||||||
|
S<[--boot]>
|
||||||
|
S<[--console]>
|
||||||
|
S<[--binary]>
|
||||||
|
S<[--logfile=LOGFILE]>
|
||||||
|
S<--infile=INFILE>
|
||||||
|
S<--outfile=OUTFILE>
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Disassembles an M9312 Intel-hex format PROM image
|
||||||
|
file (either a boot PROM or a console/diagnostic PROM)
|
||||||
|
to macro-11 source format.
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
The following options are available:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<--help>
|
||||||
|
|
||||||
|
Output this manpage and exit the program.
|
||||||
|
|
||||||
|
=item B<--debug>
|
||||||
|
|
||||||
|
Enable debug mode; print input file records as parsed.
|
||||||
|
|
||||||
|
=item B<--verbose>
|
||||||
|
|
||||||
|
Verbose mode (does nothing right now).
|
||||||
|
|
||||||
|
=item B<--boot>
|
||||||
|
|
||||||
|
Input file is an M9312 boot PROM image (512x4, half-used).
|
||||||
|
|
||||||
|
=item B<--console>
|
||||||
|
|
||||||
|
Input file is an M9312 diagnostic/console PROM image (1024x4).
|
||||||
|
|
||||||
|
=item B<--binary>
|
||||||
|
|
||||||
|
Input file is a PDP-11 binary program file (BIN/BIC/LDA/SYS).
|
||||||
|
|
||||||
|
=item B<--option=STRING>
|
||||||
|
|
||||||
|
For console PROMs, provide option flag to control disassembly.
|
||||||
|
|
||||||
|
=item B<--logfile=FILENAME>
|
||||||
|
|
||||||
|
Generate debug output into this file.
|
||||||
|
|
||||||
|
=item B<--infile=FILENAME>
|
||||||
|
|
||||||
|
Input file in selected format (HEX, BIN, OBJ, etc).
|
||||||
|
|
||||||
|
=item B<--outfile=FILENAME>
|
||||||
|
|
||||||
|
Output text file in .mac format.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 ERRORS
|
||||||
|
|
||||||
|
The following diagnostic error messages can be produced on STDERR.
|
||||||
|
The meaning should be fairly self explanatory.
|
||||||
|
|
||||||
|
C<Aborted due to command line errors> -- bad option or missing file(s)
|
||||||
|
|
||||||
|
C<Can't open input file '$file'> -- bad filename or unreadable file
|
||||||
|
|
||||||
|
C<File '%s': Unknown record type '%s' ignored> -- bad record type in hex file
|
||||||
|
|
||||||
|
C<File '%s': Bad data count, exp=0x%02X rcv=0x%02X, line='%s'> - bad record length in hex file
|
||||||
|
|
||||||
|
C<File '%s': Bad checksum, exp=0x%02X rcv=0x%02X, line='%s'> - checksum error in hex file
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
Some examples of common usage:
|
||||||
|
|
||||||
|
hex2mac.pl --help
|
||||||
|
|
||||||
|
hex2mac.pl --boot <23-751A9.hex >23-751A9.mac
|
||||||
|
|
||||||
|
=head1 NOTES
|
||||||
|
|
||||||
|
The disassembly process knows the 'standard' entry points
|
||||||
|
for boot and console PROMS, but is not real smart about multiple
|
||||||
|
entry points (it could be improved, but was not really worth
|
||||||
|
the extra trouble, as there are so few of these PROM images).
|
||||||
|
|
||||||
|
Console format was tuned for disassembling the 248F1 11/34,etc PROM.
|
||||||
|
Disassembly of the 616F1 11/70 PROM (not tried) will likely require
|
||||||
|
massive tuning to the internal entry point hash table.
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Don North - donorth <ak6dn _at_ mindspring _dot_ com>
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
Modification history:
|
||||||
|
|
||||||
|
2005-05-05 v1.0 donorth - Initial version.
|
||||||
|
2005-10-29 v1.1 donorth - Added auto-detect of boot continue PROM.
|
||||||
|
2016-09-09 v1.2 donorth - Added binary mode.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external standard modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
use FileHandle;
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, $ENV{PERL5LIB}) if defined($ENV{PERL5LIB}); # cygwin bugfix
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v1.2'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
my $crctype = 'CRC-16'; # type of crc calc to do
|
||||||
|
my $memsize; # number of instruction bytes allowed
|
||||||
|
my $memfill; # memory fill pattern
|
||||||
|
my %excaddr; # words to be skipped in rom crc calc
|
||||||
|
my $rombase; # base address of rom image
|
||||||
|
my $romsize; # number of rom addresses
|
||||||
|
my $romfill; # rom fill pattern
|
||||||
|
my $romtype = 'NONE'; # default rom type
|
||||||
|
my $option = ''; # option string
|
||||||
|
my $infile = undef; # input filename
|
||||||
|
my $outfile = undef; # output filename
|
||||||
|
my $logfile = undef; # log filename
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help" => \$HELP,
|
||||||
|
"debug" => \$DEBUG,
|
||||||
|
"verbose" => \$VERBOSE,
|
||||||
|
"boot" => sub { $romtype = 'BOOT'; },
|
||||||
|
"console" => sub { $romtype = 'DIAG'; },
|
||||||
|
"binary" => sub { $romtype = 'BINA'; },
|
||||||
|
"option=s" => \$option,
|
||||||
|
"infile=s" => \$infile,
|
||||||
|
"outfile=s" => \$outfile,
|
||||||
|
"logfile=s" => \$logfile,
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR
|
||||||
|
&& scalar(@ARGV) == 0
|
||||||
|
&& defined($infile)
|
||||||
|
&& defined($outfile)
|
||||||
|
&& $romtype ne 'NONE'
|
||||||
|
) {
|
||||||
|
printf STDERR "hex2mac.pl %s by Don North (perl %g)\n", $VERSION, $];
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
--boot M9312 boot prom
|
||||||
|
--console M9312 console/diagnostic prom
|
||||||
|
--binary binary program load image
|
||||||
|
--option=STRING option string for console prom
|
||||||
|
--infile=INFILE input object/hex pdp11 code file
|
||||||
|
--outfile=OUTFILE output ..mac pdp11 macro11 file
|
||||||
|
--logfile=LOGFILE logging message file
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# setup log file as a file, defaults to STDERR if not supplied
|
||||||
|
my $LOG = defined($logfile) ? FileHandle->new("> ".$logfile) : FileHandle->new_from_fd(fileno(STDERR),"w");
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# subroutine prototypes
|
||||||
|
|
||||||
|
sub pdp11 ($);
|
||||||
|
sub hexa ($);
|
||||||
|
sub trim ($);
|
||||||
|
sub chksum (@);
|
||||||
|
sub rad2asc (@);
|
||||||
|
sub crc (%);
|
||||||
|
sub read_rec ($);
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# fill in the parameters of the device
|
||||||
|
|
||||||
|
if ($romtype eq 'BOOT') {
|
||||||
|
|
||||||
|
# M9312 512x4 boot prom
|
||||||
|
%excaddr = ( 024=>1 ); # words to be skipped in rom crc calc
|
||||||
|
$memsize = 128; # number of instruction bytes allowed
|
||||||
|
$memfill = 0x00; # memory fill pattern
|
||||||
|
$romsize = 512; # number of rom addresses (must be a power of two)
|
||||||
|
$romfill = 0x00; # rom fill pattern
|
||||||
|
$rombase = 0173000; # base address of rom
|
||||||
|
|
||||||
|
} elsif ($romtype eq 'DIAG') {
|
||||||
|
|
||||||
|
# M9312 1024x4 diagnostic/console prom
|
||||||
|
%excaddr = ( ); # words to be skipped in rom crc calc
|
||||||
|
$memsize = 512; # number of instruction bytes allowed
|
||||||
|
$memfill = 0x00; # memory fill pattern
|
||||||
|
$romsize = 1024; # number of rom addresses
|
||||||
|
$romfill = 0x00; # rom fill pattern
|
||||||
|
$rombase = 0165000; # base address of rom
|
||||||
|
|
||||||
|
} elsif ($romtype eq 'BINA') {
|
||||||
|
|
||||||
|
# program load image ... 56KB address space maximum
|
||||||
|
%excaddr = ( ); # bytes to be skipped in rom crc calc
|
||||||
|
$memsize = 0; # number of instruction bytes allowed
|
||||||
|
$memfill = 0x00; # memory fill pattern
|
||||||
|
$romsize = 8*8192; # number of rom addresses (must be a power of two)
|
||||||
|
$romfill = 0x00; # image fill pattern
|
||||||
|
$rombase = 0; # base address of binary image
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# unknown ROM type code
|
||||||
|
die "ROM type '$romtype' is not supported!\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($VERBOSE) {
|
||||||
|
printf $LOG "ROM type is '%s'\n", $romtype;
|
||||||
|
printf $LOG "ROM space is %d. bytes\n", $memsize;
|
||||||
|
printf $LOG "ROM length is %d. addresses\n", $romsize;
|
||||||
|
printf $LOG "ROM base address is 0%06o\n", $rombase;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# read/process the input object/binary file records
|
||||||
|
|
||||||
|
# physical PROM data bytes
|
||||||
|
my @rom = ((0) x $romsize);
|
||||||
|
|
||||||
|
# real pdp11 memory data words
|
||||||
|
my @wrd = ();
|
||||||
|
|
||||||
|
# open the input file, die if error
|
||||||
|
my $INP = FileHandle->new("< ".$infile);
|
||||||
|
die "Error: can't open input file '$infile'\n" unless defined $INP;
|
||||||
|
|
||||||
|
if ($romtype eq 'BOOT' or $romtype eq 'DIAG') {
|
||||||
|
|
||||||
|
# process hex rom format
|
||||||
|
|
||||||
|
# extended address offset
|
||||||
|
my $extadr = 0;
|
||||||
|
|
||||||
|
# read the input hex-format stream into a buffer
|
||||||
|
while (my $line = scalar(<$INP>)) {
|
||||||
|
$line =~ s/[\015\012]+$//; # strip EOLs
|
||||||
|
if ($line =~ m/^:([0-9A-F]{2})([0-9A-F]{4})([0][0-3])([0-9A-F]{0,})([0-9A-F]{2})$/i) {
|
||||||
|
# 00 data record: :NNAAAA00DDDDD...DDDDCC
|
||||||
|
# 01 end record: :NNAAAA01CC
|
||||||
|
# 02 extended address record: :NNAAAA02EEEECC
|
||||||
|
# 03 start record: :NNAAAA03SSSSCC
|
||||||
|
my ($typ,$cnt,$adr,$chk,@dat) = (hex($3),hex($1),hex($2),hex($5),hexa($4));
|
||||||
|
|
||||||
|
# validate data byte count
|
||||||
|
unless (@dat == $cnt) {
|
||||||
|
printf $LOG "Bad data count, exp=0x%02X rcv=0x%02X, line='%s'\n",
|
||||||
|
$cnt, scalar(@dat), $line;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# compute checksum, validate
|
||||||
|
my $cmp = chksum($typ, $cnt, $adr, $adr>>8, @dat);
|
||||||
|
unless ($cmp == $chk) {
|
||||||
|
printf $LOG "Bad checksum, exp=0x%02X rcv=0x%02X, line='%s'\n", $cmp, $chk, $line;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# print what we read if debugging
|
||||||
|
printf $LOG "lin=%s typ=%d cnt=0x%02X adr=0x%04X chk=0x%02X dat=%s\n",
|
||||||
|
$line, $typ, $cnt, $adr, $chk,
|
||||||
|
join('',map(sprintf("%02X",$_),@dat)) if $DEBUG;
|
||||||
|
|
||||||
|
# process each record type
|
||||||
|
if ($typ == 0) {
|
||||||
|
# data record
|
||||||
|
for (my $idx = 0; $idx < $cnt; $idx++) { $rom[$extadr+$adr+$idx] = $dat[$idx]; }
|
||||||
|
} elsif ($typ == 2) {
|
||||||
|
# save extended address
|
||||||
|
$extadr = $adr<<4;
|
||||||
|
} elsif ($typ == 1) {
|
||||||
|
# exit if hit last
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printf $LOG "Unknown record type '%s' ignored\n", $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# now we have a buffer full of data, process it
|
||||||
|
for (my $idx = 0; $idx < $romsize; $idx += 4) {
|
||||||
|
# true byte address
|
||||||
|
my $adr = $idx>>1;
|
||||||
|
# merge 4 nibbles into 16 data bits
|
||||||
|
my $dat = ($rom[$idx+3]<<12) | ($rom[$idx+2]<<8) | ($rom[$idx+1]<<4) | ($rom[$idx+0]<<0);
|
||||||
|
$dat = $dat ^ 0x1C00; # bits 12:10 get inverted
|
||||||
|
$dat = ($dat & 0xFEFE) | ((0x0100&$dat)>>8) | ((0x0001&$dat)<<8); # swap bits 8,0
|
||||||
|
printf $LOG "adr=%06o dat=%06o\n", $adr, $dat if $DEBUG;
|
||||||
|
# store it
|
||||||
|
$wrd[$adr] = $dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($romtype eq 'BINA') {
|
||||||
|
|
||||||
|
# process binary format file
|
||||||
|
|
||||||
|
while (my @rec = &read_rec($INP)) {
|
||||||
|
|
||||||
|
my $len = scalar(@rec)-2;
|
||||||
|
my $minadr = $rec[1]*256+$rec[0];
|
||||||
|
|
||||||
|
foreach my $i (0..($len-1)) {
|
||||||
|
my ($adr,$dat) = ($minadr+$i,$rec[2+$i]);
|
||||||
|
printf $LOG "adr=%06o dat=%03o\n", $adr, $dat if $DEBUG;
|
||||||
|
$wrd[$adr] = $memfill unless defined $wrd[$adr];
|
||||||
|
if ($adr & 1) {
|
||||||
|
# upper/odd byte
|
||||||
|
$wrd[$adr-1] = ($wrd[$adr-1]&0x00FF) | ($dat<<8);
|
||||||
|
} else {
|
||||||
|
# lower/even byte
|
||||||
|
$wrd[$adr+0] = ($wrd[$adr+0]&0xFF00) | ($dat<<0);
|
||||||
|
}
|
||||||
|
$memsize = $adr if $adr > $memsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($DEBUG) {
|
||||||
|
for (my $i = 0; defined $wrd[$i]; $i += 2) {
|
||||||
|
my $ub = ($wrd[$i]>>8)&0xFF; $ub = 056 if $ub < 040 || $ub > 0176;
|
||||||
|
my $lb = ($wrd[$i]>>0)&0xFF; $lb = 056 if $lb < 040 || $lb > 0176;
|
||||||
|
printf $LOG "wrd[%06d]=%06o \"%c%c\"\n", $i, $wrd[$i], $lb, $ub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# done with input file
|
||||||
|
$INP->close;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# disassemble the prom image we just unmangled
|
||||||
|
|
||||||
|
my $OUT = FileHandle->new("> ".$outfile);
|
||||||
|
die "Error: can't open output file '$outfile'\n" unless defined $OUT;
|
||||||
|
|
||||||
|
my %entry = ();
|
||||||
|
my %label = ();
|
||||||
|
my $label = 0;
|
||||||
|
my $continuation = ($wrd[0] == 0177776); # a continuation boot PROM
|
||||||
|
|
||||||
|
if ($romtype eq 'DIAG') {
|
||||||
|
%label = ( 020=>'DIAG', 0144=>'NODIAG', 0564=>'RSTRT' );
|
||||||
|
} elsif ($romtype eq 'BOOT') {
|
||||||
|
if ($continuation) {
|
||||||
|
%label = ( 02=>'CONT' );
|
||||||
|
} else {
|
||||||
|
%label = ( 04=>'PUP0ND', 06=>'PUP0D', 012=>'BOOTSZ', 016=>'BOOTNZ', 020=>'SECD' );
|
||||||
|
}
|
||||||
|
} elsif ($romtype eq 'BINA') {
|
||||||
|
%label = ( 0174=>'START',
|
||||||
|
0123=>'WTERR', 0134=>'RDERR', 0150=>'ILLCMD' );
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $pass (1..2) {
|
||||||
|
|
||||||
|
if ($romtype eq 'DIAG') {
|
||||||
|
# these entry points found by inspection/iteration for the 248F1 PROM
|
||||||
|
# probably will be different for 616F1 PROM (hasn't been tried yet)
|
||||||
|
if ($option eq '248F1') {
|
||||||
|
%entry = ( 0020=>1, 0144=>1, 0564=>1,
|
||||||
|
0112=>1, 0120=>1, 0124=>1,
|
||||||
|
0150=>1, 0154=>1, 0160=>1, 0166=>1, 0172=>1, 0200=>1, 0210=>1,
|
||||||
|
0214=>1, 0220=>1, 0320=>1, 0342=>1, 0352=>1, 0376=>1, 0446=>1,
|
||||||
|
0510=>1, 0650=>1, 0662=>1, 0700=>1,
|
||||||
|
);
|
||||||
|
} elsif ($option eq '616F1') {
|
||||||
|
%entry = ( 0020=>1, 0144=>1, 0564=>1,
|
||||||
|
0000=>1, 0340=>1, 0342=>1, 0352=>1, 0354=>1, 0360=>1, 0362=>1,
|
||||||
|
0554=>1, 0676=>1, 0714=>1, 0716=>1, 0744=>1, 0772=>1,
|
||||||
|
);
|
||||||
|
} elsif ($option eq '446F1') {
|
||||||
|
%entry = ( 0020=>1, 0144=>1, 0564=>1,
|
||||||
|
0000=>1, 0010=>1, 0016=>1, 0070=>1, 0146=>1, 0366=>1, 0370=>1,
|
||||||
|
0400=>1, 0402=>1, 0406=>1, 0410=>1, 0466=>1, 0652=>1, 0662=>1,
|
||||||
|
0666=>1, 0676=>1, 0702=>1, 0704=>1, 0714=>1, 0736=>1,
|
||||||
|
);
|
||||||
|
} elsif ($option eq '774F1') {
|
||||||
|
%entry = ( 0020=>1, 0144=>1, 0564=>1,
|
||||||
|
0006=>1, 0316=>1, 0364=>1, 0552=>1,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
%entry = ( 0020=>1, 0144=>1, 0564=>1 );
|
||||||
|
}
|
||||||
|
} elsif ($romtype eq 'BOOT') {
|
||||||
|
# standard entry points for a single-device boot PROM
|
||||||
|
if ($continuation) {
|
||||||
|
%entry = ( 02=>1 );
|
||||||
|
} else {
|
||||||
|
%entry = ( 04=>1, 06=>1, 012=>1, 016=>1, 020=>1 );
|
||||||
|
}
|
||||||
|
} elsif ($romtype eq 'BINA') {
|
||||||
|
# binary load image file
|
||||||
|
%entry = ( 0174=>1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$label = 1; # reset label counter
|
||||||
|
|
||||||
|
if ($pass == 1) {
|
||||||
|
|
||||||
|
# now iterate over the words of interest
|
||||||
|
for (my $adr = 0; $adr < $memsize; $adr += 2) {
|
||||||
|
if (exists($entry{$adr})) { # an instr should start here
|
||||||
|
my ($cntr,$inst) = &pdp11($adr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($pass == 2) {
|
||||||
|
|
||||||
|
printf $OUT "\t.sbttl\t%s\n\n", "M9312 $romtype prom";
|
||||||
|
printf $OUT "\t.asect\n\t.=%o\n\n", $rombase;
|
||||||
|
|
||||||
|
# now iterate over the words of interest
|
||||||
|
for (my $adr = 0; $adr < $memsize; $adr += 2) {
|
||||||
|
|
||||||
|
if (exists($entry{$adr})) { # an instr should start here
|
||||||
|
|
||||||
|
my ($cntr,$inst) = &pdp11($adr);
|
||||||
|
printf $OUT "%06o:\t%06o\t", $adr, $wrd[$adr] if $DEBUG;
|
||||||
|
printf $OUT "%s:", $label{$adr} if $label{$adr};
|
||||||
|
printf $OUT "\t%s\n", $inst;
|
||||||
|
while (--$cntr > 0) {
|
||||||
|
$adr += 2;
|
||||||
|
printf $OUT "%06o:\t%06o\n", $adr, $wrd[$adr] if $DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($romtype eq 'BOOT' && $adr == 0 && !$continuation) { # special string for boot
|
||||||
|
|
||||||
|
printf $OUT "%06o:\t%06o\t", $adr, $wrd[$adr] if $DEBUG;
|
||||||
|
printf $OUT "\t.ascii\t\"%c%c\"\n", ($wrd[$adr]>>0)&0xFF, ($wrd[$adr]>>8)&0xFF;
|
||||||
|
|
||||||
|
} else { # just print it as a data word
|
||||||
|
|
||||||
|
printf $OUT "%06o:\t%06o\t", $adr, $wrd[$adr] if $DEBUG;
|
||||||
|
printf $OUT "%s:", $label{$adr} if $label{$adr};
|
||||||
|
my $lb = ($wrd[$adr]>>0)&0xFF; $lb = 056 if $lb < 040 || $lb > 0176;
|
||||||
|
my $ub = ($wrd[$adr]>>8)&0xFF; $ub = 056 if $ub < 040 || $ub > 0176;
|
||||||
|
printf $OUT "\t.word\t%06o\t\t; \"%c%c\"\n", $wrd[$adr], $lb, $ub;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
printf $OUT "\n\t.end\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# all done
|
||||||
|
$OUT->close;
|
||||||
|
exit;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# disassemble a pdp11 instr at $adr in image $wrd[]
|
||||||
|
|
||||||
|
sub pdp11 ($) {
|
||||||
|
|
||||||
|
my ($adr) = @_;
|
||||||
|
|
||||||
|
# generate a register specifier
|
||||||
|
sub _r {
|
||||||
|
my $r = $_[0]&7;
|
||||||
|
return $r == 7 ? 'pc' : $r == 6 ? 'sp' : 'r'.$r;
|
||||||
|
} # sub _r
|
||||||
|
|
||||||
|
# generate src/dst operand reference
|
||||||
|
sub _mode {
|
||||||
|
my ($mode, $adr, $off) = @_;
|
||||||
|
my ($m, $r) = (($mode>>3)&7, _r(($mode>>0)&7));
|
||||||
|
if ($r eq 'pc') {
|
||||||
|
my $ea = ($adr + $off + $wrd[$adr]) & 0xFFFF;
|
||||||
|
if ($m == 0) { return sprintf("pc"); }
|
||||||
|
elsif ($m == 1) { return sprintf("(pc)"); }
|
||||||
|
elsif ($m == 2) { return sprintf("#%o", $wrd[$adr]); }
|
||||||
|
elsif ($m == 3) { return sprintf("\@#%o", $wrd[$adr]); }
|
||||||
|
elsif ($m == 4) { return sprintf("-(pc)"); }
|
||||||
|
elsif ($m == 5) { return sprintf("\@-(pc)"); }
|
||||||
|
elsif ($m == 6) { return sprintf("%s", exists($label{$ea})?$label{$ea}:sprintf("0%o",$ea)); }
|
||||||
|
elsif ($m == 7) { return sprintf("\@%s", exists($label{$ea})?$label{$ea}:sprintf("0%o",$ea)); }
|
||||||
|
} else {
|
||||||
|
if ($m == 0) { return sprintf("%s", $r); }
|
||||||
|
elsif ($m == 1) { return sprintf("(%s)", $r); }
|
||||||
|
elsif ($m == 2) { return sprintf("(%s)+", $r); }
|
||||||
|
elsif ($m == 3) { return sprintf("\@(%s)+", $r); }
|
||||||
|
elsif ($m == 4) { return sprintf("-(%s)", $r); }
|
||||||
|
elsif ($m == 5) { return sprintf("\@-(%s)", $r); }
|
||||||
|
elsif ($m == 6) { return sprintf("%o(%s)", $wrd[$adr],$r); }
|
||||||
|
elsif ($m == 7) { return sprintf("\@%o(%s)", $wrd[$adr],$r); }
|
||||||
|
}
|
||||||
|
} # sub _mode
|
||||||
|
|
||||||
|
# return 1/0 if indicated address mode will eat an instr stream word
|
||||||
|
sub _eat {
|
||||||
|
my ($mode) = @_;
|
||||||
|
my ($m, $r) = (($mode>>3)&7, ($mode>>0)&7);
|
||||||
|
return ($r == 7 && ($m == 2 || $m == 3)) || $m == 6 || $m == 7 ? 1 : 0;
|
||||||
|
} # sub _eat
|
||||||
|
|
||||||
|
my $wrd = $wrd[$adr]; # instruction word
|
||||||
|
my $str = 'NONE'; # build the instruction here
|
||||||
|
my $cnt = 1; # number of instruction words total
|
||||||
|
delete($entry{$adr}); # eat the current instruction
|
||||||
|
|
||||||
|
if ($wrd >= 000000 && $wrd <= 000007) { # ok
|
||||||
|
#
|
||||||
|
# misc single-word zop instructions
|
||||||
|
#
|
||||||
|
$str = ('halt','wait','rti','bpt','iot','reset','rtt','mfpt')[$wrd&7];
|
||||||
|
$entry{$adr+2}++ unless $str =~ m/^(halt|rti|rtt)$/i;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 0104000 && $wrd <= 0104377) { # ok
|
||||||
|
#
|
||||||
|
# trap single-word sop instructions
|
||||||
|
#
|
||||||
|
my $opc = ('emt','trap')[($wrd&000400)>>8];
|
||||||
|
$str = sprintf("%s\t%o", $opc, $wrd&0377);
|
||||||
|
$entry{$adr+2}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 000230 && $wrd <= 000237) { # ok
|
||||||
|
#
|
||||||
|
# priority-level sop single-word instruction
|
||||||
|
#
|
||||||
|
$str = sprintf("spl\t%o", $wrd&7);
|
||||||
|
$entry{$adr+2}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 000240 && $wrd <= 000277) { # ok
|
||||||
|
#
|
||||||
|
# condition code zop single-word instructions
|
||||||
|
#
|
||||||
|
if ($wrd == 000240) { $str = 'nop'; }
|
||||||
|
elsif ($wrd == 000260) { $str = 'nop2'; }
|
||||||
|
elsif ($wrd == 000257) { $str = 'ccc'; }
|
||||||
|
elsif ($wrd == 000277) { $str = 'scc'; }
|
||||||
|
else { $str = join('', $wrd&020?'se':'cl', $wrd&010?'n':'',$wrd&04?'z':'',$wrd&02?'v':'',$wrd&01?'c':''); }
|
||||||
|
$entry{$adr+2}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 000400 && $wrd <= 003777 || $wrd >= 0100000 && $wrd <= 0103777) { # ok
|
||||||
|
#
|
||||||
|
# conditional branch sop single-word instructions
|
||||||
|
#
|
||||||
|
my $opc = ('xxx','br', 'bne','beq', 'bge','blt','bgt','ble',
|
||||||
|
'bpl','bmi','bhi','blos','bvc','bvs','bcc','bcs'
|
||||||
|
) [ (($wrd&0100000)>>12) | (($wrd&03400)>>8) ];
|
||||||
|
my $off = $wrd&0377; $off = -(0400-$off) if $off >= 0200;
|
||||||
|
my $npc = $adr+2 + 2*$off;
|
||||||
|
$label{$npc} = 'L'.$label++ unless exists($label{$npc});
|
||||||
|
if (0) {
|
||||||
|
$str = sprintf("%s\t.%s%o\t\t; %06o [%s]",
|
||||||
|
$opc, $off < 0 ? '-' : '+', abs($npc-$adr), $npc, $label{$npc});
|
||||||
|
} else {
|
||||||
|
$str = sprintf("%s\t%s\t\t; %06o [.%s%o]",
|
||||||
|
$opc, $label{$npc}, $npc, $off < 0 ? '-' : '+', abs($npc-$adr));
|
||||||
|
}
|
||||||
|
$entry{$adr+2}++ if $opc ne 'br';
|
||||||
|
$entry{$npc}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 077000 && $wrd <= 077777) { # maybe
|
||||||
|
#
|
||||||
|
# subtract-one-branch dop single-word instruction
|
||||||
|
#
|
||||||
|
my $off = $wrd&077;
|
||||||
|
my $npc = $adr+2 - 2*$off;
|
||||||
|
$label{$npc} = 'L'.$label++ unless exists($label{$npc});
|
||||||
|
if (0) {
|
||||||
|
$str = sprintf("%s\t%s,.-%o\t\t; %06o [%s]",
|
||||||
|
'sob', _r($wrd>>6), abs($npc-$adr), $npc, $label{$npc});
|
||||||
|
} else {
|
||||||
|
$str = sprintf("%s\t%s,%s\t\t; %06o [.-%o]",
|
||||||
|
'sob', _r($wrd>>6), $label{$npc}, $npc, abs($npc-$adr));
|
||||||
|
}
|
||||||
|
$entry{$adr+2}++;
|
||||||
|
$entry{$npc}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 000200 && $wrd <= 000207) { # ok
|
||||||
|
#
|
||||||
|
# return-from-subroutine sop single-word instruction
|
||||||
|
#
|
||||||
|
$str = sprintf("rts\t%s", _r($wrd>>0));
|
||||||
|
|
||||||
|
} elsif ($wrd >= 000100 && $wrd <= 000177) { # maybe
|
||||||
|
#
|
||||||
|
# unconditional jump sop single/double-word instruction
|
||||||
|
#
|
||||||
|
$str = sprintf("%s\t%s", 'jmp', _mode($wrd>>0,$adr+2,2));
|
||||||
|
$cnt += _eat($wrd>>0);
|
||||||
|
if (($wrd&077) == 037) { # absolute address @#FOO
|
||||||
|
$entry{$wrd[$adr+2]}++;
|
||||||
|
} elsif (($wrd&067) == 067) { # pc-relative address FOO
|
||||||
|
my $npc = ($adr+2 + 2 + $wrd[$adr+2]) & 0xFFFF;
|
||||||
|
$label{$npc} = 'L'.$label++ unless exists($label{$npc});
|
||||||
|
$entry{$npc}++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($wrd >= 004000 && $wrd <= 004777) { # maybe
|
||||||
|
#
|
||||||
|
# jump-to-subr dop single/double-word instruction
|
||||||
|
#
|
||||||
|
$str = sprintf("%s\t%s,%s", 'jsr', _r($wrd>>6), _mode($wrd>>0,$adr+2,2));
|
||||||
|
$cnt += _eat($wrd>>0);
|
||||||
|
if (($wrd&077) == 037) { # absolute address @#FOO
|
||||||
|
$entry{$wrd[$adr+2]}++;
|
||||||
|
} elsif (($wrd&067) == 067) { # pc-relative address FOO
|
||||||
|
my $npc = ($adr+2 + 2 + $wrd[$adr+2]) & 0xFFFF;
|
||||||
|
$label{$npc} = 'L'.$label++ unless exists($label{$npc});
|
||||||
|
$entry{$npc}++;
|
||||||
|
}
|
||||||
|
$entry{$adr+2 + 2*_eat($wrd>>0)}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 005000 && $wrd <= 006777 || $wrd >= 0105000 && $wrd <= 0106777 ||
|
||||||
|
$wrd >= 000300 && $wrd <= 000377) { # maybe
|
||||||
|
#
|
||||||
|
# arithmetic sop single/double-word instructions
|
||||||
|
#
|
||||||
|
my $opc = ('ror', 'rol', 'asr', 'asl', 'mark','mfpi','mtpi','sxt',
|
||||||
|
'clr', 'com', 'inc', 'dec', 'neg', 'adc', 'sbc', 'tst',
|
||||||
|
'rorb','rolb','asrb','aslb','mtps','mfpd','mtpd','mfps',
|
||||||
|
'clrb','comb','incb','decb','negb','adcb','sbcb','tstb'
|
||||||
|
) [ (($wrd&0100000)>>11) | (($wrd&001700)>>6) ];
|
||||||
|
$opc = 'swab' if $wrd <= 000377;
|
||||||
|
if ($opc eq 'mark') {
|
||||||
|
$str = sprintf("mark\t%o", $wrd&077);
|
||||||
|
} else {
|
||||||
|
if ((($wrd>>0)&067) == 067) {
|
||||||
|
my $ea = ($adr+2 + 2 + $wrd[$adr+2]) & 0xFFFF;
|
||||||
|
$label{$ea} = 'L'.$label++ unless exists($label{$ea});;
|
||||||
|
}
|
||||||
|
$str = sprintf("%s\t%s", $opc, _mode($wrd>>0,$adr+2,2));
|
||||||
|
$cnt += _eat($wrd>>0);
|
||||||
|
$entry{$adr+2 + 2*_eat($wrd>>0)}++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($wrd >= 070000 && $wrd <= 074777) { # maybe
|
||||||
|
#
|
||||||
|
# arithmetic dop single/double-word instructions
|
||||||
|
#
|
||||||
|
my $opc = ('mul','div','ash','ashc','xor') [ ($wrd&007000)>>9 ];
|
||||||
|
if ((($wrd>>0)&067) == 067) {
|
||||||
|
my $ea = ($adr+2 + 2 + $wrd[$adr+2]) & 0xFFFF;
|
||||||
|
$label{$ea} = 'L'.$label++ unless exists($label{$ea});;
|
||||||
|
}
|
||||||
|
if ($opc eq 'xor') {
|
||||||
|
$str = sprintf("%s\t%s,%s", $opc, _r($wrd>>6), _mode($wrd>>0,$adr+2,2));
|
||||||
|
} else {
|
||||||
|
$str = sprintf("%s\t%s,%s", $opc, _mode($wrd>>0,$adr+2,2), _r($wrd>>6));
|
||||||
|
}
|
||||||
|
$cnt += _eat($wrd>>0);
|
||||||
|
$entry{$adr+2 + 2*_eat($wrd>>0)}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 010000 && $wrd <= 067777 || $wrd >= 0110000 && $wrd <= 0167777) { # maybe
|
||||||
|
#
|
||||||
|
# arithmetic dop single/double/triple-word instructions
|
||||||
|
#
|
||||||
|
my $opc = ('xxx','mov', 'cmp', 'bit', 'bic', 'bis', 'add','xxx',
|
||||||
|
'xxx','movb','cmpb','bitb','bicb','bisb','sub','xxx'
|
||||||
|
) [ ($wrd&0170000)>>12 ];
|
||||||
|
if ((($wrd>>6)&067) == 067) {
|
||||||
|
my $ea = ($adr+2 + 2 + $wrd[$adr+2]) & 0xFFFF;
|
||||||
|
$label{$ea} = 'L'.$label++ unless exists($label{$ea});;
|
||||||
|
}
|
||||||
|
if ((($wrd>>0)&067) == 067) {
|
||||||
|
my $ea = ($adr+2 + 2*_eat($wrd>>6) + 2 + $wrd[$adr+2*_eat($wrd>>6)+2]) & 0xFFFF;
|
||||||
|
$label{$ea} = 'L'.$label++ unless exists($label{$ea});;
|
||||||
|
}
|
||||||
|
$str = sprintf("%s\t%s,%s",
|
||||||
|
$opc, _mode($wrd>>6,$adr+2,2), _mode($wrd>>0,$adr+2+2*_eat($wrd>>6),4));
|
||||||
|
$cnt += _eat($wrd>>6) + _eat($wrd>>0);
|
||||||
|
$entry{$adr+2 + 2*_eat($wrd>>6) + 2*_eat($wrd>>0)}++;
|
||||||
|
|
||||||
|
} elsif ($wrd >= 0170000 && $wrd <= 0177777) { # TBD
|
||||||
|
#
|
||||||
|
# FPP float sop/dop single/double-word instructions
|
||||||
|
#
|
||||||
|
$str = 'float';
|
||||||
|
$entry{$adr+2}++;
|
||||||
|
|
||||||
|
} else { # ok
|
||||||
|
#
|
||||||
|
# all ILLEGAL opcodes (not previously decoded)
|
||||||
|
#
|
||||||
|
$str = 'ILLEGAL';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($cnt,$str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# convert string of byte hex characters to an array of numbers
|
||||||
|
|
||||||
|
sub hexa ($) {
|
||||||
|
|
||||||
|
my ($dat) = @_;
|
||||||
|
|
||||||
|
my @dat = ();
|
||||||
|
while ($dat) { push(@dat,hex(substr($dat,0,2))); $dat = substr($dat,2); }
|
||||||
|
|
||||||
|
return @dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# trim leading/trailing spaces on a string
|
||||||
|
|
||||||
|
sub trim ($) {
|
||||||
|
|
||||||
|
my ($str) = @_;
|
||||||
|
|
||||||
|
$str =~ s/\s+$//;
|
||||||
|
$str =~ s/^\s+//;
|
||||||
|
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# compute checksum (twos complement of the sum of bytes)
|
||||||
|
|
||||||
|
sub chksum (@) {
|
||||||
|
|
||||||
|
my $sum = 0;
|
||||||
|
|
||||||
|
map($sum += $_, @_);
|
||||||
|
|
||||||
|
return (-$sum) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# RAD50 to ASCII decode
|
||||||
|
|
||||||
|
sub rad2asc (@) {
|
||||||
|
|
||||||
|
my @str = split(//, ' ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789'); # RAD50 character subset
|
||||||
|
|
||||||
|
my $ascii = "";
|
||||||
|
foreach my $rad50 (@_) {
|
||||||
|
$ascii .= $str[int($rad50/1600)%40] . $str[int($rad50/40)%40] . $str[$rad50%40];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ascii;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# crc computation routine
|
||||||
|
|
||||||
|
sub crc (%) {
|
||||||
|
|
||||||
|
# pass all args by name
|
||||||
|
my %args = @_;
|
||||||
|
|
||||||
|
# all the crcs we know how to compute
|
||||||
|
my %crcdat = ( 'CRC-16' => [ 0xA001, 2, 0x0000, 0x0000 ],
|
||||||
|
'CRC-32' => [ 0xEDB88320, 4, 0xFFFFFFFF, 0xFFFFFFFF ] );
|
||||||
|
|
||||||
|
# run next byte thru crc computation, return updated crc
|
||||||
|
return $args{-table}[($args{-crc}^$args{-byte}) & 0xFF]^($args{-crc}>>8) if exists($args{-byte});
|
||||||
|
|
||||||
|
# return initial crc value
|
||||||
|
return $crcdat{$args{-name}}->[2] if exists($args{-init});
|
||||||
|
|
||||||
|
# return final crc value xored with xorout
|
||||||
|
return $args{-crc} ^ $crcdat{$args{-name}}->[3] if exists($args{-last});
|
||||||
|
|
||||||
|
# compute the crc lookup table, return a pointer to it
|
||||||
|
if (exists($args{-new})) {
|
||||||
|
my $crctab = [];
|
||||||
|
my $poly = $crcdat{$args{-name}}->[0];
|
||||||
|
foreach my $byte (0..255) {
|
||||||
|
my $data = $byte;
|
||||||
|
foreach (1..8) { $data = ($data>>1) ^ ($data&1 ? $poly : 0); }
|
||||||
|
$$crctab[$byte] = $data;
|
||||||
|
}
|
||||||
|
return $crctab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# read a record from the object file
|
||||||
|
|
||||||
|
sub read_rec ($) {
|
||||||
|
|
||||||
|
my ($fh) = @_;
|
||||||
|
|
||||||
|
my ($buf, $cnt, $len, $err) = (0,0,0,0);
|
||||||
|
my @pre = ();
|
||||||
|
my @dat = ();
|
||||||
|
my @suf = ();
|
||||||
|
|
||||||
|
# Object file format consists of blocks, optionally preceded, separated, and
|
||||||
|
# followed by zeroes. Each block consists of:
|
||||||
|
#
|
||||||
|
# 001 ---
|
||||||
|
# 000 |
|
||||||
|
# lo(length) |
|
||||||
|
# hi(length) > 'length' bytes
|
||||||
|
# databyte1 |
|
||||||
|
# : |
|
||||||
|
# databyteN ---
|
||||||
|
# checksum
|
||||||
|
#
|
||||||
|
|
||||||
|
# skip over strings of 0x00; exit OK if hit EOF
|
||||||
|
do { return () unless $cnt = read($fh, $buf, 1); } while (ord($buf) == 0);
|
||||||
|
|
||||||
|
# valid record starts with (1)
|
||||||
|
$err = 1 unless $cnt == 1 && ord($buf) == 1;
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# second byte must be (0)
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 2 unless $cnt == 1 && ord($buf) == 0;
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# third byte is low byte of record length
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 3 unless $cnt == 1;
|
||||||
|
$len = ord($buf);
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# fourth byte is high byte of record length
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 4 unless $cnt == 1;
|
||||||
|
$len += ord($buf)<<8;
|
||||||
|
push(@pre, ord($buf));
|
||||||
|
|
||||||
|
# bytes five thru end-1 are data bytes
|
||||||
|
$cnt = read($fh, $buf, $len-4);
|
||||||
|
$err = 5 unless $cnt == $len-4 && $len >= 4;
|
||||||
|
@dat = unpack("C*", $buf);
|
||||||
|
|
||||||
|
# last byte is checksum
|
||||||
|
$cnt = read($fh, $buf, 1);
|
||||||
|
$err = 6 unless $cnt == 1;
|
||||||
|
my $rcv = ord($buf);
|
||||||
|
push(@suf, ord($buf));
|
||||||
|
|
||||||
|
# output the record if debugging
|
||||||
|
if ($DEBUG) {
|
||||||
|
my $fmt = "%03o";
|
||||||
|
my $n = 16;
|
||||||
|
my $pre = sprintf("RECORD: [%s] ",join(" ",map(sprintf($fmt,$_),@pre)));
|
||||||
|
printf $LOG "\n\n%s", $pre;
|
||||||
|
my $k = length($pre);
|
||||||
|
my @tmp = @dat;
|
||||||
|
while (@tmp > $n) {
|
||||||
|
printf $LOG "%s\n%*s", join(" ",map(sprintf($fmt,$_),splice(@tmp,0,$n))), $k, '';
|
||||||
|
}
|
||||||
|
printf $LOG "%s", join(" ",map(sprintf($fmt,$_),@tmp)) if @tmp;
|
||||||
|
printf $LOG " [%s]\n\n", join(" ",map(sprintf($fmt,$_),@suf));
|
||||||
|
}
|
||||||
|
|
||||||
|
# check we have a well formatted record
|
||||||
|
die sprintf("Error: invalid object file record format (%d)", $err) if $err;
|
||||||
|
|
||||||
|
# compare rcv'ed checksum vs exp'ed checksum
|
||||||
|
my $exp = &chksum(0x01, $len>>0, $len>>8, @dat);
|
||||||
|
die sprintf("Error: Bad checksum exp=0x%02X rcv=0x%02X", $exp, $rcv) unless $exp == $rcv;
|
||||||
|
|
||||||
|
# all is well, return the record
|
||||||
|
return @dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# the end
|
||||||
586
img2sdcard/img2sdcard.pl
Normal file
586
img2sdcard/img2sdcard.pl
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
#!/usr/local/bin/perl -w
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external global modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
use FileHandle;
|
||||||
|
use File::Copy;
|
||||||
|
use File::Compare;
|
||||||
|
use POSIX;
|
||||||
|
use Expect;
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# defaults
|
||||||
|
my $VERSION = 'v1.0'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# arguments
|
||||||
|
my $XMLFILE = undef; # define for XML file output
|
||||||
|
my $DEVICE = undef; # define for device selection as /dev/DEVICE
|
||||||
|
my $SLICE = undef; # define for device selection as $DEVICE.$SLICE
|
||||||
|
my $SCSI = undef; # list of scsi IDs per partition
|
||||||
|
my $READFILE = undef; # image file to read
|
||||||
|
my $WRITEFILE = undef; # image file to write
|
||||||
|
my $COMPAREFILE = undef; # image file to compare
|
||||||
|
my $PARTITIONS = undef; # list of data partitions to create
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help!" => \$HELP,
|
||||||
|
"debug!" => \$DEBUG,
|
||||||
|
"verbose!" => \$VERBOSE,
|
||||||
|
"xmlfile=s" => \$XMLFILE,
|
||||||
|
"readfile=s" => \$READFILE,
|
||||||
|
"writefile=s" => \$WRITEFILE,
|
||||||
|
"comparefile=s" => \$COMPAREFILE,
|
||||||
|
"device=s" => \$DEVICE,
|
||||||
|
"slice=i" => \$SLICE,
|
||||||
|
"scsi=s" => \$SCSI,
|
||||||
|
"partitions=s" => \$PARTITIONS,
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR
|
||||||
|
&& scalar(@ARGV) == 0
|
||||||
|
&& defined($DEVICE)
|
||||||
|
) {
|
||||||
|
printf STDERR "%s %s (perl %g)\n", $0, $VERSION, $];
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
--device=DEVICE device SDcard is mounted on (ie, sdd) [REQUIRED]
|
||||||
|
--slice=N logical partition number 5..8 [optional]
|
||||||
|
--xmlfile=XMLFILE generated .xml description file [optional]
|
||||||
|
--readfile=IMGFILE image file to read from disk [optional]
|
||||||
|
--writefile=IMGFILE image file to write to disk [optional]
|
||||||
|
--comparefile=IMGFILE image file to compare to disk [optional]
|
||||||
|
--scsi=S1[,S2[,S3[,S4]]] scsi id per partition [optional]
|
||||||
|
--partitions=P1[,P2[,P3[,P4]]] logical partition sizes [optional]
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# database setup
|
||||||
|
|
||||||
|
my %db = ();
|
||||||
|
my %slice = ();
|
||||||
|
my $devfile = '/dev/'.$DEVICE;
|
||||||
|
|
||||||
|
my %disktab = ( # type legacy#blocks assigned#blocks size-in-MB text-description
|
||||||
|
RL01 => { actual => 10240, allocate => 10240, capacity => 5, description => 'DEC RL01' },
|
||||||
|
RL02 => { actual => 20480, allocate => 20480, capacity => 10, description => 'DEC RL02' },
|
||||||
|
RD51 => { actual => 21600, allocate => 22528, capacity => 11, description => 'DEC RD51 Winchester' },
|
||||||
|
RK06 => { actual => 27126, allocate => 28672, capacity => 14, description => 'DEC RK06' },
|
||||||
|
RD31 => { actual => 41560, allocate => 43008, capacity => 21, description => 'DEC RD31 Winchester' },
|
||||||
|
RC25 => { actual => 50902, allocate => 51200, capacity => 25, description => 'RCF25' },
|
||||||
|
RK07 => { actual => 53790, allocate => 55296, capacity => 27, description => 'DEC RK07' },
|
||||||
|
RD52 => { actual => 60480, allocate => 61440, capacity => 30, description => 'DEC RD52 Winchester' },
|
||||||
|
RD32 => { actual => 83236, allocate => 83968, capacity => 41, description => 'DEC RD32 Winchester' },
|
||||||
|
RZ22 => { actual => 102432, allocate => 104448, capacity => 51, description => 'DEC RZ22 Winchester' },
|
||||||
|
AMP980 => { actual => 131680, allocate => 133120, capacity => 65, description => 'AMPEX DM980' },
|
||||||
|
RM03 => { actual => 131680, allocate => 133120, capacity => 65, description => 'DEC RM03' },
|
||||||
|
RD33 => { actual => 138565, allocate => 139264, capacity => 68, description => 'DEC RD33 Winchester' },
|
||||||
|
RD53 => { actual => 138672, allocate => 139264, capacity => 68, description => 'DEC RD53 Winchester' },
|
||||||
|
RP05 => { actual => 171798, allocate => 172032, capacity => 84, description => 'DEC RP05' },
|
||||||
|
RZ23 => { actual => 204864, allocate => 206848, capacity => 101, description => 'DEC RZ23 Winchester' },
|
||||||
|
RA80 => { actual => 237212, allocate => 237568, capacity => 116, description => 'DEC RA80 Winchester' },
|
||||||
|
RZ23L => { actual => 237588, allocate => 239616, capacity => 117, description => 'DEC RZ23L Winchester' },
|
||||||
|
RM80 => { actual => 242606, allocate => 243712, capacity => 119, description => 'DEC RM80' },
|
||||||
|
RB80 => { actual => 242606, allocate => 243712, capacity => 119, description => 'DEC R80 on 730 IDC' },
|
||||||
|
ESE20 => { actual => 245757, allocate => 245760, capacity => 120, description => 'DEC ESE20 Electronic' },
|
||||||
|
CDC9730 => { actual => 263360, allocate => 264192, capacity => 129, description => 'CDC 9730' },
|
||||||
|
FUJ160 => { actual => 263360, allocate => 264192, capacity => 129, description => 'Fujitsu 160' },
|
||||||
|
RF30 => { actual => 293040, allocate => 294912, capacity => 144, description => 'DEC RF30 Winchester' },
|
||||||
|
RD54 => { actual => 311200, allocate => 311296, capacity => 152, description => 'DEC RD54 Winchester' },
|
||||||
|
RP06 => { actual => 340670, allocate => 342016, capacity => 167, description => 'DEC RP06' },
|
||||||
|
RA60 => { actual => 400176, allocate => 401408, capacity => 196, description => 'DEC RA60 Removable' },
|
||||||
|
RZ24 => { actual => 409792, allocate => 411648, capacity => 201, description => 'DEC RZ24 Winchester' },
|
||||||
|
AMP9300 => { actual => 495520, allocate => 495616, capacity => 242, description => 'Ampex 9300' },
|
||||||
|
CDC9766 => { actual => 500384, allocate => 501760, capacity => 245, description => 'CDC 9766' },
|
||||||
|
RM05 => { actual => 500384, allocate => 501760, capacity => 245, description => 'DEC RM05' },
|
||||||
|
AMP330 => { actual => 524288, allocate => 524288, capacity => 256, description => 'Ampex Capricorn' },
|
||||||
|
RA70 => { actual => 547041, allocate => 548864, capacity => 268, description => 'DEC RA70 Winchester' },
|
||||||
|
RZ55 => { actual => 649040, allocate => 649216, capacity => 317, description => 'DEC RZ55 Winchester' },
|
||||||
|
RF31 => { actual => 744400, allocate => 745472, capacity => 364, description => 'DEC RF31 Winchester' },
|
||||||
|
RF71 => { actual => 781440, allocate => 782336, capacity => 382, description => 'DEC RF71 Winchester' },
|
||||||
|
EAGLE => { actual => 808320, allocate => 808960, capacity => 395, description => 'Fujitsu Eagle (48 sectors)' },
|
||||||
|
RZ25 => { actual => 832527, allocate => 833536, capacity => 407, description => 'DEC RZ25 Winchester' },
|
||||||
|
RA81 => { actual => 891072, allocate => 892928, capacity => 436, description => 'DEC RA81 Winchester' },
|
||||||
|
RP07 => { actual => 1008000, allocate => 1009664, capacity => 493, description => 'DEC RP07' },
|
||||||
|
CDC9775 => { actual => 1079040, allocate => 1079296, capacity => 527, description => 'CDC 9775' },
|
||||||
|
RA82 => { actual => 1216665, allocate => 1218560, capacity => 595, description => 'DEC RA82 Winchester' },
|
||||||
|
RZ56 => { actual => 1299174, allocate => 1300480, capacity => 635, description => 'DEC RZ56 Winchester' },
|
||||||
|
RZ80 => { actual => 1308930, allocate => 1310720, capacity => 640, description => 'Maxtor 8760 Winchester' },
|
||||||
|
RA71 => { actual => 1367310, allocate => 1368064, capacity => 668, description => 'DEC RA71 Winchester' },
|
||||||
|
RA72 => { actual => 1953300, allocate => 1953792, capacity => 954, description => 'DEC RA72 Winchester' },
|
||||||
|
RF72 => { actual => 1954050, allocate => 1955840, capacity => 955, description => 'DEC RF72 Winchester' },
|
||||||
|
RZ57 => { actual => 2025788, allocate => 2027520, capacity => 990, description => 'DEC RZ57 Winchester' },
|
||||||
|
M2266 => { actual => 2096256, allocate => 2097152, capacity => 1024, description => 'Fujitsu M2266' },
|
||||||
|
M2694 => { actual => 2117025, allocate => 2117632, capacity => 1034, description => 'Fujitsu M2694' },
|
||||||
|
RA90 => { actual => 2376153, allocate => 2377728, capacity => 1161, description => 'DEC RA90 Winchester' },
|
||||||
|
RZ58 => { actual => 2698061, allocate => 2699264, capacity => 1318, description => 'DEC RZ58 Winchester' },
|
||||||
|
RA92 => { actual => 2940951, allocate => 2942976, capacity => 1437, description => 'DEC RA92 Winchester' },
|
||||||
|
M2652 => { actual => 3409965, allocate => 3411968, capacity => 1666, description => 'Fujitsu M2652' },
|
||||||
|
RA73 => { actual => 3920490, allocate => 3921920, capacity => 1915, description => 'DEC RA73 Winchester' },
|
||||||
|
ST32171 => { actual => 4110000, allocate => 4110336, capacity => 2007, description => 'Seagate ST32171N' },
|
||||||
|
ST32550 => { actual => 4194995, allocate => 4196352, capacity => 2049, description => 'Seagate ST32550N' },
|
||||||
|
);
|
||||||
|
|
||||||
|
# defaults
|
||||||
|
$db{ByteCount} = undef;
|
||||||
|
$db{SectorCount} = undef;
|
||||||
|
$db{SectorSize} = 512;
|
||||||
|
$db{IDcode} = 0xDA;
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# initialize SDcard device structure
|
||||||
|
|
||||||
|
if (defined($DEVICE) && defined($PARTITIONS)) {
|
||||||
|
|
||||||
|
# setup for expect
|
||||||
|
my $prompt_cmd = qr/\nCommand \(m for help\): /;
|
||||||
|
my $timeout = 10;
|
||||||
|
|
||||||
|
# launch fdisk as an interactive subprocess
|
||||||
|
my $exp = Expect->spawn('/sbin/fdisk', $devfile) or die;
|
||||||
|
|
||||||
|
# enable debugging if set to 1
|
||||||
|
$exp->exp_internal(0);
|
||||||
|
|
||||||
|
# init MBR
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("o\n"); } ] );
|
||||||
|
|
||||||
|
# print disk info
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("p\n"); exp_continue; } ],
|
||||||
|
[ qr/\nDisk \S+: \S+ \S+, (\d+) bytes, (\d+) sectors/,
|
||||||
|
sub { $db{ByteCount} = ($exp->matchlist)[0];
|
||||||
|
$db{SectorCount} = ($exp->matchlist)[1];
|
||||||
|
$db{SectorSize} = int($db{ByteCount}/$db{SectorCount}); } ] );
|
||||||
|
|
||||||
|
# compute size of extra FAT partition as about 100MB; use rest for data partitions
|
||||||
|
my $use_size_mb = int($db{ByteCount}/1048576 - 100.5);
|
||||||
|
|
||||||
|
# create logical container partition 1
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("n\n"); exp_continue; } ],
|
||||||
|
[ qr/\nSelect.+: /, sub { $exp->send("e\n"); exp_continue; } ],
|
||||||
|
[ qr/\nPartition.+: /, sub { $exp->send("1\n"); exp_continue; } ],
|
||||||
|
[ qr/\nFirst sector.+: /, sub { $exp->send("\n"); exp_continue; } ],
|
||||||
|
[ qr/\nLast sector.+: /, sub { $exp->send("+".$use_size_mb."M\n"); } ] );
|
||||||
|
|
||||||
|
# create filesystem partition 2
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("n\n"); exp_continue; } ],
|
||||||
|
[ qr/\nSelect.+: /, sub { $exp->send("p\n"); exp_continue; } ],
|
||||||
|
[ qr/\nPartition.+: /, sub { $exp->send("2\n"); exp_continue; } ],
|
||||||
|
[ qr/\nFirst sector.+: /, sub { $exp->send("\n"); exp_continue; } ],
|
||||||
|
[ qr/\nLast sector.+: /, sub { $exp->send("\n"); } ] );
|
||||||
|
|
||||||
|
|
||||||
|
# change filesystem partition 2 to FAT32
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("t\n"); exp_continue; } ],
|
||||||
|
[ qr/\nPartition.+: /, sub { $exp->send("2\n"); exp_continue; } ],
|
||||||
|
[ qr/\nHex code.+: /, sub { $exp->send("0b\n"); } ] );
|
||||||
|
|
||||||
|
# create data partitions
|
||||||
|
foreach my $entry (split(/,/,uc($PARTITIONS))) {
|
||||||
|
|
||||||
|
# partition size; lookup from table, else just use it
|
||||||
|
my $size = exists $disktab{$entry} ? $disktab{$entry}{allocate} : $entry;
|
||||||
|
|
||||||
|
# created partition number
|
||||||
|
my $n = undef;
|
||||||
|
|
||||||
|
# create data partition N
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("n\n"); exp_continue; } ],
|
||||||
|
[ qr/\nSelect.+: /, sub { $exp->send("l\n"); exp_continue; } ],
|
||||||
|
[ qr/\nAdding logical partition (\d+)/,
|
||||||
|
sub { $n = ($exp->matchlist)[0]; exp_continue; } ],
|
||||||
|
[ qr/\nFirst sector.+: /, sub { $exp->send("\n"); exp_continue; } ],
|
||||||
|
[ qr/\nLast sector.+: /, sub { $exp->send("+".$size."\n"); } ] );
|
||||||
|
|
||||||
|
# change data partition N to raw data
|
||||||
|
if (defined($n)) {
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("t\n"); exp_continue; } ],
|
||||||
|
[ qr/\nPartition.+: /, sub { $exp->send($n."\n"); exp_continue; } ],
|
||||||
|
[ qr/\nHex code.+: /, sub { $exp->send(sprintf("%02x\n",$db{IDcode})); } ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
# exit loop if created last partition
|
||||||
|
last if $n >= 8;
|
||||||
|
|
||||||
|
} # foreach my $entry
|
||||||
|
|
||||||
|
# print partitions
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("p\n"); } ] );
|
||||||
|
|
||||||
|
# write and quit
|
||||||
|
$exp->expect($timeout,
|
||||||
|
[ $prompt_cmd, sub { $exp->send("w\n"); } ] );
|
||||||
|
|
||||||
|
# and done
|
||||||
|
$exp->soft_close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# gather data from existing SDcard device
|
||||||
|
|
||||||
|
if (defined($DEVICE)) {
|
||||||
|
|
||||||
|
# read the partition map and get the partitions of the selected type
|
||||||
|
if (open(my $fh, '-|', '/sbin/fdisk --list '.$devfile)) {
|
||||||
|
|
||||||
|
# scan all lines
|
||||||
|
while (my $line = scalar(<$fh>)) {
|
||||||
|
$line =~ s/[\015\012]+$//;
|
||||||
|
if ($line =~ m/^${devfile}(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)/i) {
|
||||||
|
# process partition definition lines
|
||||||
|
my ($id, $start, $end, $count, $size, $type) = ($1+0,$2+0,$3+0,$4+0,$5,hex($6));
|
||||||
|
if ($type == $db{IDcode} && $count == $end-$start+1) {
|
||||||
|
$slice{$id}{start} = $start;
|
||||||
|
$slice{$id}{end} = $end;
|
||||||
|
$slice{$id}{count} = $count;
|
||||||
|
}
|
||||||
|
} elsif ($line =~ m/^disk\s+${devfile}:\s+[0-9.]+\s+[a-z]+,\s+(\d+)\s+bytes,\s+(\d+)\s+sectors/i) {
|
||||||
|
# process line with total physical device byte and sector count
|
||||||
|
$db{ByteCount} = ($1+0);
|
||||||
|
$db{SectorCount} = ($2+0);
|
||||||
|
$db{SectorSize} = int($db{ByteCount}/$db{SectorCount});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close($fh);
|
||||||
|
|
||||||
|
} # if (open(my $fh ...
|
||||||
|
|
||||||
|
if ($DEBUG) {
|
||||||
|
printf STDERR "\n[ SectorSize = %d ]\n", $db{SectorSize};
|
||||||
|
printf STDERR "[ SectorCount = %d ]\n", $db{SectorCount};
|
||||||
|
printf STDERR "[ ByteCount = %d ]\n\n", $db{ByteCount};
|
||||||
|
printf STDERR "[ Device Sector Sector Sector ]\n";
|
||||||
|
printf STDERR "[ & Slice Start End Count ]\n";
|
||||||
|
foreach my $id (sort(keys(%slice))) {
|
||||||
|
printf STDERR "[ %-10s %10d %10d %10d ]\n", $devfile.$id,
|
||||||
|
$slice{$id}{start}, $slice{$id}{end}, $slice{$id}{count};
|
||||||
|
}
|
||||||
|
printf STDERR "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# write image file to partition
|
||||||
|
|
||||||
|
if (defined($DEVICE) && defined($WRITEFILE) && defined($SLICE)) {
|
||||||
|
|
||||||
|
# some parameters
|
||||||
|
my $blksize = $db{SectorSize};
|
||||||
|
my $bufsize = 2048*$blksize;
|
||||||
|
|
||||||
|
# configure partition start/length blocks
|
||||||
|
my $start = $slice{$SLICE}{start};
|
||||||
|
my $end = $slice{$SLICE}{end};
|
||||||
|
my $count = $slice{$SLICE}{count};
|
||||||
|
|
||||||
|
# check input exists
|
||||||
|
if (open(my $ifh, '<', $WRITEFILE)) {
|
||||||
|
# check output exists
|
||||||
|
if (open(my $ofh, '+<', $devfile)) {
|
||||||
|
# seek to output position
|
||||||
|
die unless sysseek($ofh, $start*$blksize, 0) == $start*$blksize;
|
||||||
|
# this many bytes per chunk
|
||||||
|
my $buffer = undef;
|
||||||
|
# read/write byte counts
|
||||||
|
my $rdtotal = 0;
|
||||||
|
my $wrtotal = 0;
|
||||||
|
# read/write byte positions
|
||||||
|
my $rdpos = sysseek($ifh, 0, 1);
|
||||||
|
my $wrpos = sysseek($ofh, 0, 1);
|
||||||
|
while ((my $rdsize = sysread($ifh, $buffer, $bufsize)) > 0) {
|
||||||
|
# read bytes
|
||||||
|
$rdtotal += $rdsize;
|
||||||
|
printf STDERR "[ write slice %d rd %12d at %12d ]\n", $SLICE, $rdsize, $rdpos if $DEBUG;
|
||||||
|
# check write bytes vs partition size; set partition size as maximum
|
||||||
|
if ($wrtotal+$rdsize > $count*$blksize) {
|
||||||
|
$rdsize = $count*$blksize - $wrtotal;
|
||||||
|
printf STDERR "Write overflow; truncating read to %d bytes\n", $rdsize;
|
||||||
|
}
|
||||||
|
# write bytes
|
||||||
|
my $wrsize = syswrite($ofh, $buffer, $rdsize);
|
||||||
|
$wrtotal += $wrsize;
|
||||||
|
printf STDERR "[ write slice %d wr %12d at %12d ]\n", $SLICE, $wrsize, $wrpos if $DEBUG;
|
||||||
|
# continue
|
||||||
|
$rdpos = sysseek($ifh, 0, 1);
|
||||||
|
$wrpos = sysseek($ofh, 0, 1);
|
||||||
|
} # while ((my $rdsize ...
|
||||||
|
# summary
|
||||||
|
printf STDERR "Write image file %s %d bytes to slice %d %d bytes\n",
|
||||||
|
$WRITEFILE, $rdtotal, $SLICE, $wrtotal if $VERBOSE;
|
||||||
|
close($ofh);
|
||||||
|
} # if (open(my $ofh ...
|
||||||
|
close($ifh);
|
||||||
|
} # if (open(my $ifh ...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# read partition to image file
|
||||||
|
|
||||||
|
if (defined($DEVICE) && defined($READFILE) && defined($SLICE)) {
|
||||||
|
|
||||||
|
# some parameters
|
||||||
|
my $blksize = $db{SectorSize};
|
||||||
|
my $bufsize = 2048*$blksize;
|
||||||
|
|
||||||
|
# configure partition start/length blocks
|
||||||
|
my $start = $slice{$SLICE}{start};
|
||||||
|
my $end = $slice{$SLICE}{end};
|
||||||
|
my $count = $slice{$SLICE}{count};
|
||||||
|
|
||||||
|
# check input exists
|
||||||
|
if (open(my $ifh, '+<', $devfile)) {
|
||||||
|
# create output file
|
||||||
|
if (open(my $ofh, '>', $READFILE)) {
|
||||||
|
# seek to input position
|
||||||
|
die unless sysseek($ifh, $start*$blksize, 0) == $start*$blksize;
|
||||||
|
# this many bytes per chunk
|
||||||
|
my $buffer = undef;
|
||||||
|
# read/write byte counts
|
||||||
|
my $rdtotal = 0;
|
||||||
|
my $wrtotal = 0;
|
||||||
|
# read/write byte positions
|
||||||
|
my $rdpos = sysseek($ifh, 0, 1);
|
||||||
|
my $wrpos = sysseek($ofh, 0, 1);
|
||||||
|
while ($rdtotal < $count*$blksize) {
|
||||||
|
# shrink buffer on last read if extends past partition
|
||||||
|
$bufsize = $count*$blksize - $rdtotal if $rdtotal+$bufsize > $count*$blksize;
|
||||||
|
# read bytes
|
||||||
|
my $rdsize = sysread($ifh, $buffer, $bufsize);
|
||||||
|
$rdtotal += $rdsize;
|
||||||
|
printf STDERR "[ read slice %d rd %12d at %12d ]\n", $SLICE, $rdsize, $rdpos if $DEBUG;
|
||||||
|
# write bytes
|
||||||
|
my $wrsize = syswrite($ofh, $buffer, $rdsize);
|
||||||
|
$wrtotal += $wrsize;
|
||||||
|
printf STDERR "[ read slice %d wr %12d at %12d ]\n", $SLICE, $wrsize, $wrpos if $DEBUG;
|
||||||
|
# continue
|
||||||
|
$rdpos = sysseek($ifh, 0, 1);
|
||||||
|
$wrpos = sysseek($ofh, 0, 1);
|
||||||
|
} # while ((my $rdsize ...
|
||||||
|
# summary
|
||||||
|
printf STDERR "Read slice %d %d bytes to image file %s %d bytes\n",
|
||||||
|
$SLICE, $rdtotal, $READFILE, $wrtotal if $VERBOSE;
|
||||||
|
close($ofh);
|
||||||
|
} # if (open(my $ofh ...
|
||||||
|
close($ifh);
|
||||||
|
} # if (open(my $ifh ...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# read partition to temp file and compare to named file
|
||||||
|
|
||||||
|
if (defined($DEVICE) && defined($COMPAREFILE) && defined($SLICE)) {
|
||||||
|
|
||||||
|
# some parameters
|
||||||
|
my $blksize = $db{SectorSize};
|
||||||
|
my $bufsize = 2048*$blksize;
|
||||||
|
|
||||||
|
# configure partition start/length blocks
|
||||||
|
my $start = $slice{$SLICE}{start};
|
||||||
|
my $end = $slice{$SLICE}{end};
|
||||||
|
my $count = $slice{$SLICE}{count};
|
||||||
|
|
||||||
|
# locals
|
||||||
|
my $tmpfile = sprintf("img2sdcard_%s%d_%d.tmp", $DEVICE, $SLICE, $$);
|
||||||
|
|
||||||
|
# check input exists
|
||||||
|
if (open(my $ifh, '+<', $devfile)) {
|
||||||
|
# create output file
|
||||||
|
if (open(my $ofh, '>', $tmpfile)) {
|
||||||
|
# seek to input position
|
||||||
|
die unless sysseek($ifh, $start*$blksize, 0) == $start*$blksize;
|
||||||
|
# this many bytes per chunk
|
||||||
|
my $buffer = undef;
|
||||||
|
# read/write byte counts
|
||||||
|
my $rdtotal = 0;
|
||||||
|
my $wrtotal = 0;
|
||||||
|
# read/write byte positions
|
||||||
|
my $rdpos = sysseek($ifh, 0, 1);
|
||||||
|
my $wrpos = sysseek($ofh, 0, 1);
|
||||||
|
while ($rdtotal < $count*$blksize) {
|
||||||
|
# shrink buffer on last read if extends past partition
|
||||||
|
$bufsize = $count*$blksize - $rdtotal if $rdtotal+$bufsize > $count*$blksize;
|
||||||
|
# read bytes
|
||||||
|
my $rdsize = sysread($ifh, $buffer, $bufsize);
|
||||||
|
$rdtotal += $rdsize;
|
||||||
|
printf STDERR "[ read slice %d rd %12d at %12d ]\n", $SLICE, $rdsize, $rdpos if $DEBUG;
|
||||||
|
# write bytes
|
||||||
|
my $wrsize = syswrite($ofh, $buffer, $rdsize);
|
||||||
|
$wrtotal += $wrsize;
|
||||||
|
printf STDERR "[ read slice %d wr %12d at %12d ]\n", $SLICE, $wrsize, $wrpos if $DEBUG;
|
||||||
|
# continue
|
||||||
|
$rdpos = sysseek($ifh, 0, 1);
|
||||||
|
$wrpos = sysseek($ofh, 0, 1);
|
||||||
|
} # while ((my $rdsize ...
|
||||||
|
close($ofh);
|
||||||
|
} # if (open(my $ofh ...
|
||||||
|
close($ifh);
|
||||||
|
} # if (open(my $ifh ...
|
||||||
|
|
||||||
|
# now do the compare
|
||||||
|
if (-r $tmpfile && -r $COMPAREFILE) {
|
||||||
|
# compare only length of compare file
|
||||||
|
my $len = (stat($COMPAREFILE))[7];
|
||||||
|
# do the compare, print result
|
||||||
|
my $sts = system('/usr/bin/cmp', '-b', '-n '.$len, $tmpfile, $COMPAREFILE);
|
||||||
|
printf STDERR "Compare slice %d %d bytes to image file %s %d bytes; status is '%s'\n",
|
||||||
|
$SLICE, $len, $COMPAREFILE, $len, $sts == 0 ? 'files match' : 'FILES DIFFER';
|
||||||
|
# delete tmp file if no error and not debug
|
||||||
|
unlink($tmpfile) if -e $tmpfile && $sts == 0 && !$DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# write an XML description file if requested and device exists
|
||||||
|
|
||||||
|
if (defined($DEVICE) && defined($XMLFILE)) {
|
||||||
|
|
||||||
|
if (open(my $fh, '>', $XMLFILE)) {
|
||||||
|
|
||||||
|
# BoardConfig
|
||||||
|
my %bc = ( unitAttention => 'true',
|
||||||
|
enableDisconnect => 'true',
|
||||||
|
parity => 'true',
|
||||||
|
enableScsi2 => 'false',
|
||||||
|
disableGlitchFilter => 'false',
|
||||||
|
enableCache => 'false',
|
||||||
|
selLatch => 'false',
|
||||||
|
mapLunsToIds => 'false',
|
||||||
|
selectionDelay => '255',
|
||||||
|
startupDelay => '0',
|
||||||
|
);
|
||||||
|
|
||||||
|
# SCSITarget per unit
|
||||||
|
my %st = ( enabled => 'false', # overwritten
|
||||||
|
sdSectorStart => '0', # overwritten
|
||||||
|
scsiSectors => '311200', # overwritten
|
||||||
|
deviceType => '0x0',
|
||||||
|
deviceTypeModifier => '0x0',
|
||||||
|
bytesPerSector => '512',
|
||||||
|
sectorsPerTrack => '63',
|
||||||
|
headsPerCylinder => '255',
|
||||||
|
vendor => 'SCSItoSD',
|
||||||
|
revision => '4.71',
|
||||||
|
prodId => sprintf("%-16s", 'RA81'), # overwritten
|
||||||
|
serial => sprintf("%-16d", 12345), # overwritten
|
||||||
|
modePages => '',
|
||||||
|
quirks => '',
|
||||||
|
vpd => '',
|
||||||
|
);
|
||||||
|
|
||||||
|
# XML header
|
||||||
|
printf $fh "<SCSI2SD>\n";
|
||||||
|
|
||||||
|
# board configuration
|
||||||
|
printf $fh " <BoardConfig>\n";
|
||||||
|
foreach my $key (sort(keys(%bc))) {
|
||||||
|
printf $fh " <%s>%s</%s>\n", $key, $bc{$key}, $key;
|
||||||
|
}
|
||||||
|
printf $fh " </BoardConfig>\n";
|
||||||
|
|
||||||
|
# list of defined units and corresponding scsi id
|
||||||
|
my @list = sort({$a <=> $b}keys(%slice));
|
||||||
|
my @scsi = defined($SCSI) ? (split(/,/,$SCSI)) : (0..$#list);
|
||||||
|
|
||||||
|
# exactly four mapped units in SCSItoSD
|
||||||
|
foreach my $unit (0..3) {
|
||||||
|
# get unit number from list
|
||||||
|
my $id = $list[$unit];
|
||||||
|
# check if less than all units defined
|
||||||
|
if (defined($id)) {
|
||||||
|
# configure partition start/length
|
||||||
|
$st{sdSectorStart} = $slice{$id}{start};
|
||||||
|
$st{scsiSectors} = $slice{$id}{count};
|
||||||
|
$st{enabled} = 'true';
|
||||||
|
$st{serial} = sprintf("%-16d", 1000+$unit);
|
||||||
|
# search type database for next same or larger entry
|
||||||
|
my @types = sort({$disktab{$a}{allocate}<=>$disktab{$b}{allocate}}keys(%disktab));
|
||||||
|
foreach my $type (@types) {
|
||||||
|
$st{prodId} = sprintf("%-16s", $type);
|
||||||
|
last if $disktab{$type}{allocate} >= $st{scsiSectors};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# undefined unit
|
||||||
|
$st{enabled} = 'false';
|
||||||
|
}
|
||||||
|
# print per unit configuration
|
||||||
|
printf $fh " <SCSITarget id=\"%d\">\n", $scsi[$unit];
|
||||||
|
foreach my $key (sort(keys(%st))) {
|
||||||
|
printf $fh " <%s>%s</%s>\n", $key, $st{$key}, $key;
|
||||||
|
}
|
||||||
|
printf $fh " </SCSITarget>\n";
|
||||||
|
} # foreach my $unit ...
|
||||||
|
|
||||||
|
# XML trailer
|
||||||
|
printf $fh "</SCSI2SD>\n";
|
||||||
|
|
||||||
|
# all done
|
||||||
|
close($fh);
|
||||||
|
} # if (open(my $fh ...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
exit;
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# the end
|
||||||
46
macro8x/Makefile
Normal file
46
macro8x/Makefile
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# makefile for pdp8 support routines
|
||||||
|
|
||||||
|
# system dependencies
|
||||||
|
ifeq ($(WINDIR),)
|
||||||
|
# unix
|
||||||
|
BINDIR=../../../tools/bin
|
||||||
|
EXE=
|
||||||
|
else
|
||||||
|
# cygwin
|
||||||
|
BINDIR=../../../tools/exe
|
||||||
|
EXE=.exe
|
||||||
|
endif
|
||||||
|
|
||||||
|
# omit frame pointer option needed for 25% speed improvment
|
||||||
|
OPTFLGS=-fno-strength-reduce -fomit-frame-pointer
|
||||||
|
|
||||||
|
# select compiler
|
||||||
|
CC=gcc
|
||||||
|
# cflags when making optimized version
|
||||||
|
CFLAGS=-O3 -Wall $(OPTFLGS)
|
||||||
|
# cflags when making debugging version
|
||||||
|
##CFLAGS=-g
|
||||||
|
|
||||||
|
# linker flags
|
||||||
|
LFLAGS=-lm
|
||||||
|
|
||||||
|
# system libs
|
||||||
|
LIBS=
|
||||||
|
|
||||||
|
|
||||||
|
# all the bins
|
||||||
|
BIN=macro8x$(EXE)
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BIN)
|
||||||
|
|
||||||
|
install:
|
||||||
|
cp $(BIN) $(BINDIR)
|
||||||
|
|
||||||
|
# make the macro8x binary
|
||||||
|
macro8x$(EXE): macro8x.c
|
||||||
|
$(CC) $(CFLAGS) $(LFLAGS) $(LIBS) -o $@ $<
|
||||||
|
|
||||||
|
# the end
|
||||||
4432
macro8x/macro8x.c
Normal file
4432
macro8x/macro8x.c
Normal file
File diff suppressed because it is too large
Load Diff
46
palbart/Makefile
Normal file
46
palbart/Makefile
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# makefile for pdp8 support routines
|
||||||
|
|
||||||
|
# system dependencies
|
||||||
|
ifeq ($(WINDIR),)
|
||||||
|
# unix
|
||||||
|
BINDIR=../../../tools/bin
|
||||||
|
EXE=
|
||||||
|
else
|
||||||
|
# cygwin
|
||||||
|
BINDIR=../../../tools/exe
|
||||||
|
EXE=.exe
|
||||||
|
endif
|
||||||
|
|
||||||
|
# omit frame pointer option needed for 25% speed improvment
|
||||||
|
OPTFLGS=-fno-strength-reduce -fomit-frame-pointer
|
||||||
|
|
||||||
|
# select compiler
|
||||||
|
CC=gcc
|
||||||
|
# cflags when making optimized version
|
||||||
|
CFLAGS=-O3 -Wall $(OPTFLGS)
|
||||||
|
# cflags when making debugging version
|
||||||
|
##CFLAGS=-g
|
||||||
|
|
||||||
|
# linker flags
|
||||||
|
LFLAGS=-lm
|
||||||
|
|
||||||
|
# system libs
|
||||||
|
LIBS=
|
||||||
|
|
||||||
|
|
||||||
|
# all the bins
|
||||||
|
BIN=palbart$(EXE)
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BIN)
|
||||||
|
|
||||||
|
install:
|
||||||
|
cp $(BIN) $(BINDIR)
|
||||||
|
|
||||||
|
# make the palbart binary
|
||||||
|
palbart$(EXE): palbart.c
|
||||||
|
$(CC) $(CFLAGS) $(LFLAGS) $(LIBS) -o $@ $<
|
||||||
|
|
||||||
|
# the end
|
||||||
220
palbart/palbart.1
Normal file
220
palbart/palbart.1
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.\" First parameter, NAME, should be all caps
|
||||||
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
|
.TH PALBART 1 "June 23, 2013"
|
||||||
|
.\" Please adjust this date whenever revising the manpage.
|
||||||
|
.\"
|
||||||
|
.\" Some roff macros, for reference:
|
||||||
|
.\" .nh disable hyphenation
|
||||||
|
.\" .hy enable hyphenation
|
||||||
|
.\" .ad l left justify
|
||||||
|
.\" .ad b justify to both left and right margins
|
||||||
|
.\" .nf disable filling
|
||||||
|
.\" .fi enable filling
|
||||||
|
.\" .br insert line break
|
||||||
|
.\" .sp <n> insert n+1 empty lines
|
||||||
|
.\" for manpage-specific macros, see man(7)
|
||||||
|
.SH NAME
|
||||||
|
palbart \- BART enhanced PDP8 crossassembler
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B palbart
|
||||||
|
.RI [options] inputfile
|
||||||
|
.br
|
||||||
|
.SH DESCRIPTION
|
||||||
|
This manual page documents briefly the
|
||||||
|
.B palbart
|
||||||
|
command.
|
||||||
|
It is a cross-assembler to for PDP/8 assembly language programs.
|
||||||
|
It will produce an output file in bin format, rim format, and using the
|
||||||
|
appropriate pseudo-ops, a combination of rim and bin formats.
|
||||||
|
A listing file is always produced and with an optional symbol table
|
||||||
|
and/or a symbol cross-reference (concordance). The permanent symbol
|
||||||
|
table can be output in a form that may be read back in so a customized
|
||||||
|
permanent symbol table can be produced. Any detected errors are output
|
||||||
|
to a separate file giving the filename in which they were detected
|
||||||
|
along with the line number, column number and error message as well as
|
||||||
|
marking the error in the listing file.
|
||||||
|
.PP
|
||||||
|
The following file name extensions are used:
|
||||||
|
.PP
|
||||||
|
.pal source code (input)
|
||||||
|
.PP
|
||||||
|
.lst assembly listing (output)
|
||||||
|
.PP
|
||||||
|
.bin assembly output in DEC's bin format (output)
|
||||||
|
.PP
|
||||||
|
.rim assembly output in DEC's rim format (output)
|
||||||
|
.PP
|
||||||
|
.err assembly errors detected (if any) (output)
|
||||||
|
.PP
|
||||||
|
.prm permanent symbol table in form suitable for reading after the EXPUNGE pseudo-op.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH OPTIONS
|
||||||
|
A summary of options is included below.
|
||||||
|
.TP
|
||||||
|
.B \-$
|
||||||
|
Don't require a $ at end of file
|
||||||
|
.TP
|
||||||
|
.B \-a
|
||||||
|
Enable additional features not compatible with PAL8.
|
||||||
|
.TP
|
||||||
|
.B \-d
|
||||||
|
Show symbol table at end of assembly
|
||||||
|
.TP
|
||||||
|
.B \-e
|
||||||
|
Generate error if link generated
|
||||||
|
.TP
|
||||||
|
.B \-h
|
||||||
|
Display help
|
||||||
|
.TP
|
||||||
|
.B \-l
|
||||||
|
Allow generation of links and literals (default)
|
||||||
|
.TP
|
||||||
|
.B \-n
|
||||||
|
Don't allow redefinition of permanent symbols
|
||||||
|
.TP
|
||||||
|
.B \-p
|
||||||
|
Generate a file with the permanent symbols in it.
|
||||||
|
(To get the current symbol table, assemble a file than has only
|
||||||
|
a $ in it.)
|
||||||
|
.TP
|
||||||
|
.B \-r
|
||||||
|
Produce output in rim format (default is bin format)
|
||||||
|
.TP
|
||||||
|
.B \-t N
|
||||||
|
Set tab stops to N
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
Display version information
|
||||||
|
.TP
|
||||||
|
.B \-x
|
||||||
|
Generate a cross-reference (concordance) of user symbols
|
||||||
|
|
||||||
|
.SH ADDITIONAL FEATURES
|
||||||
|
The additional features flag enables functions that are not compatible
|
||||||
|
with the PAL8 assemble. Currently only the TITLE and BANK pseudo operations
|
||||||
|
are enabled with this function. There are likely other incompatabilities
|
||||||
|
that are not under this flag.
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
Assembler error diagnostics are output to an error file and inserted
|
||||||
|
in the listing file. Each line in the error file has the form
|
||||||
|
.PP
|
||||||
|
<filename>(<line>:<col>) : error: <message> at Loc = <loc>
|
||||||
|
.PP
|
||||||
|
An example error message is:
|
||||||
|
.br
|
||||||
|
bintst.pal(17:9) : error: undefined symbol "UNDEF" at Loc = 07616
|
||||||
|
.PP
|
||||||
|
The error diagnostics put in the listing start with a two character
|
||||||
|
error code (if appropriate) and a short message. A carat '^' is
|
||||||
|
placed under the item in error if appropriate.
|
||||||
|
An example error message is:
|
||||||
|
.PP
|
||||||
|
17 07616 3000 DCA UNDEF
|
||||||
|
.br
|
||||||
|
UD undefined ^
|
||||||
|
.br
|
||||||
|
18 07617 1777 TAD I DUMMY
|
||||||
|
.PP
|
||||||
|
When an indirect is generated, an at character '@' is placed after the
|
||||||
|
the instruction value in the listing as an indicator as follows:
|
||||||
|
.PP
|
||||||
|
14 03716 1777@ TAD OFFPAG
|
||||||
|
.PP
|
||||||
|
Undefined symbols are marked in the symbol table listing by prepending
|
||||||
|
a '?' to the symbol. Redefined symbols are marked in the symbol table
|
||||||
|
listing by prepending a '#' to the symbol. Examples are:
|
||||||
|
.PP
|
||||||
|
#REDEF 04567
|
||||||
|
.br
|
||||||
|
SWITCH 07612
|
||||||
|
.br
|
||||||
|
?UNDEF 00000
|
||||||
|
.PP
|
||||||
|
Refer to the code for the diagnostic messages generated.
|
||||||
|
|
||||||
|
.SH BUGS
|
||||||
|
Only a minimal effort has been made to keep the listing format
|
||||||
|
anything like the PAL-8 listing format.
|
||||||
|
.PP
|
||||||
|
The RIMPUNch and BINPUNch pseudo-ops do not change the binary output
|
||||||
|
file type that was specified on startup. This was intentional and
|
||||||
|
and allows rim formatted data to be output prior to the actual binary
|
||||||
|
formatted data. On UN*X style systems, the same effect can be achieved
|
||||||
|
using the "cat" command, but on DOS/Windows systems, doing this was
|
||||||
|
a major chore.
|
||||||
|
.PP
|
||||||
|
The floating point input does not generate values exactly as the DEC
|
||||||
|
compiler does. I worked out several examples by hand and believe that
|
||||||
|
this implementation is slightly more accurate. If I am mistaken,
|
||||||
|
let me know and, if possible, a better method of generating the values.
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH HISTORICAL NOTE
|
||||||
|
This assembler was written to support the fleet of PDP-8 systems
|
||||||
|
used by the Bay Area Rapid Transit System. As of early 1997,
|
||||||
|
this includes about 40 PDP-8/E systems driving the train destination
|
||||||
|
signs in passenger stations.
|
||||||
|
|
||||||
|
.SH REFERENCES
|
||||||
|
This assembler is based on the pal assembler by:
|
||||||
|
.br
|
||||||
|
Douglas Jones <jones@cs.uiowa.edu> and
|
||||||
|
.br
|
||||||
|
Rich Coon <coon@convexw.convex.com>
|
||||||
|
|
||||||
|
.SH DISCLAIMER
|
||||||
|
See the symbol table for the set of pseudo-ops supported.
|
||||||
|
.PP
|
||||||
|
See the code for pseudo-ops that are not standard for PDP/8 assembly.
|
||||||
|
.PP
|
||||||
|
Refer to DEC's "Programming Languages (for the PDP/8)" for complete
|
||||||
|
documentation of pseudo-ops.
|
||||||
|
.PP
|
||||||
|
Refer to DEC's "Introduction to Programming (for the PDP/8)" or a
|
||||||
|
lower level introduction to the assembly language.
|
||||||
|
|
||||||
|
.SH WARRANTY
|
||||||
|
If you don't like it the way it works or if it doesn't work, that's
|
||||||
|
tough. You're welcome to fix it yourself. That's what you get for
|
||||||
|
using free software.
|
||||||
|
|
||||||
|
.SH COPYRIGHT NOTICE
|
||||||
|
This is free software. There is no fee for using it. You may make
|
||||||
|
any changes that you wish and also give it away. If you can make
|
||||||
|
a commercial product out of it, fine, but do not put any limits on
|
||||||
|
the purchaser's right to do the same. If you improve it or fix any
|
||||||
|
bugs, it would be nice if you told me and offered me a copy of the
|
||||||
|
new version.
|
||||||
|
Gary Messenbrink <gam@rahul.net>
|
||||||
|
|
||||||
|
.SH VERSIONS
|
||||||
|
Version Date by Comments
|
||||||
|
.br
|
||||||
|
v1.0 12Apr96 GAM Original
|
||||||
|
.br
|
||||||
|
v1.1 18Nov96 GAM Permanent symbol table initialization error.
|
||||||
|
.br
|
||||||
|
v1.2 20Nov96 GAM Added BINPUNch and RIMPUNch pseudo-operators.
|
||||||
|
.br
|
||||||
|
v1.3 24Nov96 GAM Added DUBL pseudo-op (24 bit integer constants).
|
||||||
|
.br
|
||||||
|
v1.4 29Nov96 GAM Fixed bug in checksum generation.
|
||||||
|
.br
|
||||||
|
v2.1 08Dec96 GAM Added concordance processing (cross reference).
|
||||||
|
.br
|
||||||
|
v2.2 10Dec96 GAM Added FLTG psuedo-op (floating point constants).
|
||||||
|
.br
|
||||||
|
v2.3 2Feb97 GAM Fixed paging problem in cross reference output.
|
||||||
|
.br
|
||||||
|
v2.4 11Apr97 GAM Fixed problem with some labels being put in cross reference multiple times.
|
||||||
|
.br
|
||||||
|
v2.9 23Jun13 DJG David Gesswein djg@pdp8online.com
|
||||||
|
Combined versions found online and fixed many bugs.
|
||||||
|
Used source from v2.5 03Nov07 RK and
|
||||||
|
v2.6 14Jul03 PNT.
|
||||||
|
.SH AUTHOR
|
||||||
|
This manual page was written by Vince Mulhollon <vlm@execpc.com>,
|
||||||
|
for the Debian GNU/Linux system (but may be used by others).
|
||||||
4352
palbart/palbart.c
Normal file
4352
palbart/palbart.c
Normal file
File diff suppressed because it is too large
Load Diff
218
rx02_image_dump/dumpdsk.pl
Normal file
218
rx02_image_dump/dumpdsk.pl
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
# Copyright (c) 2007 Don North
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# o Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# o Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# o Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
require 5.008;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
hdr - Standard template for a Perl module
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
hdr
|
||||||
|
S<[--help]>
|
||||||
|
S<[--debug]>
|
||||||
|
S<[--verbose]>
|
||||||
|
S<[random arguments ...]>
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Description of the command ...
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
The following options are available:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<--help>
|
||||||
|
|
||||||
|
Output this manpage and exit the program.
|
||||||
|
|
||||||
|
=item B<--debug>
|
||||||
|
|
||||||
|
Enable debug mode.
|
||||||
|
|
||||||
|
=item B<--verbose>
|
||||||
|
|
||||||
|
Verbose status reporting (not implemented).
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 ERRORS
|
||||||
|
|
||||||
|
The following diagnostic error messages can be produced on STDERR.
|
||||||
|
The meaning should be fairly self explanatory.
|
||||||
|
|
||||||
|
C<List all the error messages here...> -- some error
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
Some examples of common usage:
|
||||||
|
|
||||||
|
hdr --help
|
||||||
|
|
||||||
|
hdr --verbose --string 'a string' --integer 5 some_other_argument
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
Related commands cross reference...
|
||||||
|
|
||||||
|
=head1 NOTES
|
||||||
|
|
||||||
|
Caveat emptor...
|
||||||
|
|
||||||
|
=head1 FILES
|
||||||
|
|
||||||
|
Any standard files used?
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Don North
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
Modification history:
|
||||||
|
|
||||||
|
2005-05-05 v0.0 donorth - Initial version.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external standard modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, $ENV{PERL5LIB}) if defined($ENV{PERL5LIB}); # cygwin bugfix
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v0.1'; # version of code
|
||||||
|
my $ONWIN = $^O eq 'MSWin32'; # true if running under WinPerl
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to 1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help" => \$HELP,
|
||||||
|
"debug" => \$DEBUG,
|
||||||
|
"verbose" => \$VERBOSE,
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# say hello
|
||||||
|
printf STDERR "dumpdsk.pl %s by Don North (perl %g)\n", $VERSION, $] if $VERBOSE;
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR && scalar(@ARGV) == 1) {
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug enable debug mode
|
||||||
|
--verbose verbose status reporting
|
||||||
|
DSKFILE binary .dsk file image
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# read blocks from the disk image file
|
||||||
|
|
||||||
|
foreach my $file (@ARGV) {
|
||||||
|
|
||||||
|
if (open(DSK, "< $file")) {
|
||||||
|
|
||||||
|
my $SECperTRK = 26;
|
||||||
|
my $buf = undef;
|
||||||
|
my $cnt = -1;
|
||||||
|
my $blk = 0;
|
||||||
|
my $len = 128;
|
||||||
|
|
||||||
|
# read until EOF
|
||||||
|
while (!eof(DSK)) {
|
||||||
|
# read one block
|
||||||
|
$cnt = read(DSK, $buf, $len);
|
||||||
|
printf "ERROR: CNT<>LEN %d<>%d\n", $cnt, $len unless $cnt == $len;
|
||||||
|
# print it out
|
||||||
|
my $sec = ($blk % $SECperTRK)+1;
|
||||||
|
my $trk = int($blk / $SECperTRK);
|
||||||
|
printf "blk=%-4d trk=%-2d sec=%d\n", $blk,$trk,$sec;
|
||||||
|
my @buf = map {ord($_)} split(//,$buf);
|
||||||
|
my $i = 0;
|
||||||
|
while ($i < $cnt) {
|
||||||
|
printf " %02X", $buf[$i];
|
||||||
|
printf "\n" if $i % 16 == 15;
|
||||||
|
++$i;
|
||||||
|
}
|
||||||
|
printf "\n" unless $i % 16 == 15;
|
||||||
|
$blk++;
|
||||||
|
}
|
||||||
|
printf "Total of %d blocks read\n", $blk;
|
||||||
|
close(DSK);
|
||||||
|
} else {
|
||||||
|
die "Can't open file '$file'";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
exit;
|
||||||
|
|
||||||
|
# the end
|
||||||
36
rx02_image_dump/rx8e_image_dump.pl
Normal file
36
rx02_image_dump/rx8e_image_dump.pl
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
foreach my $file (@ARGV) {
|
||||||
|
|
||||||
|
if (open(INP, "< $file")) {
|
||||||
|
my $size = (stat($file))[7];
|
||||||
|
die unless $size == 76*26*128 || $size == 77*26*128;
|
||||||
|
my ($sector,$track,$byte) = (1,0,undef);
|
||||||
|
$track++ if $size == 76*26*128;
|
||||||
|
while (!eof(INP)) {
|
||||||
|
my $sts = read(INP,$byte,128);
|
||||||
|
my @byte = unpack('C128',$byte);
|
||||||
|
my @rest = splice(@byte,-32,32);
|
||||||
|
my @word = map {0xFFF&((($byte[3*($_>>1)+2]<<16)|($byte[3*($_>>1)+1]<<8)|($byte[3*($_>>1)+0]))>>(($_%2)*12))} (0..63);
|
||||||
|
printf "\n%3d %2d ", $track, $sector;
|
||||||
|
printf "%1s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[0..11]), join(' ',map {sprintf("%04o",$_)} @word[0..7]);
|
||||||
|
printf "%8s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[12..23]), join(' ',map {sprintf("%04o",$_)} @word[8..15]);
|
||||||
|
printf "%8s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[24..35]), join(' ',map {sprintf("%04o",$_)} @word[16..23]);
|
||||||
|
printf "%8s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[36..47]), join(' ',map {sprintf("%04o",$_)} @word[24..31]);
|
||||||
|
printf "%8s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[48..59]), join(' ',map {sprintf("%04o",$_)} @word[32..39]);
|
||||||
|
printf "%8s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[60..71]), join(' ',map {sprintf("%04o",$_)} @word[40..47]);
|
||||||
|
printf "%8s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[72..83]), join(' ',map {sprintf("%04o",$_)} @word[48..55]);
|
||||||
|
printf "%8s%s => %s\n", '', join(' ',map {sprintf("%02X",$_)} @byte[84..95]), join(' ',map {sprintf("%04o",$_)} @word[56..63]);
|
||||||
|
if (0) {
|
||||||
|
printf "%7s[%s]\n", '', join(' ',map {sprintf("%02X",$_)} @rest[0..15]);
|
||||||
|
printf "%7s[%s]\n", '', join(' ',map {sprintf("%02X",$_)} @rest[16..31]);
|
||||||
|
}
|
||||||
|
$track++ if $sector==26;
|
||||||
|
$sector = $sector==26 ? 1 : $sector+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(INP);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# the end
|
||||||
491
simhtape/simhtape.pl
Normal file
491
simhtape/simhtape.pl
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
#!/usr/local/bin/perl -w
|
||||||
|
|
||||||
|
# options
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# external standard modules
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Text;
|
||||||
|
use FindBin;
|
||||||
|
use FileHandle;
|
||||||
|
use File::Spec;
|
||||||
|
use File::Basename;
|
||||||
|
use File::Path qw( make_path );
|
||||||
|
|
||||||
|
# external local modules search path
|
||||||
|
BEGIN { unshift(@INC, $FindBin::Bin);
|
||||||
|
unshift(@INC, '.'); }
|
||||||
|
|
||||||
|
# external local modules
|
||||||
|
|
||||||
|
# generic defaults
|
||||||
|
my $VERSION = 'v1.0'; # version of code
|
||||||
|
my $HELP = 0; # set to 1 for man page output
|
||||||
|
my $DEBUG = 0; # set to >=1 for debug messages
|
||||||
|
my $VERBOSE = 0; # set to 1 for verbose messages
|
||||||
|
|
||||||
|
# specific defaults
|
||||||
|
my $TAPE = 'NONE'; # set to filename of .tap file
|
||||||
|
my $MODE = 'NONE'; # set to DUMP, EXTRACT, INSERT
|
||||||
|
my $PATH = '.'; # path to directory for EXTRACT of files
|
||||||
|
|
||||||
|
# process command line arguments
|
||||||
|
my $NOERROR = GetOptions( "help" => \$HELP,
|
||||||
|
"debug:1" => \$DEBUG,
|
||||||
|
"verbose" => \$VERBOSE,
|
||||||
|
"tape=s" => \$TAPE,
|
||||||
|
"path=s" => \$PATH,
|
||||||
|
"dump" => sub { $MODE = 'DUMP'; },
|
||||||
|
"extract:s" => sub { $MODE = 'EXTRACT'; $PATH = $_[1] if $_[1]; },
|
||||||
|
"insert" => sub { $MODE = 'INSERT'; },
|
||||||
|
);
|
||||||
|
|
||||||
|
# init
|
||||||
|
$VERBOSE = 1 if $DEBUG; # debug implies verbose messages
|
||||||
|
|
||||||
|
# output the documentation
|
||||||
|
if ($HELP) {
|
||||||
|
# output a man page if we can
|
||||||
|
if (ref(Pod::Text->can('new')) eq 'CODE') {
|
||||||
|
# try the new way if appears to exist
|
||||||
|
my $parser = Pod::Text->new(sentence=>0, width=>78);
|
||||||
|
printf STDOUT "\n"; $parser->parse_from_file($0);
|
||||||
|
} else {
|
||||||
|
# else must use the old way
|
||||||
|
printf STDOUT "\n"; Pod::Text::pod2text(-78, $0);
|
||||||
|
};
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for correct arguments present, print usage if errors
|
||||||
|
unless ($NOERROR
|
||||||
|
&& $TAPE ne 'NONE'
|
||||||
|
&& $MODE ne 'NONE'
|
||||||
|
) {
|
||||||
|
printf STDERR "%s %s (perl %g)\n", $0, $VERSION, $];
|
||||||
|
print STDERR "Usage: $0 [options...] arguments\n";
|
||||||
|
print STDERR <<"EOF";
|
||||||
|
--help output manpage and exit
|
||||||
|
--debug=N enable debug mode 'N'
|
||||||
|
--verbose verbose status reporting
|
||||||
|
--tape=FILENAME name of SIMH .tap file
|
||||||
|
--dump dump tape contents
|
||||||
|
--extract extract tape contents to files
|
||||||
|
--insert FILES... insert files to tape
|
||||||
|
--path PATH directory for file access [.]
|
||||||
|
EOF
|
||||||
|
# exit if errors...
|
||||||
|
die "Aborted due to command line errors.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
my @r50asc = split('', ' ABCDEFGHIJKLMNOPQRSTUVWXYZ$.?0123456789');
|
||||||
|
my %irad50 = map {$r50asc[$_],$_} (0..$#r50asc);
|
||||||
|
|
||||||
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
# process tape file
|
||||||
|
|
||||||
|
if ($MODE eq 'DUMP') {
|
||||||
|
&_dump_tape($TAPE);
|
||||||
|
} elsif ($MODE eq 'EXTRACT') {
|
||||||
|
&_read_tape($TAPE);
|
||||||
|
} elsif ($MODE eq 'INSERT') {
|
||||||
|
&_write_tape($TAPE, \@ARGV);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit;
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# dump a full tape
|
||||||
|
|
||||||
|
sub _dump_tape {
|
||||||
|
|
||||||
|
my ($tape) = @_;
|
||||||
|
|
||||||
|
printf STDERR "Dumping tape image file '%s' ...\n", $tape if $VERBOSE;
|
||||||
|
|
||||||
|
# init some stats
|
||||||
|
my $tapemark = 0;
|
||||||
|
my %bytecount = ();
|
||||||
|
my %reccount = ();
|
||||||
|
|
||||||
|
# input file descriptor
|
||||||
|
if (open(my $ifh, '<', $tape)) {
|
||||||
|
|
||||||
|
# some support code
|
||||||
|
sub _dump { my ($p,$s) = @_; join(',',map(sprintf("%02X",$_),unpack($p,$s))); }
|
||||||
|
|
||||||
|
# loop over whole tape image file
|
||||||
|
while (1) {
|
||||||
|
my ($pre,$buf,$suf) = (undef,undef,undef);
|
||||||
|
|
||||||
|
# read the 4B record length, little endian
|
||||||
|
my $prelen = &_read($ifh, 4, \$pre);
|
||||||
|
last if $prelen == -1 || $prelen == 0; # exit on EOF, no more data
|
||||||
|
my $preval = unpack('V', $pre);
|
||||||
|
printf STDERR "\n prefix: len=%d val=%d pre=[%s]\n",
|
||||||
|
$prelen, $preval, &_dump('C*',$pre) if $DEBUG >= 1;
|
||||||
|
|
||||||
|
# a value of zero is a tape mark
|
||||||
|
if ($prelen == 4 && $preval == 0) {
|
||||||
|
printf STDERR " *** TAPE MARK ***\n" if $VERBOSE;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# a value of -1 indicates EOF, as well as two sequential tapemarks
|
||||||
|
if ($tapemark == 2 || $prelen == 4 && $preval == 0xFFFFFFFF) {
|
||||||
|
printf STDERR " *** TAPE EOF ***\n" if $VERBOSE;
|
||||||
|
my $buflen = &_read($ifh, 1<<20, \$buf);
|
||||||
|
printf STDERR " extra: len=%d buf=[%s]\n",
|
||||||
|
$buflen, &_dump('C*',$buf) unless $buflen == 0;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# reset tapemark flag
|
||||||
|
$tapemark = 0;
|
||||||
|
|
||||||
|
# read next data record depending upon prefix length
|
||||||
|
my $buflen = &_read($ifh, $preval, \$buf);
|
||||||
|
if ($VERBOSE) {
|
||||||
|
printf STDERR " buffer: len=%d buf=[%s,...]\n",
|
||||||
|
$buflen, &_dump('C20',$buf) if $DEBUG == 2;
|
||||||
|
printf STDERR " buffer: len=%d buf=[%s]\n",
|
||||||
|
$buflen, &_dump('C*',$buf) if $DEBUG >= 3;
|
||||||
|
if ($buflen == 80) {
|
||||||
|
# will be an ANSI header record
|
||||||
|
printf STDERR " alabel: [%s]\n", $buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# count records and data bytes
|
||||||
|
$reccount{$buflen} += 1;
|
||||||
|
$bytecount{$buflen} += $buflen;
|
||||||
|
|
||||||
|
# SIMH format has a record trailer
|
||||||
|
my $suflen = &_read($ifh, 4, \$suf);
|
||||||
|
my $sufval = unpack('V', $suf);
|
||||||
|
printf STDERR " suffix: len=%d val=%d suf=[%s]\n",
|
||||||
|
$suflen, $sufval, &_dump('C*',$suf) if $DEBUG >= 1;
|
||||||
|
|
||||||
|
# check for valid format
|
||||||
|
next if $prelen == 4 && $suflen == 4 && $preval == $sufval && $preval == $buflen;
|
||||||
|
|
||||||
|
# nope, something is unexpected
|
||||||
|
printf STDERR " format error: prelen=%d suflen=%d preval=%d sufval=%d buflen=%d\n",
|
||||||
|
$prelen, $suflen, $preval, $sufval, $buflen;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# we be done
|
||||||
|
close($ifh);
|
||||||
|
}
|
||||||
|
|
||||||
|
# overall counts
|
||||||
|
printf STDERR "\nDone\n" if $VERBOSE;
|
||||||
|
foreach my $i (sort({$a<=>$b}keys(%reccount))) {
|
||||||
|
printf STDERR "Saw %d records of length %d bytes; total %d bytes\n",
|
||||||
|
$reccount{$i},$i,$bytecount{$i} if $VERBOSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# read a full tape
|
||||||
|
|
||||||
|
sub _read_tape {
|
||||||
|
|
||||||
|
my ($tape) = @_;
|
||||||
|
|
||||||
|
printf STDERR "Reading tape image file '%s' ...\n", $tape if $VERBOSE;
|
||||||
|
|
||||||
|
# init some stats
|
||||||
|
my $tapemark = 0;
|
||||||
|
my $vollabel = '';
|
||||||
|
my $filename = '';
|
||||||
|
my $filedate = '';
|
||||||
|
my $ofh = undef;
|
||||||
|
|
||||||
|
# input file descriptor
|
||||||
|
if (open(my $ifh, '<', $tape)) {
|
||||||
|
|
||||||
|
# loop over whole tape image file
|
||||||
|
while (1) {
|
||||||
|
my ($pre,$buf,$suf) = (undef,undef,undef);
|
||||||
|
|
||||||
|
# read the 4B record length, little endian
|
||||||
|
my $prelen = &_read($ifh, 4, \$pre);
|
||||||
|
last if $prelen == -1 || $prelen == 0; # exit on EOF, no more data
|
||||||
|
my $preval = unpack('V', $pre);
|
||||||
|
|
||||||
|
# a value of zero is a tape mark
|
||||||
|
next if $prelen == 4 && $preval == 0;
|
||||||
|
|
||||||
|
# a value of -1 indicates EOF, as well as two sequential tapemarks
|
||||||
|
last if $tapemark == 2 || $prelen == 4 && $preval == 0xFFFFFFFF;
|
||||||
|
|
||||||
|
# reset tapemark flag
|
||||||
|
$tapemark = 0;
|
||||||
|
|
||||||
|
# read next data record depending upon prefix length
|
||||||
|
my $buflen = &_read($ifh, $preval, \$buf);
|
||||||
|
|
||||||
|
# process header vs data vs trailer
|
||||||
|
if ($buflen == 80 && substr($buf, 0, 4) eq 'HDR1') {
|
||||||
|
# HDR1 has filename
|
||||||
|
$filename = &trim(substr($buf, 4, 17));
|
||||||
|
$filedate = substr($buf, 42, 5);
|
||||||
|
printf STDERR "Extracting file '%s' (%s)\n", $filename, $filedate if $VERBOSE;
|
||||||
|
printf STDERR "%s file=%s date=%s close\n", substr($buf,0,4), $filename, $filedate if $DEBUG;
|
||||||
|
make_path($PATH);
|
||||||
|
open($ofh, '>', File::Spec->catfile($PATH, $filename)) || die;
|
||||||
|
} elsif ($buflen == 80 && substr($buf, 0, 4) eq 'HDR2') {
|
||||||
|
# HDR2 info we don't use
|
||||||
|
} elsif ($buflen == 80 && substr($buf, 0, 4) eq 'EOF1') {
|
||||||
|
# EOF1 info we don;t use except to close file
|
||||||
|
printf STDERR "%s file=%s close\n", substr($buf,0,4), $filename if $DEBUG;
|
||||||
|
close($ofh);
|
||||||
|
} elsif ($buflen == 80 && substr($buf, 0, 4) eq 'EOF2') {
|
||||||
|
# EOF2 info we don't use
|
||||||
|
} elsif ($buflen == 80 && substr($buf, 0, 4) eq 'VOL1') {
|
||||||
|
# VOL1 has volume label
|
||||||
|
$vollabel = substr($buf, 4, 6);
|
||||||
|
} else {
|
||||||
|
# prune trailing zero bytes in record
|
||||||
|
my $skplen = 0;
|
||||||
|
while (ord(substr($buf,$buflen-$skplen-1,1)) == 0 && $skplen < $buflen) { ++$skplen; }
|
||||||
|
my $wrote = &_write($ofh, $buflen-$skplen, \$buf);
|
||||||
|
printf STDERR "DATA %d (%d)\n", $wrote, -$skplen if $DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
# SIMH format has a record trailer
|
||||||
|
my $suflen = &_read($ifh, 4, \$suf);
|
||||||
|
my $sufval = unpack('V', $suf);
|
||||||
|
|
||||||
|
# check for valid format
|
||||||
|
next if $prelen == 4 && $suflen == 4 && $preval == $sufval && $preval == $buflen;
|
||||||
|
|
||||||
|
# nope, something is unexpected
|
||||||
|
printf STDERR " format error: prelen=%d suflen=%d preval=%d sufval=%d buflen=%d\n",
|
||||||
|
$prelen, $suflen, $preval, $sufval, $buflen;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# we be done
|
||||||
|
close($ifh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# write a full tape
|
||||||
|
|
||||||
|
sub _write_tape {
|
||||||
|
|
||||||
|
my ($tape,$files) = @_;
|
||||||
|
|
||||||
|
printf STDERR "Writing tape image file '%s' ...\n", $tape if $VERBOSE;
|
||||||
|
|
||||||
|
# local state
|
||||||
|
my $vollab = 'RSTS';
|
||||||
|
my $blksiz = 512;
|
||||||
|
my $wrote = 0;
|
||||||
|
my $buf = undef;
|
||||||
|
my $hdr = pack('V', 80);
|
||||||
|
my $dat = pack('V', $blksiz);
|
||||||
|
|
||||||
|
# output file descriptor
|
||||||
|
if (open(my $ofh, '>', $tape)) {
|
||||||
|
|
||||||
|
# write volume label
|
||||||
|
$buf = sprintf("%-4s%-6s%-1s%-26s%-14s%-28s%-1s",
|
||||||
|
'VOL1', $vollab, '', '', 'D%B44310100101', '', '3');
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
|
||||||
|
# locals
|
||||||
|
my $filenumb = 0;
|
||||||
|
|
||||||
|
# loop over all files
|
||||||
|
foreach my $fullname (@$files) {
|
||||||
|
|
||||||
|
printf STDERR "Copy file '%s' ...\n", $fullname if $VERBOSE;
|
||||||
|
|
||||||
|
# locals
|
||||||
|
my $blocks = 0; # count blocks written
|
||||||
|
|
||||||
|
# open data file for reading
|
||||||
|
if (open(my $ifh, '<', File::Spec->catfile($fullname))) {
|
||||||
|
|
||||||
|
# strip any leading path from name, make uppercase
|
||||||
|
my $filename = uc((File::Spec->splitpath($fullname))[-1]);
|
||||||
|
my $filedate = 99050;
|
||||||
|
|
||||||
|
# write header1 label
|
||||||
|
$buf = sprintf("%-4s%-17s%-6s%04d%04d%04d%02d %05d %05d%1s%06d%-13s%-7s",
|
||||||
|
'HDR1', $filename, $vollab, 1, ++$filenumb, 1, 0, $filedate, $filedate, '', 0, 'DECRSTS/E', '');
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
|
||||||
|
# write header2 label
|
||||||
|
$buf = sprintf("%-4s%1s%05d%05d%21s%1s%13s%02d%28s",
|
||||||
|
'HDR2', 'U', $blksiz, 0, '', 'M', '', 0, '');
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
|
||||||
|
# write a record mark
|
||||||
|
$buf = pack('V', 0);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
|
||||||
|
# copy all the data, blocked to 512 byte records
|
||||||
|
while ((my $count = &_read($ifh, $blksiz, \$buf)) > 0) {
|
||||||
|
# write a data block
|
||||||
|
$wrote = &_write($ofh, length($dat), \$dat);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
if ($count < $blksiz) {
|
||||||
|
# pad out short blocks to blocksize
|
||||||
|
$buf = pack(sprintf("x[%d]",$blksiz-$count));
|
||||||
|
$wrote += &_write($ofh, length($buf), \$buf);
|
||||||
|
}
|
||||||
|
$wrote = &_write($ofh, length($dat), \$dat);
|
||||||
|
# count blocks
|
||||||
|
++$blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
# write a record mark
|
||||||
|
$buf = pack('V', 0);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
|
||||||
|
# write trailer1 label
|
||||||
|
$buf = sprintf("%-4s%-17s%-6s%04d%04d%04d%02d %05d %05d%1s%06d%-13s%-7s",
|
||||||
|
'EOF1', $filename, $vollab, 1, $filenumb, 1, 0, $filedate, $filedate, '', $blocks, 'DECRSTS/E', '');
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
|
||||||
|
# write trailer2 label
|
||||||
|
$buf = sprintf("%-4s%1s%05d%05d%21s%1s%13s%02d%28s",
|
||||||
|
'EOF2', 'U', $blksiz, 0, '', 'M', '', 0, '');
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
$wrote = &_write($ofh, length($hdr), \$hdr);
|
||||||
|
|
||||||
|
# write a record mark
|
||||||
|
$buf = pack('V', 0);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
|
||||||
|
close($ifh);
|
||||||
|
}
|
||||||
|
|
||||||
|
} # foreach my $filename
|
||||||
|
|
||||||
|
# write an end of media as two record marks
|
||||||
|
$buf = pack('V', 0);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
$wrote = &_write($ofh, length($buf), \$buf);
|
||||||
|
|
||||||
|
# we be done
|
||||||
|
close($ofh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# read LENGTH bytes from FH to BUFFER
|
||||||
|
|
||||||
|
sub _read {
|
||||||
|
|
||||||
|
my ($fh, $length, $buffer) = @_;
|
||||||
|
|
||||||
|
my $offset = 0;
|
||||||
|
$$buffer = '';
|
||||||
|
while ($length > 0) {
|
||||||
|
my $count = sysread($fh, $$buffer, $length, $offset);
|
||||||
|
return -1 unless defined($count);
|
||||||
|
return length($$buffer) if $count == 0;
|
||||||
|
$length -= $count;
|
||||||
|
$offset += $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length($$buffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# write LENGTH bytes from BUFFER to FH
|
||||||
|
|
||||||
|
sub _write {
|
||||||
|
|
||||||
|
my ($fh, $length, $buffer) = @_;
|
||||||
|
|
||||||
|
my $offset = 0;
|
||||||
|
while ($length > 0) {
|
||||||
|
my $count = syswrite($fh, $$buffer, $length, $offset);
|
||||||
|
return -1 unless defined($count);
|
||||||
|
$length -= $count;
|
||||||
|
$offset += $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $offset;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# rad50 decoder
|
||||||
|
|
||||||
|
sub rad50dec {
|
||||||
|
my $str = '';
|
||||||
|
foreach my $word (@_) {
|
||||||
|
my $trip = '';
|
||||||
|
foreach my $n (1..3) {
|
||||||
|
my $char = $word % 40;
|
||||||
|
$word = ($word - $char) / 40;
|
||||||
|
$trip = $r50asc[$char] . $trip;
|
||||||
|
}
|
||||||
|
$str .= $trip;
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
# rad50 encoder
|
||||||
|
|
||||||
|
sub rad50enc {
|
||||||
|
my ($str) = join('',@_);
|
||||||
|
$str .= ' ' x (3 - length($str) % 3) if length($str) % 3;
|
||||||
|
my @out = ();
|
||||||
|
while (length($str)) {
|
||||||
|
my $word = 0;
|
||||||
|
foreach my $char (split('', substr($str,0,3,''))) {
|
||||||
|
$word *= 40;
|
||||||
|
$word += exists($irad50{$char}) ? $irad50{$char} : $irad50{'?'};
|
||||||
|
}
|
||||||
|
push @out, $word;
|
||||||
|
}
|
||||||
|
return pack 'n*', @out;
|
||||||
|
}
|
||||||
|
|
||||||
|
# space trim
|
||||||
|
|
||||||
|
sub trim {
|
||||||
|
my ($str) = join('',@_);
|
||||||
|
$str =~ s/\s+$//g;
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# the end
|
||||||
Loading…
x
Reference in New Issue
Block a user