From a685d341c52c27c04d8af1e6ddc80e76f7a175d3 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sun, 21 Feb 2016 21:13:50 +0100 Subject: [PATCH 001/174] First changes in 0.5wip: correct some grammar (it's vs. its). --- CHANGES | 3 +++ TODO | 1 + assemble_aux.c | 4 ++-- assemble_globals.c | 2 +- assemble_globals.h | 2 +- macro11.h | 4 ++-- macros.c | 2 +- mlb.c | 2 +- object.c | 2 +- rept_irpc.c | 2 +- symbols.c | 2 +- 11 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 1f24aed..e66dc9c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +??.??.201?: Rhialto + version 0.5: + 09.11.2015: Rhialto version 0.4: - Fixed various bugs. The most notable was extensive use- diff --git a/TODO b/TODO index 9cf9f53..9a514ec 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ + .packed pdf page 80 listing format errors: ignore whitespace of input diff --git a/assemble_aux.c b/assemble_aux.c index a5b7180..c6dbfbc 100644 --- a/assemble_aux.c +++ b/assemble_aux.c @@ -553,7 +553,7 @@ int eval_undefined( } /* push_cond - a new conditional (.IF) block has been activated. Push - it's context. */ + its context. */ void push_cond( int ok, @@ -731,7 +731,7 @@ void write_globals( if (ident) gsd_ident(&gsd, ident); - /* write out each PSECT with it's global stuff */ + /* write out each PSECT with its global stuff */ /* Sections must be written out in the order that they appear in the assembly file. */ for (isect = 0; isect < sector; isect++) { diff --git a/assemble_globals.c b/assemble_globals.c index 40742b3..c4ad063 100644 --- a/assemble_globals.c +++ b/assemble_globals.c @@ -59,7 +59,7 @@ EX_TREE *xfer_address = NULL; /* The transfer address */ SYMBOL *current_pc; /* The current program counter */ unsigned last_dot_addr; /* Last coded PC... */ -SECTION *last_dot_section; /* ...and it's program section */ +SECTION *last_dot_section; /* ...and its program section */ /* The following are dummy psects for symbols which have meaning to the assembler: */ diff --git a/assemble_globals.h b/assemble_globals.h index ea5ff01..5054d38 100644 --- a/assemble_globals.h +++ b/assemble_globals.h @@ -67,7 +67,7 @@ extern EX_TREE *xfer_address; /* The transfer address */ extern SYMBOL *current_pc; /* The current program counter */ extern unsigned last_dot_addr; /* Last coded PC... */ -extern SECTION *last_dot_section; /* ...and it's program section */ +extern SECTION *last_dot_section; /* ...and its program section */ /* The following are dummy psects for symbols which have meaning to the assembler: */ diff --git a/macro11.h b/macro11.h index d8cc5ba..043547a 100644 --- a/macro11.h +++ b/macro11.h @@ -3,12 +3,12 @@ #include "git-info.h" -#define BASE_VERSION "0.4" +#define BASE_VERSION "0.5wip" #if defined(GIT_VERSION) #define VERSIONSTR BASE_VERSION" ("GIT_VERSION"\n\t"GIT_AUTHOR_DATE")" #else -#define VERSIONSTR BASE_VERSION" (21 June 2015)" +#define VERSIONSTR BASE_VERSION" (xx xxxx 2016)" /*#define VERSIONSTR "0.3 (April 21, 2009)" */ /*#define VERSIONSTR "0.2 July 15, 2001" */ #endif diff --git a/macros.c b/macros.c index c1f4490..5dbc810 100644 --- a/macros.c +++ b/macros.c @@ -591,7 +591,7 @@ MACRO *new_macro( return mac; } -/* free a macro, it's args, it's text, etc. */ +/* free a macro, its args, its text, etc. */ void free_macro( MACRO *mac) { diff --git a/mlb.c b/mlb.c index 8ec62c3..b5c7d8b 100644 --- a/mlb.c +++ b/mlb.c @@ -278,7 +278,7 @@ BUFFER *mlb_entry( return buf; } -/* mlb_extract - walk thru a macro library and store it's contents +/* mlb_extract - walk thru a macro library and store its contents into files in the current directory. See, I had decided not to bother writing macro library maintenance diff --git a/object.c b/object.c index 997cf26..061117c 100644 --- a/object.c +++ b/object.c @@ -786,7 +786,7 @@ void text_complex_begin( } /* text_complex_fit checks if a complex expression will fit and - returns a pointer to it's location */ + returns a pointer to its location */ static char *text_complex_fit( TEXT_COMPLEX *tx, diff --git a/rept_irpc.c b/rept_irpc.c index 5ba5fb4..419b816 100644 --- a/rept_irpc.c +++ b/rept_irpc.c @@ -29,7 +29,7 @@ typedef struct rept_stream { /* rept_stream_gets gets a line from a repeat stream. At the end of each count, the coutdown is decreated and the stream is reset to - it's beginning. */ + its beginning. */ char *rept_stream_gets( STREAM *str) diff --git a/symbols.c b/symbols.c index 50d1c91..63693ca 100644 --- a/symbols.c +++ b/symbols.c @@ -97,7 +97,7 @@ void free_sym( free(sym); } -/* remove_sym removes a symbol from it's symbol table. */ +/* remove_sym removes a symbol from its symbol table. */ void remove_sym( SYMBOL *sym, From 8aeec20765b98a81e3140478fc4bd4d550cd7e7d Mon Sep 17 00:00:00 2001 From: Don North Date: Sun, 10 Jul 2016 19:36:50 -0700 Subject: [PATCH 002/174] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..d1d2ecd --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# obj2hex +PDP-11 object file translator / linker From 6e4fe4c66e6b2616b9292670bc44c00019a1546c Mon Sep 17 00:00:00 2001 From: Don North Date: Sun, 10 Jul 2016 19:38:33 -0700 Subject: [PATCH 003/174] Initial version --- README.md | 145 ++++++- obj2hex.pl | 1059 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1202 insertions(+), 2 deletions(-) create mode 100644 obj2hex.pl diff --git a/README.md b/README.md index d1d2ecd..b7fccbf 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,143 @@ -# obj2hex -PDP-11 object file translator / linker +tu58em is a ... + +If run with no options, it prints a usage screen: + +``` +obj2hex.pl v1.5 by Don North (perl 5.022) +Usage: ./obj2hex.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 + --objfile=OBJFILE macro11 object .obj file + --outfile=OUTFILE output .hex/.txt/.bin file +Aborted due to command line errors. +``` + +If run with the --help option it prints a longer manual page: + +``` +NAME + obj2hex.pl - Convert a Macro-11 program image to PROM/load format + +SYNOPSIS + obj2hex.pl [--help] [--debug] [--verbose] [--boot] [--console] [--binary] + [--ascii] [--bytes=N] [--nocrc] [--logfile=LOGFILE] --objfile=OBJFILE + --outfile=BINFILE + +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. + + --objfile=FILENAME + Input objject file in .obj format. + + --outfile=FILENAME + Output binary file in format selected by user option. + +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: + + obj2hex.pl --help + + obj2hex.pl --verbose --boot --in 23-751A9.obj --out 23-751A9.hex + + obj2hex.pl --verbose --binary --in memtest.obj --out memtest.bin + +AUTHOR + Don North - donorth + +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. +``` diff --git a/obj2hex.pl b/obj2hex.pl new file mode 100644 index 0000000..7ced521 --- /dev/null +++ b/obj2hex.pl @@ -0,0 +1,1059 @@ +#!/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 + +obj2hex.pl - Convert a Macro-11 program image to PROM/load format + +=head1 SYNOPSIS + +obj2hex.pl +S<[--help]> +S<[--debug]> +S<[--verbose]> +S<[--boot]> +S<[--console]> +S<[--binary]> +S<[--ascii]> +S<[--bytes=N]> +S<[--nocrc]> +S<[--logfile=LOGFILE]> +S<--objfile=OBJFILE> +S<--outfile=BINFILE> + +=head1 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. + +=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<--boot> + +Generate a hex PROM file image suitable for programming into +an M9312 boot prom (512x4 geometry, only low half used). + +=item B<--console> + +Generate a hex PROM file image suitable for programming into +an M9312 console/diagnostic prom (1024x4 geometry). + +=item B<--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). + +=item B<--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 B<--boot>, B<--console>, B<--binary>, or B<--ascii> +must be specified. + +=item B<--bytes=N> + +For hex format output files, output N bytes per line (default 16). + +=item B<--nocrc> + +For hex format output files, don't automatically stuff the computed +CRC-16 as the last word in the ROM. + +=item B<--logfile=FILENAME> + +Generate debug output into this file. + +=item B<--objfile=FILENAME> + +Input objject file in .obj format. + +=item B<--outfile=FILENAME> + +Output binary file in format selected by user option. + +=back + +=head1 ERRORS + +The following diagnostic error messages can be produced on STDERR. +The meaning should be fairly self explanatory. + +C -- bad option or missing file(s) + +C -- bad filename or unreadable file + +C -- valid record must start with 0x01 + +C -- second byte must be 0x00 + +C -- third byte is low byte of record length + +C -- fourth byte is high byte of record length + +C -- bytes five thru end-1 are data bytes + +C -- last byte is checksum + +C -- compare rcv'ed checksum vs exp'ed checksum + +=head1 EXAMPLES + +Some examples of common usage: + + obj2hex.pl --help + + obj2hex.pl --verbose --boot --in 23-751A9.obj --out 23-751A9.hex + + obj2hex.pl --verbose --binary --in memtest.obj --out memtest.bin + +=head1 AUTHOR + +Don North - donorth + +=head1 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. + +=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.5'; # 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 $bytesper = -1; # bytes per block in output file +my $nocrc = 0; # output CRC16 as last word unless set +my $objfile = 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'; }, + "ascii" => sub { $romtype = 'ASC9'; }, + "bytes=i" => \$bytesper, + "nocrc" => \$nocrc, + "objfile=s" => \$objfile, + "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($objfile) + && defined($outfile) + && $romtype ne 'NONE' + ) { + printf STDERR "obj2hex.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 + --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 + --objfile=OBJFILE macro11 object .obj file + --outfile=OUTFILE output .hex/.txt/.bin 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 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, 025=>1 ); # bytes 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 = ( ); # bytes 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 (must be a power of two) + $romfill = 0x00; # rom fill pattern + $rombase = 0165000; # base address of rom + +} elsif ($romtype eq 'BINA' || $romtype eq 'ASC9') { + + # program load image ... 56KB address space maximum + %excaddr = ( ); # bytes to be skipped in rom crc calc + $memsize = 7*8192; # 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 file records + +# real pdp11 memory data words in boot prom +my @mem = ((0) x $memsize); + +# min/max address limits in object file +my ($adrmin,$adrmax) = ('',''); + +# state variables in processing object records +my $rommsk = ($romsize-1)>>1; # address bit mask +my $adrmsk = 0xFFFF; # 16b addr mask +my $datmsk = 0xFFFF; # 16b data mask +my $memmsk = 0xFF; # 8b memory data mask + +# open the input .obj file, die if error +my $OBJ = FileHandle->new("< ".$objfile); +die "Error: can't open input object file '$objfile'\n" unless defined $OBJ; + +# databases +my %gblsym = (); +my %psect = (); +my @psect = (); +my %program = (); +my $psectname = '. ABS.'; +my $psectaddr = 0; +my $psectnumb = -1; +my $textaddr = 0; + +# program defaults +$program{START}{VALUE} = 1; +$program{START}{PSECT} = '. ABS.'; + +# now parse all the records +while (my @rec = &read_rec($OBJ)) { + + # type is first byte of record + my $key = $rec[0]; + + if ($key == 001) { # GSD + + # iterate over GSD subrecords + for (my $i = 2; $i < @rec; ) { + # GSD records are fixed 8B length all in the same format + my $nam = &rad2asc(($rec[$i+1]<<8)|($rec[$i+0]<<0), ($rec[$i+3]<<8)|($rec[$i+2]<<0)); + my $flg = $rec[$i+4]; + my $ent = $rec[$i+5]; + my $val = ($rec[$i+7]<<8)|($rec[$i+6]<<0); + my @ent = ('MODULE','CSECT','INTSYM','XFRADR','GBLSYM','PSECT','IDENT','VSECT'); + if ($ent == 3) { + # XFRADR + $program{START}{PSECT} = $nam; + $program{START}{VALUE} = $val; + } elsif ($ent == 4) { + # GBLSYM flags + $gblsym{$nam}{FLG}{$flg&(1<<0) ? "WEA" : "STR"}++; + $gblsym{$nam}{FLG}{$flg&(1<<3) ? "DEF" : "REF"}++; + $gblsym{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; + $gblsym{$nam}{PSECT} = $psectname; + $gblsym{$nam}{VALUE} = $val; + } elsif ($ent == 5) { + # PSECT flags + $psect[++$psectnumb] = $nam; + $psect{$nam}{NUMBER} = $psectnumb; + $psect{$nam}{FLG}{$flg&(1<<0) ? "GBL" : $flg&(1<<6) ? "GBL" : "LCL"}++; + $psect{$nam}{FLG}{$flg&(1<<2) ? "OVR" : "CAT"}++; + $psect{$nam}{FLG}{$flg&(1<<4) ? "R/O" : "R/W"}++; + $psect{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; + $psect{$nam}{FLG}{$flg&(1<<7) ? "D" : "I/D"}++; + if ($psect{$nam}{FLG}{CAT}) { + $psect{$nam}{LENGTH} = $val; + $psect{$nam}{START} = $psectaddr; + $psectname = $nam; + $psectaddr += $val; + } elsif ($psect{$nam}{FLG}{ABS}) { + $psect{$nam}{LENGTH} = $val; + $psect{$nam}{START} = 0; + $psectname = $nam; + } + } + if ($DEBUG) { + printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, $nam, $val; + printf $LOG " flags=%s", join(",", sort(keys(%{$gblsym{$nam}{FLG}}))) if $ent == 4; + printf $LOG " flags=%s", join(",", sort(keys(%{$psect{$nam}{FLG}}))) if $ent == 5; + printf $LOG "\n"; + } + $i += 8; + } + + } elsif ($key == 002) { # ENDGSD + + # just say we saw it + printf $LOG "..ENDGSD\n" if $DEBUG; + + $program{END}{ADDRESS} = 0; + foreach my $nam (sort(keys(%psect))) { + my $start = $psect{$nam}{START}; + my $length = $psect{$nam}{LENGTH}; + my $end = $length ? $start + $length - 1 : $start; + $program{END}{ADDRESS} = $end if $end > $program{END}{ADDRESS}; + printf $LOG "..PSECT[%d](%s) START=%06o END=%06o LENGTH=%06o\n", + $psect{$nam}{NUMBER}, $nam, $start, $end, $length if $length && $DEBUG; + } + $program{START}{ADDRESS} = $program{START}{VALUE} + $psect{$program{START}{PSECT}}{START}; + printf $LOG "..PROG(ADDRESS) START=%06o END=%06o\n", + $program{START}{ADDRESS}, $program{END}{ADDRESS} if $DEBUG; + + } elsif ($key == 003) { # TXT + + # process text record + my $off = ($rec[3]<<8)|($rec[2]<<0); + my $len = @rec-4; + my $base = $psect{$psectname}{START}; + my $adr = ($base + $off) & $adrmsk; + foreach my $i (1..$len) { $mem[$adr+$i-1] = $rec[4+$i-1]; } + if ($DEBUG) { + printf $LOG "..TXT OFFSET=%06o LENGTH=%o BASE=%06o PSECTNAME='%s'\n", $off, $len, $base, $psectname; + for (my $i = 0; $i < $len; $i += 2) { + printf $LOG " %06o: ", ($adr+$i)&~1 if $i%8 == 0; + printf $LOG " %03o...", $mem[$adr+$i++] if ($adr+$i)&1; + printf $LOG " %06o", ($mem[$adr+$i+1]<<8)|($mem[$adr+$i+0]<<0) if $i < $len-1; + printf $LOG " ...%03o", $mem[$adr+$i] if $i == $len-1; + printf $LOG "\n" if $i%8 >= 6 && $i < $len-2; + } + printf $LOG "\n"; + } + $adrmin = $adr if $adrmin eq '' || $adr < $adrmin; + $adrmax = $adr+$len-1 if $adrmax eq '' || $adr+$len-1 > $adrmax; + $textaddr = $adr; + + } elsif ($key == 004) { # RLD + + # iterate over RLD subrecords + for (my $i = 2; $i < @rec; ) { + # first byte is entry type and flags + my $ent = $rec[$i+0] & 0x7F; # entry type + my $flg = $rec[$i+0] & 0x80; # modification flag (0=word, 1=byte) + # process an entry + if ($ent == 001) { + # internal relocation ... OK + my $dis = $rec[$i+1]; + my $con = ($rec[$i+3]<<8)|($rec[$i+2]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$psectname}{START} + $con); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(IR): adr=%06o val=%06o ; dis=%06o con=%06o\n", + $adr, $val, $dis, $con if $DEBUG; + $i += 4; + } elsif ($ent == 002) { + # global relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + # process + printf $LOG "..RLD(GR): dis=%06o nam='%s'\n", + $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 003) { + # internal displaced ... OK + my $dis = $rec[$i+1]; + my $con = ($rec[$i+3]<<8)|($rec[$i+2]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($con - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(ID): adr=%06o val=%06o ; dis=%06o con=%06o\n", + $adr, $val, $dis, $con if $DEBUG; + $i += 4; + } elsif ($ent == 004) { + # global displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + # process + printf $LOG "..RLD(GDR): dis=%06o nam='%s'\n", + $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 005) { + # global additive relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); + # process + printf $LOG "..RLD(GAR): dis=%06o con=%06o nam='%s'\n", + $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 006) { + # global additive displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); + # process + printf $LOG "..RLD(GADR): dis=%06o con=%06o nam='%s'\n", + $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 007) { + # location counter definition ... OK + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); + # process + $psectname = $nam; + $textaddr = $datmsk & ($con); + printf $LOG "..RLD(LCD): adr=%06o ; dis=%06o con=%06o nam='%s'\n", + $textaddr, $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 010) { + # location counter modification ... OK + my $dis = $rec[$i+1]; + my $con = ($rec[$i+3]<<8)|($rec[$i+2]<<0); + # process + $textaddr = $datmsk & ($con); + printf $LOG "..RLD(LCM): adr=%06o ; dis=%06o con=%06o\n", + $textaddr, $dis, $con if $DEBUG; + $i += 4; + } elsif ($ent == 011) { + # program limits ... OK, mostly + my $dis = $rec[$i+1]; + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ( 01000 ); # make this up, no easy way to compute it + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(LIM1): adr=%06o val=%06o ; dis=%06o\n", + $adr, $val, $dis if $DEBUG; + $dis += 2; + $adr += 2; + $val = $datmsk & ($program{END}{ADDRESS}); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(LIM2): adr=%06o val=%06o ; dis=%06o\n", + $adr, $val, $dis if $DEBUG; + $i += 2; + } elsif ($ent == 012) { + # psect relocation ... OK + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START}); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", + $adr, $val, $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 014) { + # psect displaced relocation ... OK + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PDR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", + $adr, $val, $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 015) { + # psect additive relocation ... OK + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} + $con); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PAR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", + $adr, $val, $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 016) { + # psect additive displaced relocation ... OK + my $dis = $rec[$i+1]; + my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); + my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} + $con - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PADR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", + $adr, $val, $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 017) { + # complex relocation ... OK + my $dis = $rec[$i+1]; + my $nam = '. ABS.'; + my $con = 0; + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $loc = 0; + my $val = 0; + my $opc = ""; + my @stk = (); + my $dun = 0; + for ($i += 2; !$dun; $i += 1) { + if ($rec[$i] == 000) { + $opc = "NOP"; + } elsif ($rec[$i] == 001) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] + $arg[1]); + $opc = "ADD"; + } elsif ($rec[$i] == 002) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] - $arg[1]); + $opc = "SUB"; + } elsif ($rec[$i] == 003) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] * $arg[1]); + $opc = "MUL"; + } elsif ($rec[$i] == 004) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[1] == 0 ? 0 : int($arg[0] / $arg[1])); + $opc = "DIV"; + } elsif ($rec[$i] == 005) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] & $arg[1]); + $opc = "AND"; + } elsif ($rec[$i] == 006) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] | $arg[1]); + $opc = "IOR"; + } elsif ($rec[$i] == 007) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] ^ $arg[1]); + $opc = "XOR"; + } elsif ($rec[$i] == 010) { + my @arg = splice(@stk,-1,1); + push(@stk, -$arg[0]); + $opc = "NEG"; + } elsif ($rec[$i] == 011) { + my @arg = splice(@stk,-1,1); + push(@stk, ~$arg[0]); + $opc = "COM"; + } elsif ($rec[$i] == 012) { + my @arg = splice(@stk,-1,1); + $val = $arg[0]; + $opc = "STO"; + $dun = 1; + } elsif ($rec[$i] == 013) { + ############## may need tweaking ################ + my @arg = splice(@stk,-1,1); + $val = $arg[0]; + $opc = "STO+DIS"; + $dun = 1; + } elsif ($rec[$i] == 016) { + ############## may need tweaking ################ + $nam = &rad2asc(($rec[$i+2]<<8)|($rec[$i+1]<<0), + ($rec[$i+4]<<8)|($rec[$i+3]<<0)); + $con = $gblsym{$nam}{VALUE}; + push(@stk, $con); + $opc = sprintf("GLB[%s]=(%o)", &trim($nam), $con); + $i += 4; + } elsif ($rec[$i] == 017) { + $nam = $psect[$rec[$i+1]]; + $con = ($rec[$i+3]<<8) | ($rec[$i+2]<<0); + $loc = $psect{$nam}{START} + $con; + push(@stk, $loc); + $opc = sprintf("FET[%s+%o]=(%o)", &trim($nam), $con, $loc); + $i += 3; + } elsif ($rec[$i] == 020) { + $con = ($rec[$i+2]<<8) | ($rec[$i+1]<<0); + push(@stk, $con); + $opc = "CON"; + $i += 2; + } + $stk[-1] = $datmsk & $stk[-1] if @stk; + printf $LOG "....OPC=%-20s STK=(%s)\n", $opc, join(",",map(sprintf("%o",$_),@stk)) if $DEBUG; + } + printf $LOG "..RLD(CMPX): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; + } else { + die sprintf("Error: Unknown RLD entry 0%o (%d)", $ent, $ent); + } + } + + } elsif ($key == 005) { # ISD + + # ignore + printf $LOG "..ISD: ignored\n" if $DEBUG; + + } elsif ($key == 006) { # ENDMOD + + # just say we saw it + printf $LOG "..ENDMOD\n\n\n" if $DEBUG; + + } elsif ($key == 007) { # LIBHDR + + # ignore + printf $LOG "..LIBHDR: ignored\n" if $DEBUG; + + } elsif ($key == 010) { # LIBEND + + # ignore + printf $LOG "..LIBEND: ignored\n" if $DEBUG; + + } else { # unknown + + # invalid record type in the object file + die sprintf("Error: unknown record type 0%o (%d)", $key, $key); + + } + +} + +# done with object file +$OBJ->close; + +#---------------------------------------------------------------------------------------------------- + +# compute CRC if required, copy memory image to output buffer + +my @buf = ($romfill) x $romsize; # physical PROM data bytes, filled background pattern + +# only compute CRC on M9312 ROMs +if ($romtype eq 'BOOT' || $romtype eq 'DIAG') { + + # compute CRC-16 of the prom contents (except exception words) and store at last location + my $crctab = &crc(-name=>$crctype, -new=>1); + my $crc = &crc(-name=>$crctype, -init=>1); + for (my $adr = 0; $adr < $memsize-2; $adr += 1) { + next if exists($excaddr{$adr}); # skip these addresses + $mem[$rombase+$adr] = $memfill unless defined($mem[$rombase+$adr]); + $crc = &crc(-name=>$crctype, -table=>$crctab, -crc=>$crc, -byte=>$mem[$rombase+$adr]); + } + $crc = &crc(-name=>$crctype, -crc=>$crc, -last=>1); + unless ($nocrc) { + # output computed CRC-16 as last word in the ROM file + $mem[$rombase+$memsize-2] = ($crc>>0)&0xFF; + $mem[$rombase+$memsize-1] = ($crc>>8)&0xFF; + } + printf $LOG "ROM %s is %06o (0x%04X)\n", $crctype, ($crc) x 2 if $VERBOSE; + + # process data words to actual PROM byte data + # put 4bit nibble in low 4b of each 8b data byte, zero the upper 4b + # only copy the above instruction portion over + for (my $idx = 0; $idx < $memsize<<1; $idx += 4) { + my $dat = ($mem[$rombase+($idx>>1)+1]<<8) | ($mem[$rombase+($idx>>1)+0]<<0); + $buf[$idx+0] = ($dat&0xE)|(($dat>>8)&0x1); # bits 3 2 1 8 + $buf[$idx+1] = ($dat>>4)&0xF; # bits 7 6 5 4 + $buf[$idx+2] = ((($dat>>8)&0xE)|($dat&0x1))^0xC; # bits ~11 ~10 9 0 + $buf[$idx+3] = (($dat>>12)&0xF)^0x1; # bits 15 14 13 ~12 + } + +} elsif ($romtype eq 'BINA' || $romtype eq 'ASC9') { + + # only copy the above instruction portion over + for (my $adr = 0; $adr < $memsize; $adr += 1) { + $mem[$rombase+$adr] = $memfill unless defined($mem[$rombase+$adr]); + $buf[$adr] = $mem[$rombase+$adr]; + } + +} + +if ($VERBOSE) { + + # print checksum of entire device + my $chksum = 0; map($chksum += $_, @buf); + printf $LOG "ROM checksum is %06o (0x%04X)\n", $chksum, $chksum; + +} + +#---------------------------------------------------------------------------------------------------- + +# output the linked/processed binary file image in the desired format + +my $OUT = FileHandle->new("> ".$outfile); +die "Error: can't open output file '$outfile'\n" unless defined $OUT; + +if ($romtype eq 'BOOT' || $romtype eq 'DIAG') { + + # 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 $OUT ":%02X%04X%02X%s%02X\n", $cnt, $idx, 0x00, $dat, &chksum($cnt, $idx>>0, $idx>>8, 0x00, @dat); + } + + printf $OUT ":%02X%04X%02X%s%02X\n", 0x00, 0x0000, 0x01, '', &chksum(0x0, 0x0000>>0, 0x0000>>8, 0x01); + +} elsif ($romtype eq 'BINA') { + + # Loader 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 + # + # If the byte length is exactly six, the block is the last on the tape, and + # there is no checksum. If the origin is not 000001, then the origin is + # the PC at which to start the program. + + $bytesper = 128 if $bytesper <= 0; + + my $start = $program{START}{ADDRESS}; + + sub m ($) { $_[0] & 0xFF; } + + # output the entire PROM buffer as a binary loader file + for (my $idx = $adrmin; $idx < $adrmax+1; $idx += $bytesper) { + my $cnt = $idx+$bytesper <= $adrmax+1 ? $bytesper : $adrmax+1-$idx; # N bytes or whatever is left + my @dat = @buf[$idx..($idx+$cnt-1)]; # get the data + my $len = $cnt+6; + my @rec = (0x01, 0x00, &m($len>>0), &m($len>>8), &m($idx>>0), &m($idx>>8), @dat); + print $OUT pack("C*", @rec, &chksum(@rec)); + } + my @end = (0x01, 0x00, 0x06, 0x00, &m($start>>0), &m($start>>8)); + print $OUT pack("C*", @end, &chksum(@end)); + +} elsif ($romtype eq 'ASC9') { + + # ascii interface to M9312 console emulator + + sub n ($) { $_[0] & 0xFF; } + + # start program load here + printf $OUT "L %o\r\n", $adrmin; + + # output the PROM buffer as an ascii load file + for (my $idx = $adrmin; $idx < $adrmax+1; $idx += 2) { + printf $OUT "D %06o\r\n", (&n($buf[$idx+1])<<8) | &n($buf[$idx+0]); + } + + # start program exec here + printf $OUT "L %o\r\nS\r\n", $adrmin; + +} + +# all done +$OUT->close; + +#---------------------------------------------------------------------------------------------------- + +# really done +$LOG->close; +exit; + +#---------------------------------------------------------------------------------------------------- + +# 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 From 9ec5623662fb8d5fc58535e414c4c1b0bb47e9d2 Mon Sep 17 00:00:00 2001 From: Don North Date: Sun, 10 Jul 2016 19:41:57 -0700 Subject: [PATCH 004/174] Corrected header --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b7fccbf..ecd5e43 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -tu58em is a ... +obj2hex.pl 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: From b8a955792c0998a40d9374bc0123e230af7eacae Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 11 Jul 2016 22:10:15 +0200 Subject: [PATCH 005/174] Fix operand check for XOR which is shared with JSR. Fixes issue #1. --- assemble.c | 4 +- tests/test-jmp.lst.ok | 103 ++++++++++++++++++++++++++++-------------- tests/test-jmp.mac | 26 +++++++++++ 3 files changed, 96 insertions(+), 37 deletions(-) diff --git a/assemble.c b/assemble.c index a837551..e26c005 100644 --- a/assemble.c +++ b/assemble.c @@ -1468,7 +1468,7 @@ static int assemble( return 1; case OC_JSR: - /* First op is register, second is gen. */ { + /* For JSR and XOR, first op is register, second is gen. */ { ADDR_MODE mode; EX_TREE *value; unsigned reg; @@ -1496,7 +1496,7 @@ static int assemble( return 0; } - if ((mode.type & 070) == 0) { + if (op->value == I_JSR && (mode.type & 070) == 0) { report(stack->top, "JSR Rn,Rm is illegal\n"); /* But encode it anyway... */ } diff --git a/tests/test-jmp.lst.ok b/tests/test-jmp.lst.ok index eca2513..1ed2d78 100644 --- a/tests/test-jmp.lst.ok +++ b/tests/test-jmp.lst.ok @@ -3,47 +3,80 @@ 3 ; Tests the addressing modes for JMP. 4 ; JMP Rx is not allowed, all other modes are. 5 ; - 6 - 7 000000 000167 000104 start: jmp label ; rel(pc) jumps to label - 8 000004 000177 000100 jmp @label ; @rel(pc) does something else! - 9 000010 000127 000110' jmp #label ; (pc)+ does something else! - 10 000014 000137 000110' jmp @#label ; @(pc)+ jumps to label - 11 -test-jmp.mac:12: ***ERROR JMP Rn is illegal - 12 000020 000101 jmp r1 ; must fail - 13 000022 000112 jmp (r2) - 14 000024 000121 jmp (r1)+ - 15 000026 000131 jmp @(r1)+ - 16 000030 000141 jmp -(r1) - 17 000032 000151 jmp @-(r1) - 18 000034 000161 001234 jmp 1234(r1) - 19 000040 000171 001234 jmp @1234(r1) - 20 - 21 000044 004067 000040 secnd: jsr r0,label ; rel(pc) jumps to label - 22 000050 004077 000034 jsr r0,@label ; @rel(pc) does something else! - 23 000054 004027 000110' jsr r0,#label ; (pc)+ does something else! - 24 000060 004037 000110' jsr r0,@#label ; @(pc)+ jumps to label - 25 -test-jmp.mac:26: ***ERROR JSR Rn,Rm is illegal - 26 000064 004201 jsr r2,r1 ; must fail - 27 000066 004312 jsr r3,(r2) - 28 000070 004421 jsr r4,(r1)+ - 29 000072 004531 jsr r5,@(r1)+ - 30 000074 004241 jsr r2,-(r1) - 31 000076 004351 jsr r3,@-(r1) - 32 000100 004461 001234 jsr r4,1234(r1) - 33 000104 004571 001234 jsr r5,@1234(r1) - 34 - 35 000110 000207 label: rts pc - 35 + 6 ; XOR shares the instruction format with JSR + 7 ; (their source operand can only be a register), + 8 ; but XOR Rx,Ry is allowed whereas JSR Rx,Ry is not. + 9 ; + 10 + 11 000000 000167 000150 start: jmp label ; rel(pc) jumps to label + 12 000004 000177 000144 jmp @label ; @rel(pc) does something else! + 13 000010 000127 000154' jmp #label ; (pc)+ does something else! + 14 000014 000137 000154' jmp @#label ; @(pc)+ jumps to label + 15 +test-jmp.mac:16: ***ERROR JMP Rn is illegal + 16 000020 000101 jmp r1 ; must fail + 17 000022 000112 jmp (r2) + 18 000024 000121 jmp (r1)+ + 19 000026 000131 jmp @(r1)+ + 20 000030 000141 jmp -(r1) + 21 000032 000151 jmp @-(r1) + 22 000034 000161 001234 jmp 1234(r1) + 23 000040 000171 001234 jmp @1234(r1) + 24 + 25 000044 004067 000104 secnd: jsr r0,label ; rel(pc) jumps to label + 26 000050 004077 000100 jsr r0,@label ; @rel(pc) does something else! + 27 000054 004027 000154' jsr r0,#label ; (pc)+ does something else! + 28 000060 004037 000154' jsr r0,@#label ; @(pc)+ jumps to label + 29 +test-jmp.mac:30: ***ERROR JSR Rn,Rm is illegal + 30 000064 004201 jsr r2,r1 ; must fail + 31 000066 004312 jsr r3,(r2) + 32 000070 004421 jsr r4,(r1)+ + 33 000072 004531 jsr r5,@(r1)+ + 34 000074 004241 jsr r2,-(r1) + 35 000076 004351 jsr r3,@-(r1) + 36 000100 004461 001234 jsr r4,1234(r1) + 37 000104 004571 001234 jsr r5,@1234(r1) + 38 + 39 000110 074067 000040 third: xor r0,label ; rel(pc) + 40 000114 074077 000034 xor r0,@label ; @rel(pc) + 41 000120 074027 000154' xor r0,#label ; (pc)+ + 42 000124 074037 000154' xor r0,@#label ; @(pc)+ + 43 + 44 000130 074201 xor r2,r1 ; must succeed + 45 000132 074312 xor r3,(r2) ; must succeed + 46 000134 074421 xor r4,(r1)+ ; must succeed + 47 000136 074531 xor r5,@(r1)+ ; must succeed + 48 000140 074241 xor r2,-(r1) ; must succeed + 49 000142 074351 xor r3,@-(r1) ; must succeed + 50 000144 074461 001234 xor r4,1234(r1) ; must succeed + 51 000150 074571 001234 xor r5,@1234(r1) ; must succeed + 52 +test-jmp.mac:53: ***ERROR Illegal addressing mode + 53 xor (r2),r1 ; must fail +test-jmp.mac:54: ***ERROR Illegal addressing mode + 54 xor (r2)+,r1 ; must fail +test-jmp.mac:55: ***ERROR Illegal addressing mode + 55 xor @(r2)+,r1 ; must fail +test-jmp.mac:56: ***ERROR Illegal addressing mode + 56 xor -(r2),r1 ; must fail +test-jmp.mac:57: ***ERROR Illegal addressing mode + 57 xor @-(r2),r1 ; must fail +test-jmp.mac:58: ***ERROR Illegal addressing mode + 58 xor 1234(r2),r1 ; must fail +test-jmp.mac:59: ***ERROR Illegal addressing mode + 59 xor @1234(r2),r1 ; must fail + 60 + 61 000154 000207 label: rts pc + 61 Symbol table -. ******R 001 LABEL 000110R 001 SECND 000044R 001 START 000000R 001 +. ******R 001 LABEL 000154R 001 SECND 000044R 001 START 000000R 001 THIRD 000110R 001 Program sections: . ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) - 000112 001 (RW,I,LCL,REL,CON,NOSAV) + 000156 001 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/test-jmp.mac b/tests/test-jmp.mac index b578a90..ac57b55 100644 --- a/tests/test-jmp.mac +++ b/tests/test-jmp.mac @@ -3,6 +3,10 @@ ; Tests the addressing modes for JMP. ; JMP Rx is not allowed, all other modes are. ; +; XOR shares the instruction format with JSR +; (their source operand can only be a register), +; but XOR Rx,Ry is allowed whereas JSR Rx,Ry is not. +; start: jmp label ; rel(pc) jumps to label jmp @label ; @rel(pc) does something else! @@ -32,4 +36,26 @@ secnd: jsr r0,label ; rel(pc) jumps to label jsr r4,1234(r1) jsr r5,@1234(r1) +third: xor r0,label ; rel(pc) + xor r0,@label ; @rel(pc) + xor r0,#label ; (pc)+ + xor r0,@#label ; @(pc)+ + + xor r2,r1 ; must succeed + xor r3,(r2) ; must succeed + xor r4,(r1)+ ; must succeed + xor r5,@(r1)+ ; must succeed + xor r2,-(r1) ; must succeed + xor r3,@-(r1) ; must succeed + xor r4,1234(r1) ; must succeed + xor r5,@1234(r1) ; must succeed + + xor (r2),r1 ; must fail + xor (r2)+,r1 ; must fail + xor @(r2)+,r1 ; must fail + xor -(r2),r1 ; must fail + xor @-(r2),r1 ; must fail + xor 1234(r2),r1 ; must fail + xor @1234(r2),r1 ; must fail + label: rts pc From 2620a1e98fa9f79082e339aeca15406323c2e85e Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 11 Jul 2016 22:28:48 +0200 Subject: [PATCH 006/174] Add .gitignore file. --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f89ebd --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.d +*.o +tests/*.lst +tests/*.obj +tests/*.objd From 433e8ecda613e17f909c8ca5761b7e36a8c39c3a Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 22 Oct 2016 15:13:34 +0200 Subject: [PATCH 007/174] Add comment on a format strictness. ... Remove unneeded #define. --- assemble.c | 11 +++++++++++ extree.c | 2 -- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/assemble.c b/assemble.c index e26c005..b162147 100644 --- a/assemble.c +++ b/assemble.c @@ -766,6 +766,17 @@ static int assemble( free_tree(value); } else if (strcmp(label, "B") == 0 || strcmp(label, "NB") == 0) { + /* + * Page 6-46 footnote 1 says + * "A macro argument (a form of symbolic argument) + * is enclosed within angle brackets or delimited + * by the circumflex construction, as described in + * section 7.3. For example, + * + * ^/124/" + * but we don't enforce that here (yet) by using + * simply getstring(). + */ cp = skipwhite(cp); if (EOL(*cp)) { ok = 1; diff --git a/extree.c b/extree.c index 37970cc..57444a6 100644 --- a/extree.c +++ b/extree.c @@ -1,5 +1,3 @@ -#define EXTREE__C - #include #include #include From 872b33f183a123dc2b709016dd0693b8f7a1c9cc Mon Sep 17 00:00:00 2001 From: AK6DN Date: Wed, 5 Apr 2017 15:35:25 -0700 Subject: [PATCH 008/174] Restructure code in preparation for supporting multiple input .obj files and linking. --- README.md | 18 +- obj2hex.pl | 2134 ++++++++++++++++++++++++++-------------------------- 2 files changed, 1085 insertions(+), 1067 deletions(-) diff --git a/README.md b/README.md index ecd5e43..c2614b2 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Usage: ./obj2hex.pl [options...] arguments --bytes=N bytes per block on output --nocrc inhibit output of CRC-16 in hex format --logfile=LOGFILE logging message file - --objfile=OBJFILE macro11 object .obj file --outfile=OUTFILE output .hex/.txt/.bin file + OBJFILE... macro11 object .obj file(s) Aborted due to command line errors. ``` @@ -28,8 +28,8 @@ NAME SYNOPSIS obj2hex.pl [--help] [--debug] [--verbose] [--boot] [--console] [--binary] - [--ascii] [--bytes=N] [--nocrc] [--logfile=LOGFILE] --objfile=OBJFILE - --outfile=BINFILE + [--ascii] [--bytes=N] [--nocrc] [--logfile=LOGFILE] --outfile=BINFILE + OBJFILE... DESCRIPTION Converts a Macro-11 object file to various output formats, including M9312 @@ -86,12 +86,12 @@ OPTIONS --logfile=FILENAME Generate debug output into this file. - --objfile=FILENAME - Input objject file in .obj format. - --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. @@ -124,9 +124,9 @@ EXAMPLES obj2hex.pl --help - obj2hex.pl --verbose --boot --in 23-751A9.obj --out 23-751A9.hex + obj2hex.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj - obj2hex.pl --verbose --binary --in memtest.obj --out memtest.bin + obj2hex.pl --verbose --binary --out memtest.bin memtest.obj AUTHOR Don North - donorth @@ -140,4 +140,6 @@ HISTORY 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. ``` diff --git a/obj2hex.pl b/obj2hex.pl index 7ced521..b27a3fc 100644 --- a/obj2hex.pl +++ b/obj2hex.pl @@ -1,1059 +1,1075 @@ -#!/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 - -obj2hex.pl - Convert a Macro-11 program image to PROM/load format - -=head1 SYNOPSIS - -obj2hex.pl -S<[--help]> -S<[--debug]> -S<[--verbose]> -S<[--boot]> -S<[--console]> -S<[--binary]> -S<[--ascii]> -S<[--bytes=N]> -S<[--nocrc]> -S<[--logfile=LOGFILE]> -S<--objfile=OBJFILE> -S<--outfile=BINFILE> - -=head1 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. - -=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<--boot> - -Generate a hex PROM file image suitable for programming into -an M9312 boot prom (512x4 geometry, only low half used). - -=item B<--console> - -Generate a hex PROM file image suitable for programming into -an M9312 console/diagnostic prom (1024x4 geometry). - -=item B<--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). - -=item B<--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 B<--boot>, B<--console>, B<--binary>, or B<--ascii> -must be specified. - -=item B<--bytes=N> - -For hex format output files, output N bytes per line (default 16). - -=item B<--nocrc> - -For hex format output files, don't automatically stuff the computed -CRC-16 as the last word in the ROM. - -=item B<--logfile=FILENAME> - -Generate debug output into this file. - -=item B<--objfile=FILENAME> - -Input objject file in .obj format. - -=item B<--outfile=FILENAME> - -Output binary file in format selected by user option. - -=back - -=head1 ERRORS - -The following diagnostic error messages can be produced on STDERR. -The meaning should be fairly self explanatory. - -C -- bad option or missing file(s) - -C -- bad filename or unreadable file - -C -- valid record must start with 0x01 - -C -- second byte must be 0x00 - -C -- third byte is low byte of record length - -C -- fourth byte is high byte of record length - -C -- bytes five thru end-1 are data bytes - -C -- last byte is checksum - -C -- compare rcv'ed checksum vs exp'ed checksum - -=head1 EXAMPLES - -Some examples of common usage: - - obj2hex.pl --help - - obj2hex.pl --verbose --boot --in 23-751A9.obj --out 23-751A9.hex - - obj2hex.pl --verbose --binary --in memtest.obj --out memtest.bin - -=head1 AUTHOR - -Don North - donorth - -=head1 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. - -=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.5'; # 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 $bytesper = -1; # bytes per block in output file -my $nocrc = 0; # output CRC16 as last word unless set -my $objfile = 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'; }, - "ascii" => sub { $romtype = 'ASC9'; }, - "bytes=i" => \$bytesper, - "nocrc" => \$nocrc, - "objfile=s" => \$objfile, - "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($objfile) - && defined($outfile) - && $romtype ne 'NONE' - ) { - printf STDERR "obj2hex.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 - --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 - --objfile=OBJFILE macro11 object .obj file - --outfile=OUTFILE output .hex/.txt/.bin 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 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, 025=>1 ); # bytes 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 = ( ); # bytes 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 (must be a power of two) - $romfill = 0x00; # rom fill pattern - $rombase = 0165000; # base address of rom - -} elsif ($romtype eq 'BINA' || $romtype eq 'ASC9') { - - # program load image ... 56KB address space maximum - %excaddr = ( ); # bytes to be skipped in rom crc calc - $memsize = 7*8192; # 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 file records - -# real pdp11 memory data words in boot prom -my @mem = ((0) x $memsize); - -# min/max address limits in object file -my ($adrmin,$adrmax) = ('',''); - -# state variables in processing object records -my $rommsk = ($romsize-1)>>1; # address bit mask -my $adrmsk = 0xFFFF; # 16b addr mask -my $datmsk = 0xFFFF; # 16b data mask -my $memmsk = 0xFF; # 8b memory data mask - -# open the input .obj file, die if error -my $OBJ = FileHandle->new("< ".$objfile); -die "Error: can't open input object file '$objfile'\n" unless defined $OBJ; - -# databases -my %gblsym = (); -my %psect = (); -my @psect = (); -my %program = (); -my $psectname = '. ABS.'; -my $psectaddr = 0; -my $psectnumb = -1; -my $textaddr = 0; - -# program defaults -$program{START}{VALUE} = 1; -$program{START}{PSECT} = '. ABS.'; - -# now parse all the records -while (my @rec = &read_rec($OBJ)) { - - # type is first byte of record - my $key = $rec[0]; - - if ($key == 001) { # GSD - - # iterate over GSD subrecords - for (my $i = 2; $i < @rec; ) { - # GSD records are fixed 8B length all in the same format - my $nam = &rad2asc(($rec[$i+1]<<8)|($rec[$i+0]<<0), ($rec[$i+3]<<8)|($rec[$i+2]<<0)); - my $flg = $rec[$i+4]; - my $ent = $rec[$i+5]; - my $val = ($rec[$i+7]<<8)|($rec[$i+6]<<0); - my @ent = ('MODULE','CSECT','INTSYM','XFRADR','GBLSYM','PSECT','IDENT','VSECT'); - if ($ent == 3) { - # XFRADR - $program{START}{PSECT} = $nam; - $program{START}{VALUE} = $val; - } elsif ($ent == 4) { - # GBLSYM flags - $gblsym{$nam}{FLG}{$flg&(1<<0) ? "WEA" : "STR"}++; - $gblsym{$nam}{FLG}{$flg&(1<<3) ? "DEF" : "REF"}++; - $gblsym{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; - $gblsym{$nam}{PSECT} = $psectname; - $gblsym{$nam}{VALUE} = $val; - } elsif ($ent == 5) { - # PSECT flags - $psect[++$psectnumb] = $nam; - $psect{$nam}{NUMBER} = $psectnumb; - $psect{$nam}{FLG}{$flg&(1<<0) ? "GBL" : $flg&(1<<6) ? "GBL" : "LCL"}++; - $psect{$nam}{FLG}{$flg&(1<<2) ? "OVR" : "CAT"}++; - $psect{$nam}{FLG}{$flg&(1<<4) ? "R/O" : "R/W"}++; - $psect{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; - $psect{$nam}{FLG}{$flg&(1<<7) ? "D" : "I/D"}++; - if ($psect{$nam}{FLG}{CAT}) { - $psect{$nam}{LENGTH} = $val; - $psect{$nam}{START} = $psectaddr; - $psectname = $nam; - $psectaddr += $val; - } elsif ($psect{$nam}{FLG}{ABS}) { - $psect{$nam}{LENGTH} = $val; - $psect{$nam}{START} = 0; - $psectname = $nam; - } - } - if ($DEBUG) { - printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, $nam, $val; - printf $LOG " flags=%s", join(",", sort(keys(%{$gblsym{$nam}{FLG}}))) if $ent == 4; - printf $LOG " flags=%s", join(",", sort(keys(%{$psect{$nam}{FLG}}))) if $ent == 5; - printf $LOG "\n"; - } - $i += 8; - } - - } elsif ($key == 002) { # ENDGSD - - # just say we saw it - printf $LOG "..ENDGSD\n" if $DEBUG; - - $program{END}{ADDRESS} = 0; - foreach my $nam (sort(keys(%psect))) { - my $start = $psect{$nam}{START}; - my $length = $psect{$nam}{LENGTH}; - my $end = $length ? $start + $length - 1 : $start; - $program{END}{ADDRESS} = $end if $end > $program{END}{ADDRESS}; - printf $LOG "..PSECT[%d](%s) START=%06o END=%06o LENGTH=%06o\n", - $psect{$nam}{NUMBER}, $nam, $start, $end, $length if $length && $DEBUG; - } - $program{START}{ADDRESS} = $program{START}{VALUE} + $psect{$program{START}{PSECT}}{START}; - printf $LOG "..PROG(ADDRESS) START=%06o END=%06o\n", - $program{START}{ADDRESS}, $program{END}{ADDRESS} if $DEBUG; - - } elsif ($key == 003) { # TXT - - # process text record - my $off = ($rec[3]<<8)|($rec[2]<<0); - my $len = @rec-4; - my $base = $psect{$psectname}{START}; - my $adr = ($base + $off) & $adrmsk; - foreach my $i (1..$len) { $mem[$adr+$i-1] = $rec[4+$i-1]; } - if ($DEBUG) { - printf $LOG "..TXT OFFSET=%06o LENGTH=%o BASE=%06o PSECTNAME='%s'\n", $off, $len, $base, $psectname; - for (my $i = 0; $i < $len; $i += 2) { - printf $LOG " %06o: ", ($adr+$i)&~1 if $i%8 == 0; - printf $LOG " %03o...", $mem[$adr+$i++] if ($adr+$i)&1; - printf $LOG " %06o", ($mem[$adr+$i+1]<<8)|($mem[$adr+$i+0]<<0) if $i < $len-1; - printf $LOG " ...%03o", $mem[$adr+$i] if $i == $len-1; - printf $LOG "\n" if $i%8 >= 6 && $i < $len-2; - } - printf $LOG "\n"; - } - $adrmin = $adr if $adrmin eq '' || $adr < $adrmin; - $adrmax = $adr+$len-1 if $adrmax eq '' || $adr+$len-1 > $adrmax; - $textaddr = $adr; - - } elsif ($key == 004) { # RLD - - # iterate over RLD subrecords - for (my $i = 2; $i < @rec; ) { - # first byte is entry type and flags - my $ent = $rec[$i+0] & 0x7F; # entry type - my $flg = $rec[$i+0] & 0x80; # modification flag (0=word, 1=byte) - # process an entry - if ($ent == 001) { - # internal relocation ... OK - my $dis = $rec[$i+1]; - my $con = ($rec[$i+3]<<8)|($rec[$i+2]<<0); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$psectname}{START} + $con); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(IR): adr=%06o val=%06o ; dis=%06o con=%06o\n", - $adr, $val, $dis, $con if $DEBUG; - $i += 4; - } elsif ($ent == 002) { - # global relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - # process - printf $LOG "..RLD(GR): dis=%06o nam='%s'\n", - $dis, $nam if $DEBUG; - $i += 6; - } elsif ($ent == 003) { - # internal displaced ... OK - my $dis = $rec[$i+1]; - my $con = ($rec[$i+3]<<8)|($rec[$i+2]<<0); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($con - ($adr+2)); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(ID): adr=%06o val=%06o ; dis=%06o con=%06o\n", - $adr, $val, $dis, $con if $DEBUG; - $i += 4; - } elsif ($ent == 004) { - # global displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - # process - printf $LOG "..RLD(GDR): dis=%06o nam='%s'\n", - $dis, $nam if $DEBUG; - $i += 6; - } elsif ($ent == 005) { - # global additive relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); - # process - printf $LOG "..RLD(GAR): dis=%06o con=%06o nam='%s'\n", - $dis, $con, $nam if $DEBUG; - $i += 8; - } elsif ($ent == 006) { - # global additive displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); - # process - printf $LOG "..RLD(GADR): dis=%06o con=%06o nam='%s'\n", - $dis, $con, $nam if $DEBUG; - $i += 8; - } elsif ($ent == 007) { - # location counter definition ... OK - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); - # process - $psectname = $nam; - $textaddr = $datmsk & ($con); - printf $LOG "..RLD(LCD): adr=%06o ; dis=%06o con=%06o nam='%s'\n", - $textaddr, $dis, $con, $nam if $DEBUG; - $i += 8; - } elsif ($ent == 010) { - # location counter modification ... OK - my $dis = $rec[$i+1]; - my $con = ($rec[$i+3]<<8)|($rec[$i+2]<<0); - # process - $textaddr = $datmsk & ($con); - printf $LOG "..RLD(LCM): adr=%06o ; dis=%06o con=%06o\n", - $textaddr, $dis, $con if $DEBUG; - $i += 4; - } elsif ($ent == 011) { - # program limits ... OK, mostly - my $dis = $rec[$i+1]; - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ( 01000 ); # make this up, no easy way to compute it - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(LIM1): adr=%06o val=%06o ; dis=%06o\n", - $adr, $val, $dis if $DEBUG; - $dis += 2; - $adr += 2; - $val = $datmsk & ($program{END}{ADDRESS}); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(LIM2): adr=%06o val=%06o ; dis=%06o\n", - $adr, $val, $dis if $DEBUG; - $i += 2; - } elsif ($ent == 012) { - # psect relocation ... OK - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START}); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", - $adr, $val, $dis, $nam if $DEBUG; - $i += 6; - } elsif ($ent == 014) { - # psect displaced relocation ... OK - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START} - ($adr+2)); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PDR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", - $adr, $val, $dis, $nam if $DEBUG; - $i += 6; - } elsif ($ent == 015) { - # psect additive relocation ... OK - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START} + $con); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PAR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", - $adr, $val, $dis, $con, $nam if $DEBUG; - $i += 8; - } elsif ($ent == 016) { - # psect additive displaced relocation ... OK - my $dis = $rec[$i+1]; - my $nam = &rad2asc(($rec[$i+3]<<8)|($rec[$i+2]<<0), ($rec[$i+5]<<8)|($rec[$i+4]<<0)); - my $con = ($rec[$i+7]<<8)|($rec[$i+6]<<0); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START} + $con - ($adr+2)); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PADR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", - $adr, $val, $dis, $con, $nam if $DEBUG; - $i += 8; - } elsif ($ent == 017) { - # complex relocation ... OK - my $dis = $rec[$i+1]; - my $nam = '. ABS.'; - my $con = 0; - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $loc = 0; - my $val = 0; - my $opc = ""; - my @stk = (); - my $dun = 0; - for ($i += 2; !$dun; $i += 1) { - if ($rec[$i] == 000) { - $opc = "NOP"; - } elsif ($rec[$i] == 001) { - my @arg = splice(@stk,-2,2); - push(@stk, $arg[0] + $arg[1]); - $opc = "ADD"; - } elsif ($rec[$i] == 002) { - my @arg = splice(@stk,-2,2); - push(@stk, $arg[0] - $arg[1]); - $opc = "SUB"; - } elsif ($rec[$i] == 003) { - my @arg = splice(@stk,-2,2); - push(@stk, $arg[0] * $arg[1]); - $opc = "MUL"; - } elsif ($rec[$i] == 004) { - my @arg = splice(@stk,-2,2); - push(@stk, $arg[1] == 0 ? 0 : int($arg[0] / $arg[1])); - $opc = "DIV"; - } elsif ($rec[$i] == 005) { - my @arg = splice(@stk,-2,2); - push(@stk, $arg[0] & $arg[1]); - $opc = "AND"; - } elsif ($rec[$i] == 006) { - my @arg = splice(@stk,-2,2); - push(@stk, $arg[0] | $arg[1]); - $opc = "IOR"; - } elsif ($rec[$i] == 007) { - my @arg = splice(@stk,-2,2); - push(@stk, $arg[0] ^ $arg[1]); - $opc = "XOR"; - } elsif ($rec[$i] == 010) { - my @arg = splice(@stk,-1,1); - push(@stk, -$arg[0]); - $opc = "NEG"; - } elsif ($rec[$i] == 011) { - my @arg = splice(@stk,-1,1); - push(@stk, ~$arg[0]); - $opc = "COM"; - } elsif ($rec[$i] == 012) { - my @arg = splice(@stk,-1,1); - $val = $arg[0]; - $opc = "STO"; - $dun = 1; - } elsif ($rec[$i] == 013) { - ############## may need tweaking ################ - my @arg = splice(@stk,-1,1); - $val = $arg[0]; - $opc = "STO+DIS"; - $dun = 1; - } elsif ($rec[$i] == 016) { - ############## may need tweaking ################ - $nam = &rad2asc(($rec[$i+2]<<8)|($rec[$i+1]<<0), - ($rec[$i+4]<<8)|($rec[$i+3]<<0)); - $con = $gblsym{$nam}{VALUE}; - push(@stk, $con); - $opc = sprintf("GLB[%s]=(%o)", &trim($nam), $con); - $i += 4; - } elsif ($rec[$i] == 017) { - $nam = $psect[$rec[$i+1]]; - $con = ($rec[$i+3]<<8) | ($rec[$i+2]<<0); - $loc = $psect{$nam}{START} + $con; - push(@stk, $loc); - $opc = sprintf("FET[%s+%o]=(%o)", &trim($nam), $con, $loc); - $i += 3; - } elsif ($rec[$i] == 020) { - $con = ($rec[$i+2]<<8) | ($rec[$i+1]<<0); - push(@stk, $con); - $opc = "CON"; - $i += 2; - } - $stk[-1] = $datmsk & $stk[-1] if @stk; - printf $LOG "....OPC=%-20s STK=(%s)\n", $opc, join(",",map(sprintf("%o",$_),@stk)) if $DEBUG; - } - printf $LOG "..RLD(CMPX): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; - } else { - die sprintf("Error: Unknown RLD entry 0%o (%d)", $ent, $ent); - } - } - - } elsif ($key == 005) { # ISD - - # ignore - printf $LOG "..ISD: ignored\n" if $DEBUG; - - } elsif ($key == 006) { # ENDMOD - - # just say we saw it - printf $LOG "..ENDMOD\n\n\n" if $DEBUG; - - } elsif ($key == 007) { # LIBHDR - - # ignore - printf $LOG "..LIBHDR: ignored\n" if $DEBUG; - - } elsif ($key == 010) { # LIBEND - - # ignore - printf $LOG "..LIBEND: ignored\n" if $DEBUG; - - } else { # unknown - - # invalid record type in the object file - die sprintf("Error: unknown record type 0%o (%d)", $key, $key); - - } - -} - -# done with object file -$OBJ->close; - -#---------------------------------------------------------------------------------------------------- - -# compute CRC if required, copy memory image to output buffer - -my @buf = ($romfill) x $romsize; # physical PROM data bytes, filled background pattern - -# only compute CRC on M9312 ROMs -if ($romtype eq 'BOOT' || $romtype eq 'DIAG') { - - # compute CRC-16 of the prom contents (except exception words) and store at last location - my $crctab = &crc(-name=>$crctype, -new=>1); - my $crc = &crc(-name=>$crctype, -init=>1); - for (my $adr = 0; $adr < $memsize-2; $adr += 1) { - next if exists($excaddr{$adr}); # skip these addresses - $mem[$rombase+$adr] = $memfill unless defined($mem[$rombase+$adr]); - $crc = &crc(-name=>$crctype, -table=>$crctab, -crc=>$crc, -byte=>$mem[$rombase+$adr]); - } - $crc = &crc(-name=>$crctype, -crc=>$crc, -last=>1); - unless ($nocrc) { - # output computed CRC-16 as last word in the ROM file - $mem[$rombase+$memsize-2] = ($crc>>0)&0xFF; - $mem[$rombase+$memsize-1] = ($crc>>8)&0xFF; - } - printf $LOG "ROM %s is %06o (0x%04X)\n", $crctype, ($crc) x 2 if $VERBOSE; - - # process data words to actual PROM byte data - # put 4bit nibble in low 4b of each 8b data byte, zero the upper 4b - # only copy the above instruction portion over - for (my $idx = 0; $idx < $memsize<<1; $idx += 4) { - my $dat = ($mem[$rombase+($idx>>1)+1]<<8) | ($mem[$rombase+($idx>>1)+0]<<0); - $buf[$idx+0] = ($dat&0xE)|(($dat>>8)&0x1); # bits 3 2 1 8 - $buf[$idx+1] = ($dat>>4)&0xF; # bits 7 6 5 4 - $buf[$idx+2] = ((($dat>>8)&0xE)|($dat&0x1))^0xC; # bits ~11 ~10 9 0 - $buf[$idx+3] = (($dat>>12)&0xF)^0x1; # bits 15 14 13 ~12 - } - -} elsif ($romtype eq 'BINA' || $romtype eq 'ASC9') { - - # only copy the above instruction portion over - for (my $adr = 0; $adr < $memsize; $adr += 1) { - $mem[$rombase+$adr] = $memfill unless defined($mem[$rombase+$adr]); - $buf[$adr] = $mem[$rombase+$adr]; - } - -} - -if ($VERBOSE) { - - # print checksum of entire device - my $chksum = 0; map($chksum += $_, @buf); - printf $LOG "ROM checksum is %06o (0x%04X)\n", $chksum, $chksum; - -} - -#---------------------------------------------------------------------------------------------------- - -# output the linked/processed binary file image in the desired format - -my $OUT = FileHandle->new("> ".$outfile); -die "Error: can't open output file '$outfile'\n" unless defined $OUT; - -if ($romtype eq 'BOOT' || $romtype eq 'DIAG') { - - # 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 $OUT ":%02X%04X%02X%s%02X\n", $cnt, $idx, 0x00, $dat, &chksum($cnt, $idx>>0, $idx>>8, 0x00, @dat); - } - - printf $OUT ":%02X%04X%02X%s%02X\n", 0x00, 0x0000, 0x01, '', &chksum(0x0, 0x0000>>0, 0x0000>>8, 0x01); - -} elsif ($romtype eq 'BINA') { - - # Loader 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 - # - # If the byte length is exactly six, the block is the last on the tape, and - # there is no checksum. If the origin is not 000001, then the origin is - # the PC at which to start the program. - - $bytesper = 128 if $bytesper <= 0; - - my $start = $program{START}{ADDRESS}; - - sub m ($) { $_[0] & 0xFF; } - - # output the entire PROM buffer as a binary loader file - for (my $idx = $adrmin; $idx < $adrmax+1; $idx += $bytesper) { - my $cnt = $idx+$bytesper <= $adrmax+1 ? $bytesper : $adrmax+1-$idx; # N bytes or whatever is left - my @dat = @buf[$idx..($idx+$cnt-1)]; # get the data - my $len = $cnt+6; - my @rec = (0x01, 0x00, &m($len>>0), &m($len>>8), &m($idx>>0), &m($idx>>8), @dat); - print $OUT pack("C*", @rec, &chksum(@rec)); - } - my @end = (0x01, 0x00, 0x06, 0x00, &m($start>>0), &m($start>>8)); - print $OUT pack("C*", @end, &chksum(@end)); - -} elsif ($romtype eq 'ASC9') { - - # ascii interface to M9312 console emulator - - sub n ($) { $_[0] & 0xFF; } - - # start program load here - printf $OUT "L %o\r\n", $adrmin; - - # output the PROM buffer as an ascii load file - for (my $idx = $adrmin; $idx < $adrmax+1; $idx += 2) { - printf $OUT "D %06o\r\n", (&n($buf[$idx+1])<<8) | &n($buf[$idx+0]); - } - - # start program exec here - printf $OUT "L %o\r\nS\r\n", $adrmin; - -} - -# all done -$OUT->close; - -#---------------------------------------------------------------------------------------------------- - -# really done -$LOG->close; -exit; - -#---------------------------------------------------------------------------------------------------- - -# 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 +#!/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 + +obj2hex.pl - Convert a Macro-11 program image to PROM/load format + +=head1 SYNOPSIS + +obj2hex.pl +S<[--help]> +S<[--debug]> +S<[--verbose]> +S<[--boot]> +S<[--console]> +S<[--binary]> +S<[--ascii]> +S<[--bytes=N]> +S<[--nocrc]> +S<[--logfile=LOGFILE]> +S<--outfile=BINFILE> +S + +=head1 DESCRIPTION + +Converts a Macro-11 object files 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. + +Multiple .psect/.asect ops are supported, as well as all local +(non-global) relocation directory entries. + +Multiple input object files are (not yet fully) supported - this +part is work in progress. In particular definition and resolution +of global symbols are not supported. + +=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<--boot> + +Generate a hex PROM file image suitable for programming into +an M9312 boot prom (512x4 geometry, only low half used). + +=item B<--console> + +Generate a hex PROM file image suitable for programming into +an M9312 console/diagnostic prom (1024x4 geometry). + +=item B<--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). + +=item B<--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 B<--boot>, B<--console>, B<--binary>, or B<--ascii> +must be specified. + +=item B<--bytes=N> + +For hex format output files, output N bytes per line (default 16). + +=item B<--nocrc> + +For hex format output files, don't automatically stuff the computed +CRC-16 as the last word in the ROM. + +=item B<--logfile=FILENAME> + +Generate debug output into this file. + +=item B<--outfile=FILENAME> + +Output binary file in format selected by user option. + +=item B + +Input object file(s) in .obj format. + +=back + +=head1 ERRORS + +The following diagnostic error messages can be produced on STDERR. +The meaning should be fairly self explanatory. + +C -- bad option or missing file(s) + +C -- bad filename or unreadable file + +C -- valid record must start with 0x01 + +C -- second byte must be 0x00 + +C -- third byte is low byte of record length + +C -- fourth byte is high byte of record length + +C -- bytes five thru end-1 are data bytes + +C -- last byte is checksum + +C -- compare rcv'ed checksum vs exp'ed checksum + +=head1 EXAMPLES + +Some examples of common usage: + + obj2hex.pl --help + + obj2hex.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj + + obj2hex.pl --verbose --binary --out memtest.bin memtest.obj + +=head1 AUTHOR + +Don North - donorth + +=head1 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. + +=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 = 'v2.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 $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 $bytesper = -1; # bytes per block in output file +my $nocrc = 0; # output CRC16 as last word unless set +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'; }, + "ascii" => sub { $romtype = 'ASC9'; }, + "bytes=i" => \$bytesper, + "nocrc" => \$nocrc, + "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) >= 1 + && defined($outfile) + && $romtype ne 'NONE' + ) { + printf STDERR "obj2hex.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 + --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) +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 trim ($); +sub chksum (@); +sub rad2asc (@); +sub crc (%); +sub read_rec ($); +sub parse_rec ($); + +#---------------------------------------------------------------------------------------------------- + +# fill in the parameters of the device + +if ($romtype eq 'BOOT') { + + # M9312 512x4 boot prom + %excaddr = ( 024=>1, 025=>1 ); # bytes 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 = ( ); # bytes 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 (must be a power of two) + $romfill = 0x00; # rom fill pattern + $rombase = 0165000; # base address of rom + +} elsif ($romtype eq 'BINA' || $romtype eq 'ASC9') { + + # program load image ... 56KB address space maximum + %excaddr = ( ); # bytes to be skipped in rom crc calc + $memsize = 7*8192; # 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 file records + +# real pdp11 memory data words in boot prom +my @mem = ((0) x $memsize); + +# min/max address limits in object file +my ($adrmin,$adrmax) = ('',''); + +# state variables in processing object records +my $rommsk = ($romsize-1)>>1; # address bit mask +my $adrmsk = 0xFFFF; # 16b addr mask +my $datmsk = 0xFFFF; # 16b data mask +my $memmsk = 0xFF; # 8b memory data mask + +# databases +my %gblsym = (); +my %psect = (); +my @psect = (); +my %program = (); +my $psectname = '. ABS.'; +my $psectaddr = 0; +my $psectnumb = -1; +my $textaddr = 0; + +# program defaults +$program{START}{VALUE} = 1; +$program{START}{PSECT} = '. ABS.'; + +# process all object files +while (my $objfile = shift(@ARGV)) { + + # open the input .obj file, die if error + my $OBJ = FileHandle->new("< ".$objfile); + die "Error: can't open input object file '$objfile'\n" unless defined $OBJ; + + # now parse all the records + while (my @rec = &read_rec($OBJ)) { &parse_rec(\@rec); } + + # done with object file + $OBJ->close; +} + +#---------------------------------------------------------------------------------------------------- + +# compute CRC if required, copy memory image to output buffer + +my @buf = ($romfill) x $romsize; # physical PROM data bytes, filled background pattern + +# only compute CRC on M9312 ROMs +if ($romtype eq 'BOOT' || $romtype eq 'DIAG') { + + # compute CRC-16 of the prom contents (except exception words) and store at last location + my $crctab = &crc(-name=>$crctype, -new=>1); + my $crc = &crc(-name=>$crctype, -init=>1); + for (my $adr = 0; $adr < $memsize-2; $adr += 1) { + next if exists($excaddr{$adr}); # skip these addresses + $mem[$rombase+$adr] = $memfill unless defined($mem[$rombase+$adr]); + $crc = &crc(-name=>$crctype, -table=>$crctab, -crc=>$crc, -byte=>$mem[$rombase+$adr]); + } + $crc = &crc(-name=>$crctype, -crc=>$crc, -last=>1); + unless ($nocrc) { + # output computed CRC-16 as last word in the ROM file + $mem[$rombase+$memsize-2] = ($crc>>0)&0xFF; + $mem[$rombase+$memsize-1] = ($crc>>8)&0xFF; + } + printf $LOG "ROM %s is %06o (0x%04X)\n", $crctype, ($crc) x 2 if $VERBOSE; + + # process data words to actual PROM byte data + # put 4bit nibble in low 4b of each 8b data byte, zero the upper 4b + # only copy the above instruction portion over + for (my $idx = 0; $idx < $memsize<<1; $idx += 4) { + my $dat = ($mem[$rombase+($idx>>1)+1]<<8) | ($mem[$rombase+($idx>>1)+0]<<0); + $buf[$idx+0] = ($dat&0xE)|(($dat>>8)&0x1); # bits 3 2 1 8 + $buf[$idx+1] = ($dat>>4)&0xF; # bits 7 6 5 4 + $buf[$idx+2] = ((($dat>>8)&0xE)|($dat&0x1))^0xC; # bits ~11 ~10 9 0 + $buf[$idx+3] = (($dat>>12)&0xF)^0x1; # bits 15 14 13 ~12 + } + +} elsif ($romtype eq 'BINA' || $romtype eq 'ASC9') { + + # only copy the above instruction portion over + for (my $adr = 0; $adr < $memsize; $adr += 1) { + $mem[$rombase+$adr] = $memfill unless defined($mem[$rombase+$adr]); + $buf[$adr] = $mem[$rombase+$adr]; + } + +} + +if ($VERBOSE) { + + # print checksum of entire device + my $chksum = 0; map($chksum += $_, @buf); + printf $LOG "ROM checksum is %06o (0x%04X)\n", $chksum, $chksum; + +} + +#---------------------------------------------------------------------------------------------------- + +# output the linked/processed binary file image in the desired format + +my $OUT = FileHandle->new("> ".$outfile); +die "Error: can't open output file '$outfile'\n" unless defined $OUT; + +if ($romtype eq 'BOOT' || $romtype eq 'DIAG') { + + # 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 $OUT ":%02X%04X%02X%s%02X\n", $cnt, $idx, 0x00, $dat, &chksum($cnt, $idx>>0, $idx>>8, 0x00, @dat); + } + + printf $OUT ":%02X%04X%02X%s%02X\n", 0x00, 0x0000, 0x01, '', &chksum(0x0, 0x0000>>0, 0x0000>>8, 0x01); + +} elsif ($romtype eq 'BINA') { + + # Loader 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 + # + # If the byte length is exactly six, the block is the last on the tape, and + # there is no checksum. If the origin is not 000001, then the origin is + # the PC at which to start the program. + + $bytesper = 128 if $bytesper <= 0; + + my $start = $program{START}{ADDRESS}; + + sub m ($) { $_[0] & 0xFF; } + + # output the entire PROM buffer as a binary loader file + for (my $idx = $adrmin; $idx < $adrmax+1; $idx += $bytesper) { + my $cnt = $idx+$bytesper <= $adrmax+1 ? $bytesper : $adrmax+1-$idx; # N bytes or whatever is left + my @dat = @buf[$idx..($idx+$cnt-1)]; # get the data + my $len = $cnt+6; + my @rec = (0x01, 0x00, &m($len>>0), &m($len>>8), &m($idx>>0), &m($idx>>8), @dat); + print $OUT pack("C*", @rec, &chksum(@rec)); + } + my @end = (0x01, 0x00, 0x06, 0x00, &m($start>>0), &m($start>>8)); + print $OUT pack("C*", @end, &chksum(@end)); + +} elsif ($romtype eq 'ASC9') { + + # ascii interface to M9312 console emulator + + sub n ($) { $_[0] & 0xFF; } + + # start program load here + printf $OUT "L %o\r\n", $adrmin; + + # output the PROM buffer as an ascii load file + for (my $idx = $adrmin; $idx < $adrmax+1; $idx += 2) { + printf $OUT "D %06o\r\n", (&n($buf[$idx+1])<<8) | &n($buf[$idx+0]); + } + + # start program exec here + printf $OUT "L %o\r\nS\r\n", $adrmin; + +} + +# all done +$OUT->close; + +#---------------------------------------------------------------------------------------------------- + +# really done +$LOG->close; +exit; + +#---------------------------------------------------------------------------------------------------- +#---------------------------------------------------------------------------------------------------- + +# 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; +} + +#---------------------------------------------------------------------------------------------------- + +# parse an input object file record, update data structures + +sub parse_rec ($) { + + my ($rec) = (@_); + + # type is first byte of record + my $key = $rec->[0]; + + if ($key == 001) { # GSD + + # iterate over GSD subrecords + for (my $i = 2; $i < scalar(@$rec); ) { + # GSD records are fixed 8B length all in the same format + my $nam = &rad2asc(($rec->[$i+1]<<8)|($rec->[$i+0]<<0), ($rec->[$i+3]<<8)|($rec->[$i+2]<<0)); + my $flg = $rec->[$i+4]; + my $ent = $rec->[$i+5]; + my $val = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + my @ent = ('MODULE','CSECT','INTSYM','XFRADR','GBLSYM','PSECT','IDENT','VSECT'); + if ($ent == 3) { + # XFRADR + $program{START}{PSECT} = $nam; + $program{START}{VALUE} = $val; + } elsif ($ent == 4) { + # GBLSYM flags + $gblsym{$nam}{FLG}{$flg&(1<<0) ? "WEA" : "STR"}++; + $gblsym{$nam}{FLG}{$flg&(1<<3) ? "DEF" : "REF"}++; + $gblsym{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; + $gblsym{$nam}{PSECT} = $psectname; + $gblsym{$nam}{VALUE} = $val; + } elsif ($ent == 5) { + # PSECT flags + $psect[++$psectnumb] = $nam; + $psect{$nam}{NUMBER} = $psectnumb; + $psect{$nam}{FLG}{$flg&(1<<0) ? "GBL" : $flg&(1<<6) ? "GBL" : "LCL"}++; + $psect{$nam}{FLG}{$flg&(1<<2) ? "OVR" : "CAT"}++; + $psect{$nam}{FLG}{$flg&(1<<4) ? "R/O" : "R/W"}++; + $psect{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; + $psect{$nam}{FLG}{$flg&(1<<7) ? "D" : "I/D"}++; + if ($psect{$nam}{FLG}{CAT}) { + $psect{$nam}{LENGTH} = $val; + $psect{$nam}{START} = $psectaddr; + $psectname = $nam; + $psectaddr += $val; + } elsif ($psect{$nam}{FLG}{ABS}) { + $psect{$nam}{LENGTH} = $val; + $psect{$nam}{START} = 0; + $psectname = $nam; + } + } + if ($DEBUG) { + printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, $nam, $val; + printf $LOG " flags=%s", join(",", sort(keys(%{$gblsym{$nam}{FLG}}))) if $ent == 4; + printf $LOG " flags=%s", join(",", sort(keys(%{$psect{$nam}{FLG}}))) if $ent == 5; + printf $LOG "\n"; + } + $i += 8; + } + + } elsif ($key == 002) { # ENDGSD + + # just say we saw it + printf $LOG "..ENDGSD\n" if $DEBUG; + + $program{END}{ADDRESS} = 0; + foreach my $nam (sort(keys(%psect))) { + my $start = $psect{$nam}{START}; + my $length = $psect{$nam}{LENGTH}; + my $end = $length ? $start + $length - 1 : $start; + $program{END}{ADDRESS} = $end if $end > $program{END}{ADDRESS}; + printf $LOG "..PSECT[%d](%s) START=%06o END=%06o LENGTH=%06o\n", + $psect{$nam}{NUMBER}, $nam, $start, $end, $length if $length && $DEBUG; + } + $program{START}{ADDRESS} = $program{START}{VALUE} + $psect{$program{START}{PSECT}}{START}; + printf $LOG "..PROG(ADDRESS) START=%06o END=%06o\n", + $program{START}{ADDRESS}, $program{END}{ADDRESS} if $DEBUG; + + } elsif ($key == 003) { # TXT + + # process text record + my $off = ($rec->[3]<<8)|($rec->[2]<<0); + my $len = scalar(@$rec)-4; + my $base = $psect{$psectname}{START}; + my $adr = ($base + $off) & $adrmsk; + foreach my $i (1..$len) { $mem[$adr+$i-1] = $rec->[4+$i-1]; } + if ($DEBUG) { + printf $LOG "..TXT OFFSET=%06o LENGTH=%o BASE=%06o PSECTNAME='%s'\n", $off, $len, $base, $psectname; + for (my $i = 0; $i < $len; $i += 2) { + printf $LOG " %06o: ", ($adr+$i)&~1 if $i%8 == 0; + printf $LOG " %03o...", $mem[$adr+$i++] if ($adr+$i)&1; + printf $LOG " %06o", ($mem[$adr+$i+1]<<8)|($mem[$adr+$i+0]<<0) if $i < $len-1; + printf $LOG " ...%03o", $mem[$adr+$i] if $i == $len-1; + printf $LOG "\n" if $i%8 >= 6 && $i < $len-2; + } + printf $LOG "\n"; + } + $adrmin = $adr if $adrmin eq '' || $adr < $adrmin; + $adrmax = $adr+$len-1 if $adrmax eq '' || $adr+$len-1 > $adrmax; + $textaddr = $adr; + + } elsif ($key == 004) { # RLD + + # iterate over RLD subrecords + for (my $i = 2; $i < scalar(@$rec); ) { + # first byte is entry type and flags + my $ent = $rec->[$i+0] & 0x7F; # entry type + my $flg = $rec->[$i+0] & 0x80; # modification flag (0=word, 1=byte) + # process an entry + if ($ent == 001) { + # internal relocation ... OK + my $dis = $rec->[$i+1]; + my $con = ($rec->[$i+3]<<8)|($rec->[$i+2]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$psectname}{START} + $con); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(IR): adr=%06o val=%06o ; dis=%06o con=%06o\n", + $adr, $val, $dis, $con if $DEBUG; + $i += 4; + } elsif ($ent == 002) { + # global relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + # process + printf $LOG "..RLD(GR): dis=%06o nam='%s'\n", + $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 003) { + # internal displaced ... OK + my $dis = $rec->[$i+1]; + my $con = ($rec->[$i+3]<<8)|($rec->[$i+2]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($con - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(ID): adr=%06o val=%06o ; dis=%06o con=%06o\n", + $adr, $val, $dis, $con if $DEBUG; + $i += 4; + } elsif ($ent == 004) { + # global displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + # process + printf $LOG "..RLD(GDR): dis=%06o nam='%s'\n", + $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 005) { + # global additive relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + # process + printf $LOG "..RLD(GAR): dis=%06o con=%06o nam='%s'\n", + $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 006) { + # global additive displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + # process + printf $LOG "..RLD(GADR): dis=%06o con=%06o nam='%s'\n", + $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 007) { + # location counter definition ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + # process + $psectname = $nam; + $textaddr = $datmsk & ($con); + printf $LOG "..RLD(LCD): adr=%06o ; dis=%06o con=%06o nam='%s'\n", + $textaddr, $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 010) { + # location counter modification ... OK + my $dis = $rec->[$i+1]; + my $con = ($rec->[$i+3]<<8)|($rec->[$i+2]<<0); + # process + $textaddr = $datmsk & ($con); + printf $LOG "..RLD(LCM): adr=%06o ; dis=%06o con=%06o\n", + $textaddr, $dis, $con if $DEBUG; + $i += 4; + } elsif ($ent == 011) { + # program limits ... OK, mostly + my $dis = $rec->[$i+1]; + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ( 01000 ); # make this up, no easy way to compute it + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(LIM1): adr=%06o val=%06o ; dis=%06o\n", + $adr, $val, $dis if $DEBUG; + $dis += 2; + $adr += 2; + $val = $datmsk & ($program{END}{ADDRESS}); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(LIM2): adr=%06o val=%06o ; dis=%06o\n", + $adr, $val, $dis if $DEBUG; + $i += 2; + } elsif ($ent == 012) { + # psect relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START}); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", + $adr, $val, $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 014) { + # psect displaced relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PDR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", + $adr, $val, $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 015) { + # psect additive relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} + $con); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PAR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", + $adr, $val, $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 016) { + # psect additive displaced relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} + $con - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PADR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", + $adr, $val, $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 017) { + # complex relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = '. ABS.'; + my $con = 0; + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $loc = 0; + my $val = 0; + my $opc = ""; + my @stk = (); + my $dun = 0; + for ($i += 2; !$dun; $i += 1) { + if ($rec->[$i] == 000) { + $opc = "NOP"; + } elsif ($rec->[$i] == 001) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] + $arg[1]); + $opc = "ADD"; + } elsif ($rec->[$i] == 002) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] - $arg[1]); + $opc = "SUB"; + } elsif ($rec->[$i] == 003) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] * $arg[1]); + $opc = "MUL"; + } elsif ($rec->[$i] == 004) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[1] == 0 ? 0 : int($arg[0] / $arg[1])); + $opc = "DIV"; + } elsif ($rec->[$i] == 005) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] & $arg[1]); + $opc = "AND"; + } elsif ($rec->[$i] == 006) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] | $arg[1]); + $opc = "IOR"; + } elsif ($rec->[$i] == 007) { + my @arg = splice(@stk,-2,2); + push(@stk, $arg[0] ^ $arg[1]); + $opc = "XOR"; + } elsif ($rec->[$i] == 010) { + my @arg = splice(@stk,-1,1); + push(@stk, -$arg[0]); + $opc = "NEG"; + } elsif ($rec->[$i] == 011) { + my @arg = splice(@stk,-1,1); + push(@stk, ~$arg[0]); + $opc = "COM"; + } elsif ($rec->[$i] == 012) { + my @arg = splice(@stk,-1,1); + $val = $arg[0]; + $opc = "STO"; + $dun = 1; + } elsif ($rec->[$i] == 013) { + ############## may need tweaking ################ + my @arg = splice(@stk,-1,1); + $val = $arg[0]; + $opc = "STO+DIS"; + $dun = 1; + } elsif ($rec->[$i] == 016) { + ############## may need tweaking ################ + $nam = &rad2asc(($rec->[$i+2]<<8)|($rec->[$i+1]<<0), + ($rec->[$i+4]<<8)|($rec->[$i+3]<<0)); + $con = $gblsym{$nam}{VALUE}; + push(@stk, $con); + $opc = sprintf("GLB[%s]=(%o)", &trim($nam), $con); + $i += 4; + } elsif ($rec->[$i] == 017) { + $nam = $psect[$rec->[$i+1]]; + $con = ($rec->[$i+3]<<8) | ($rec->[$i+2]<<0); + $loc = $psect{$nam}{START} + $con; + push(@stk, $loc); + $opc = sprintf("FET[%s+%o]=(%o)", &trim($nam), $con, $loc); + $i += 3; + } elsif ($rec->[$i] == 020) { + $con = ($rec->[$i+2]<<8) | ($rec->[$i+1]<<0); + push(@stk, $con); + $opc = "CON"; + $i += 2; + } + $stk[-1] = $datmsk & $stk[-1] if @stk; + printf $LOG "....OPC=%-20s STK=(%s)\n", $opc, join(",",map(sprintf("%o",$_),@stk)) if $DEBUG; + } + printf $LOG "..RLD(CMPX): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; + } else { + die sprintf("Error: Unknown RLD entry 0%o (%d)", $ent, $ent); + } + } + + } elsif ($key == 005) { # ISD + + # ignore + printf $LOG "..ISD: ignored\n" if $DEBUG; + + } elsif ($key == 006) { # ENDMOD + + # just say we saw it + printf $LOG "..ENDMOD\n\n\n" if $DEBUG; + + } elsif ($key == 007) { # LIBHDR + + # ignore + printf $LOG "..LIBHDR: ignored\n" if $DEBUG; + + } elsif ($key == 010) { # LIBEND + + # ignore + printf $LOG "..LIBEND: ignored\n" if $DEBUG; + + } else { # unknown + + # invalid record type in the object file + die sprintf("Error: unknown record type 0%o (%d)", $key, $key); + + } + + return; +} + +#---------------------------------------------------------------------------------------------------- + +# the end From 74a686102cde805e162813ad65d625836aaedac9 Mon Sep 17 00:00:00 2001 From: AK6DN Date: Wed, 5 Apr 2017 15:40:21 -0700 Subject: [PATCH 009/174] Minor type corrections. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c2614b2..fada40c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ If run with no options, it prints a usage screen: ``` -obj2hex.pl v1.5 by Don North (perl 5.022) +obj2hex.pl v2.0 by Don North (perl 5.022) Usage: ./obj2hex.pl [options...] arguments --help output manpage and exit --debug enable debug mode From eeb1147233f51547d46733d755fdf40d97786736 Mon Sep 17 00:00:00 2001 From: AK6DN Date: Fri, 7 Apr 2017 13:20:51 -0700 Subject: [PATCH 010/174] More updates staging for multiple object file linking; change name to obj2bin.pl --- README.md | 16 ++-- obj2hex.pl => obj2bin.pl | 154 ++++++++++++++++++++------------------- 2 files changed, 87 insertions(+), 83 deletions(-) rename obj2hex.pl => obj2bin.pl (97%) diff --git a/README.md b/README.md index fada40c..b0409f6 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -obj2hex.pl 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). +obj2bin.pl 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: ``` -obj2hex.pl v2.0 by Don North (perl 5.022) -Usage: ./obj2hex.pl [options...] arguments +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 @@ -24,10 +24,10 @@ If run with the --help option it prints a longer manual page: ``` NAME - obj2hex.pl - Convert a Macro-11 program image to PROM/load format + obj2bin.pl - Convert a Macro-11 program image to PROM/load format SYNOPSIS - obj2hex.pl [--help] [--debug] [--verbose] [--boot] [--console] [--binary] + obj2bin.pl [--help] [--debug] [--verbose] [--boot] [--console] [--binary] [--ascii] [--bytes=N] [--nocrc] [--logfile=LOGFILE] --outfile=BINFILE OBJFILE... @@ -122,11 +122,11 @@ ERRORS EXAMPLES Some examples of common usage: - obj2hex.pl --help + obj2bin.pl --help - obj2hex.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj + obj2bin.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj - obj2hex.pl --verbose --binary --out memtest.bin memtest.obj + obj2bin.pl --verbose --binary --out memtest.bin memtest.obj AUTHOR Don North - donorth diff --git a/obj2hex.pl b/obj2bin.pl similarity index 97% rename from obj2hex.pl rename to obj2bin.pl index b27a3fc..983cfa7 100644 --- a/obj2hex.pl +++ b/obj2bin.pl @@ -35,11 +35,11 @@ require 5.008; =head1 NAME -obj2hex.pl - Convert a Macro-11 program image to PROM/load format +obj2bin.pl - Convert a Macro-11 program image to PROM/load format =head1 SYNOPSIS -obj2hex.pl +obj2bin.pl S<[--help]> S<[--debug]> S<[--verbose]> @@ -161,11 +161,11 @@ C -- compare rcv'ed checksum vs exp'e Some examples of common usage: - obj2hex.pl --help + obj2bin.pl --help - obj2hex.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj + obj2bin.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj - obj2hex.pl --verbose --binary --out memtest.bin memtest.obj + obj2bin.pl --verbose --binary --out memtest.bin memtest.obj =head1 AUTHOR @@ -183,6 +183,7 @@ Modification history: 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 =cut @@ -259,7 +260,7 @@ unless ($NOERROR && defined($outfile) && $romtype ne 'NONE' ) { - printf STDERR "obj2hex.pl %s by Don North (perl %g)\n", $VERSION, $]; + printf STDERR "obj2bin.pl %s by Don North (perl %g)\n", $VERSION, $]; print STDERR "Usage: $0 [options...] arguments\n"; print STDERR <<"EOF"; --help output manpage and exit @@ -368,6 +369,7 @@ my $psectnumb = -1; my $textaddr = 0; # program defaults +$program{START}{ADDRESS} = 1; $program{START}{VALUE} = 1; $program{START}{PSECT} = '. ABS.'; @@ -729,11 +731,11 @@ sub parse_rec ($) { $psect[++$psectnumb] = $nam; $psect{$nam}{NUMBER} = $psectnumb; $psect{$nam}{FLG}{$flg&(1<<0) ? "GBL" : $flg&(1<<6) ? "GBL" : "LCL"}++; - $psect{$nam}{FLG}{$flg&(1<<2) ? "OVR" : "CAT"}++; + $psect{$nam}{FLG}{$flg&(1<<2) ? "OVR" : "CON"}++; $psect{$nam}{FLG}{$flg&(1<<4) ? "R/O" : "R/W"}++; $psect{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; $psect{$nam}{FLG}{$flg&(1<<7) ? "D" : "I/D"}++; - if ($psect{$nam}{FLG}{CAT}) { + if ($psect{$nam}{FLG}{CON}) { $psect{$nam}{LENGTH} = $val; $psect{$nam}{START} = $psectaddr; $psectname = $nam; @@ -756,7 +758,7 @@ sub parse_rec ($) { } elsif ($key == 002) { # ENDGSD # just say we saw it - printf $LOG "..ENDGSD\n" if $DEBUG; + printf $LOG "..ENDGSD\n\n" if $DEBUG; $program{END}{ADDRESS} = 0; foreach my $nam (sort(keys(%psect))) { @@ -764,11 +766,13 @@ sub parse_rec ($) { my $length = $psect{$nam}{LENGTH}; my $end = $length ? $start + $length - 1 : $start; $program{END}{ADDRESS} = $end if $end > $program{END}{ADDRESS}; - printf $LOG "..PSECT[%d](%s) START=%06o END=%06o LENGTH=%06o\n", + printf $LOG "....PSECT[%02d](%s) START=%06o END=%06o LENGTH=%06o\n", $psect{$nam}{NUMBER}, $nam, $start, $end, $length if $length && $DEBUG; } - $program{START}{ADDRESS} = $program{START}{VALUE} + $psect{$program{START}{PSECT}}{START}; - printf $LOG "..PROG(ADDRESS) START=%06o END=%06o\n", + if ($program{START}{ADDRESS} == 1) { + $program{START}{ADDRESS} = $program{START}{VALUE} + $psect{$program{START}{PSECT}}{START}; + } + printf $LOG "\n....PROG(ADDRESS) START=%06o END=%06o\n", $program{START}{ADDRESS}, $program{END}{ADDRESS} if $DEBUG; } elsif ($key == 003) { # TXT @@ -814,6 +818,68 @@ sub parse_rec ($) { printf $LOG "..RLD(IR): adr=%06o val=%06o ; dis=%06o con=%06o\n", $adr, $val, $dis, $con if $DEBUG; $i += 4; + } elsif ($ent == 003) { + # internal displaced relocation ... OK + my $dis = $rec->[$i+1]; + my $con = ($rec->[$i+3]<<8)|($rec->[$i+2]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($con - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(IDR): adr=%06o val=%06o ; dis=%06o con=%06o\n", + $adr, $val, $dis, $con if $DEBUG; + $i += 4; + } elsif ($ent == 012) { + # psect relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START}); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", + $adr, $val, $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 014) { + # psect displaced relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PDR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", + $adr, $val, $dis, $nam if $DEBUG; + $i += 6; + } elsif ($ent == 015) { + # psect additive relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} + $con); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PAR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", + $adr, $val, $dis, $con, $nam if $DEBUG; + $i += 8; + } elsif ($ent == 016) { + # psect additive displaced relocation ... OK + my $dis = $rec->[$i+1]; + my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); + # process + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($psect{$nam}{START} + $con - ($adr+2)); + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + printf $LOG "..RLD(PADR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", + $adr, $val, $dis, $con, $nam if $DEBUG; + $i += 8; } elsif ($ent == 002) { # global relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my $dis = $rec->[$i+1]; @@ -822,18 +888,6 @@ sub parse_rec ($) { printf $LOG "..RLD(GR): dis=%06o nam='%s'\n", $dis, $nam if $DEBUG; $i += 6; - } elsif ($ent == 003) { - # internal displaced ... OK - my $dis = $rec->[$i+1]; - my $con = ($rec->[$i+3]<<8)|($rec->[$i+2]<<0); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($con - ($adr+2)); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(ID): adr=%06o val=%06o ; dis=%06o con=%06o\n", - $adr, $val, $dis, $con if $DEBUG; - $i += 4; } elsif ($ent == 004) { # global displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my $dis = $rec->[$i+1]; @@ -898,56 +952,6 @@ sub parse_rec ($) { printf $LOG "..RLD(LIM2): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; $i += 2; - } elsif ($ent == 012) { - # psect relocation ... OK - my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START}); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", - $adr, $val, $dis, $nam if $DEBUG; - $i += 6; - } elsif ($ent == 014) { - # psect displaced relocation ... OK - my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START} - ($adr+2)); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PDR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", - $adr, $val, $dis, $nam if $DEBUG; - $i += 6; - } elsif ($ent == 015) { - # psect additive relocation ... OK - my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); - my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START} + $con); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PAR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", - $adr, $val, $dis, $con, $nam if $DEBUG; - $i += 8; - } elsif ($ent == 016) { - # psect additive displaced relocation ... OK - my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); - my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); - # process - my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($psect{$nam}{START} + $con - ($adr+2)); - $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); - $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); - printf $LOG "..RLD(PADR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", - $adr, $val, $dis, $con, $nam if $DEBUG; - $i += 8; } elsif ($ent == 017) { # complex relocation ... OK my $dis = $rec->[$i+1]; @@ -1034,7 +1038,7 @@ sub parse_rec ($) { $stk[-1] = $datmsk & $stk[-1] if @stk; printf $LOG "....OPC=%-20s STK=(%s)\n", $opc, join(",",map(sprintf("%o",$_),@stk)) if $DEBUG; } - printf $LOG "..RLD(CMPX): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; + printf $LOG "..RLD(CPXR): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; } else { die sprintf("Error: Unknown RLD entry 0%o (%d)", $ent, $ent); } From 90261543f47a186714665cdb6ddfef0767424e9c Mon Sep 17 00:00:00 2001 From: AK6DN Date: Fri, 7 Apr 2017 13:29:59 -0700 Subject: [PATCH 011/174] Updated readme file --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b0409f6..e0de6d7 100644 --- a/README.md +++ b/README.md @@ -142,4 +142,5 @@ HISTORY 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 ``` From 364bd9603ef3177422e4dfc7c1a5473c67ac989c Mon Sep 17 00:00:00 2001 From: AK6DN Date: Sat, 8 Apr 2017 00:04:35 -0700 Subject: [PATCH 012/174] Add debugging output for global symbol evaluation --- obj2bin.pl | 123 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 50 deletions(-) diff --git a/obj2bin.pl b/obj2bin.pl index 983cfa7..2aaa1a1 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -291,8 +291,9 @@ sub trim ($); sub chksum (@); sub rad2asc (@); sub crc (%); +sub sym2psect ($$); sub read_rec ($); -sub parse_rec ($); +sub parse_rec ($$$); #---------------------------------------------------------------------------------------------------- @@ -363,7 +364,7 @@ my %gblsym = (); my %psect = (); my @psect = (); my %program = (); -my $psectname = '. ABS.'; +my $psectname = sprintf("%02d:%s",1,'. ABS.'); my $psectaddr = 0; my $psectnumb = -1; my $textaddr = 0; @@ -371,20 +372,18 @@ my $textaddr = 0; # program defaults $program{START}{ADDRESS} = 1; $program{START}{VALUE} = 1; -$program{START}{PSECT} = '. ABS.'; +$program{START}{PSECT} = $psectname; -# process all object files -while (my $objfile = shift(@ARGV)) { - - # open the input .obj file, die if error - my $OBJ = FileHandle->new("< ".$objfile); - die "Error: can't open input object file '$objfile'\n" unless defined $OBJ; - - # now parse all the records - while (my @rec = &read_rec($OBJ)) { &parse_rec(\@rec); } - - # done with object file - $OBJ->close; +# two passes, first is headers, second is data records +foreach my $pass (1..2) { + foreach my $numb (0..$#ARGV) { + my $objfile = $ARGV[$numb]; + my $OBJ = FileHandle->new("< ".$objfile); + die "Error: can't open input object file '$objfile'\n" unless defined $OBJ; + printf $LOG "\n\nPROCESS PASS %d FILE %d '%s'\n\n", $pass, $numb+1, $objfile if $DEBUG; + while (my @rec = &read_rec($OBJ)) { &parse_rec($numb+1, $pass, \@rec); } + $OBJ->close; + } } #---------------------------------------------------------------------------------------------------- @@ -574,6 +573,15 @@ sub rad2asc (@) { #---------------------------------------------------------------------------------------------------- +# symbol to psect name converter + +sub sym2psect ($$) { + + return sprintf("%02d:%-6s", @_); +} + +#---------------------------------------------------------------------------------------------------- + # crc computation routine sub crc (%) { @@ -669,7 +677,7 @@ sub read_rec ($) { push(@suf, ord($buf)); # output the record if debugging - if ($DEBUG) { + if ($DEBUG >= 2) { my $fmt = "%03o"; my $n = 16; my $pre = sprintf("RECORD: [%s] ",join(" ",map(sprintf($fmt,$_),@pre))); @@ -698,34 +706,37 @@ sub read_rec ($) { # parse an input object file record, update data structures -sub parse_rec ($) { +sub parse_rec ($$$) { - my ($rec) = (@_); + my ($file,$pass,$rec) = (@_); # type is first byte of record my $key = $rec->[0]; - if ($key == 001) { # GSD + if ($key == 001 && $pass == 1) { # GSD # iterate over GSD subrecords for (my $i = 2; $i < scalar(@$rec); ) { # GSD records are fixed 8B length all in the same format - my $nam = &rad2asc(($rec->[$i+1]<<8)|($rec->[$i+0]<<0), ($rec->[$i+3]<<8)|($rec->[$i+2]<<0)); + my $sym = &rad2asc(($rec->[$i+1]<<8)|($rec->[$i+0]<<0),($rec->[$i+3]<<8)|($rec->[$i+2]<<0)); + my $nam = &sym2psect($file,$sym); my $flg = $rec->[$i+4]; my $ent = $rec->[$i+5]; my $val = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); my @ent = ('MODULE','CSECT','INTSYM','XFRADR','GBLSYM','PSECT','IDENT','VSECT'); + my $def = undef; if ($ent == 3) { # XFRADR $program{START}{PSECT} = $nam; $program{START}{VALUE} = $val; } elsif ($ent == 4) { # GBLSYM flags - $gblsym{$nam}{FLG}{$flg&(1<<0) ? "WEA" : "STR"}++; - $gblsym{$nam}{FLG}{$flg&(1<<3) ? "DEF" : "REF"}++; - $gblsym{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; - $gblsym{$nam}{PSECT} = $psectname; - $gblsym{$nam}{VALUE} = $val; + $def = $flg&(1<<3) ? "DEF" : "REF"; + $gblsym{$sym}{$def}{FLG}{$flg&(1<<0) ? "WEA" : "STR"}++; + $gblsym{$sym}{$def}{FLG}{$flg&(1<<3) ? "DEF" : "REF"}++; + $gblsym{$sym}{$def}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; + $gblsym{$sym}{$def}{PSECT} = $psectname; + $gblsym{$sym}{$def}{VALUE} = $val; } elsif ($ent == 5) { # PSECT flags $psect[++$psectnumb] = $nam; @@ -747,15 +758,17 @@ sub parse_rec ($) { } } if ($DEBUG) { - printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, $nam, $val; - printf $LOG " flags=%s", join(",", sort(keys(%{$gblsym{$nam}{FLG}}))) if $ent == 4; + printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, ($ent == 4 ? $sym : $nam), $val; + printf $LOG " psect='%s' value=%06o", $gblsym{$sym}{$def}{PSECT}, $gblsym{$sym}{$def}{VALUE} if $ent == 4; + printf $LOG " length=%06o start=%06o", $psect{$nam}{LENGTH}, $psect{$nam}{START} if $ent == 5; + printf $LOG " flags=%s", join(",", sort(keys(%{$gblsym{$sym}{$def}{FLG}}))) if $ent == 4; printf $LOG " flags=%s", join(",", sort(keys(%{$psect{$nam}{FLG}}))) if $ent == 5; printf $LOG "\n"; } $i += 8; } - } elsif ($key == 002) { # ENDGSD + } elsif ($key == 002 && $pass == 1) { # ENDGSD # just say we saw it printf $LOG "..ENDGSD\n\n" if $DEBUG; @@ -769,13 +782,23 @@ sub parse_rec ($) { printf $LOG "....PSECT[%02d](%s) START=%06o END=%06o LENGTH=%06o\n", $psect{$nam}{NUMBER}, $nam, $start, $end, $length if $length && $DEBUG; } + + printf $LOG "\n"; + foreach my $nam (sort(keys(%gblsym))) { + if (exists $gblsym{$nam}{DEF}) { + my $address = $gblsym{$nam}{DEF}{VALUE} + $psect{$gblsym{$nam}{DEF}{PSECT}}{START}; + printf $LOG "....GBLSYM(%s) PSECT='%s' VALUE=%06o : ADDRESS=%06o\n", + $nam, $gblsym{$nam}{DEF}{PSECT}, $gblsym{$nam}{DEF}{VALUE}, $address if $DEBUG; + } + } + if ($program{START}{ADDRESS} == 1) { $program{START}{ADDRESS} = $program{START}{VALUE} + $psect{$program{START}{PSECT}}{START}; } printf $LOG "\n....PROG(ADDRESS) START=%06o END=%06o\n", $program{START}{ADDRESS}, $program{END}{ADDRESS} if $DEBUG; - } elsif ($key == 003) { # TXT + } elsif ($key == 003 && $pass == 2) { # TXT # process text record my $off = ($rec->[3]<<8)|($rec->[2]<<0); @@ -798,7 +821,7 @@ sub parse_rec ($) { $adrmax = $adr+$len-1 if $adrmax eq '' || $adr+$len-1 > $adrmax; $textaddr = $adr; - } elsif ($key == 004) { # RLD + } elsif ($key == 004 && $pass == 2) { # RLD # iterate over RLD subrecords for (my $i = 2; $i < scalar(@$rec); ) { @@ -833,7 +856,7 @@ sub parse_rec ($) { } elsif ($ent == 012) { # psect relocation ... OK my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $nam = &sym2psect($file,&rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0))); # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($psect{$nam}{START}); @@ -845,7 +868,7 @@ sub parse_rec ($) { } elsif ($ent == 014) { # psect displaced relocation ... OK my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $nam = &sym2psect($file,&rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0))); # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($psect{$nam}{START} - ($adr+2)); @@ -857,7 +880,7 @@ sub parse_rec ($) { } elsif ($ent == 015) { # psect additive relocation ... OK my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $nam = &sym2psect($file,&rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0))); my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process my $adr = $adrmsk & ($textaddr + $dis - 4); @@ -870,7 +893,7 @@ sub parse_rec ($) { } elsif ($ent == 016) { # psect additive displaced relocation ... OK my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $nam = &sym2psect($file,&rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0))); my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process my $adr = $adrmsk & ($textaddr + $dis - 4); @@ -883,41 +906,41 @@ sub parse_rec ($) { } elsif ($ent == 002) { # global relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); # process - printf $LOG "..RLD(GR): dis=%06o nam='%s'\n", - $dis, $nam if $DEBUG; + printf $LOG "..RLD(GR): adr=?????? val=?????? ; dis=%06o sym='%s'\n", + $dis, $sym if $DEBUG; $i += 6; } elsif ($ent == 004) { # global displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); # process - printf $LOG "..RLD(GDR): dis=%06o nam='%s'\n", - $dis, $nam if $DEBUG; + printf $LOG "..RLD(GDR): adr=?????? val=?????? ; dis=%06o sym='%s'\n", + $dis, $sym if $DEBUG; $i += 6; } elsif ($ent == 005) { # global additive relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process - printf $LOG "..RLD(GAR): dis=%06o con=%06o nam='%s'\n", - $dis, $con, $nam if $DEBUG; + printf $LOG "..RLD(GAR): adr=?????? val=?????? ; dis=%06o con=%06o sym='%s'\n", + $dis, $con, $sym if $DEBUG; $i += 8; } elsif ($ent == 006) { # global additive displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process - printf $LOG "..RLD(GADR): dis=%06o con=%06o nam='%s'\n", - $dis, $con, $nam if $DEBUG; + printf $LOG "..RLD(GADR): adr=?????? val=?????? ; dis=%06o con=%06o sym='%s'\n", + $dis, $con, $sym if $DEBUG; $i += 8; } elsif ($ent == 007) { # location counter definition ... OK my $dis = $rec->[$i+1]; - my $nam = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0), ($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); + my $nam = &sym2psect($file,&rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0))); my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process $psectname = $nam; @@ -955,7 +978,7 @@ sub parse_rec ($) { } elsif ($ent == 017) { # complex relocation ... OK my $dis = $rec->[$i+1]; - my $nam = '. ABS.'; + my $nam = &sym2psect($file,'. ABS.'); my $con = 0; # process my $adr = $adrmsk & ($textaddr + $dis - 4); @@ -1018,7 +1041,7 @@ sub parse_rec ($) { ############## may need tweaking ################ $nam = &rad2asc(($rec->[$i+2]<<8)|($rec->[$i+1]<<0), ($rec->[$i+4]<<8)|($rec->[$i+3]<<0)); - $con = $gblsym{$nam}{VALUE}; + $con = $gblsym{$nam}{DEF}{VALUE}; push(@stk, $con); $opc = sprintf("GLB[%s]=(%o)", &trim($nam), $con); $i += 4; @@ -1064,7 +1087,7 @@ sub parse_rec ($) { # ignore printf $LOG "..LIBEND: ignored\n" if $DEBUG; - } else { # unknown + } elsif ($key == 000 || $key >= 011) { # unknown # invalid record type in the object file die sprintf("Error: unknown record type 0%o (%d)", $key, $key); From c4f9db5d8f17c47ae57b175b52f0f3e46214b085 Mon Sep 17 00:00:00 2001 From: AK6DN Date: Sat, 8 Apr 2017 02:49:22 -0700 Subject: [PATCH 013/174] First version with support for multiple .obj files and linking global symbols -- preliminary, lightly tested --- obj2bin.pl | 77 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/obj2bin.pl b/obj2bin.pl index 2aaa1a1..a645aac 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -783,12 +783,12 @@ sub parse_rec ($$$) { $psect{$nam}{NUMBER}, $nam, $start, $end, $length if $length && $DEBUG; } - printf $LOG "\n"; + printf $LOG "\n" if $DEBUG; foreach my $nam (sort(keys(%gblsym))) { if (exists $gblsym{$nam}{DEF}) { - my $address = $gblsym{$nam}{DEF}{VALUE} + $psect{$gblsym{$nam}{DEF}{PSECT}}{START}; + $gblsym{$nam}{DEF}{ADDRESS} = $gblsym{$nam}{DEF}{VALUE} + $psect{$gblsym{$nam}{DEF}{PSECT}}{START}; printf $LOG "....GBLSYM(%s) PSECT='%s' VALUE=%06o : ADDRESS=%06o\n", - $nam, $gblsym{$nam}{DEF}{PSECT}, $gblsym{$nam}{DEF}{VALUE}, $address if $DEBUG; + $nam, $gblsym{$nam}{DEF}{PSECT}, $gblsym{$nam}{DEF}{VALUE}, $gblsym{$nam}{DEF}{ADDRESS} if $DEBUG; } } @@ -836,8 +836,10 @@ sub parse_rec ($$$) { # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($psect{$psectname}{START} + $con); + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(IR): adr=%06o val=%06o ; dis=%06o con=%06o\n", $adr, $val, $dis, $con if $DEBUG; $i += 4; @@ -848,8 +850,10 @@ sub parse_rec ($$$) { # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($con - ($adr+2)); + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(IDR): adr=%06o val=%06o ; dis=%06o con=%06o\n", $adr, $val, $dis, $con if $DEBUG; $i += 4; @@ -860,8 +864,10 @@ sub parse_rec ($$$) { # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($psect{$nam}{START}); + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(PR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", $adr, $val, $dis, $nam if $DEBUG; $i += 6; @@ -872,8 +878,10 @@ sub parse_rec ($$$) { # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($psect{$nam}{START} - ($adr+2)); + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(PDR): adr=%06o val=%06o ; dis=%06o nam='%s'\n", $adr, $val, $dis, $nam if $DEBUG; $i += 6; @@ -885,8 +893,10 @@ sub parse_rec ($$$) { # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($psect{$nam}{START} + $con); + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(PAR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", $adr, $val, $dis, $con, $nam if $DEBUG; $i += 8; @@ -898,44 +908,70 @@ sub parse_rec ($$$) { # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ($psect{$nam}{START} + $con - ($adr+2)); + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(PADR): adr=%06o val=%06o ; dis=%06o con=%06o nam='%s'\n", $adr, $val, $dis, $con, $nam if $DEBUG; $i += 8; } elsif ($ent == 002) { - # global relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + # global relocation ... OK my $dis = $rec->[$i+1]; my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); # process - printf $LOG "..RLD(GR): adr=?????? val=?????? ; dis=%06o sym='%s'\n", - $dis, $sym if $DEBUG; + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS}); + # store + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print + printf $LOG "..RLD(GR): adr=%06o val=%06o ; dis=%06o sym='%s'\n", + $adr, $val, $dis, $sym if $DEBUG; $i += 6; } elsif ($ent == 004) { - # global displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + # global displaced relocation ... OK my $dis = $rec->[$i+1]; my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); # process - printf $LOG "..RLD(GDR): adr=?????? val=?????? ; dis=%06o sym='%s'\n", - $dis, $sym if $DEBUG; + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS} - ($adr+2)); + # store + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print + printf $LOG "..RLD(GDR): adr=%06o val=%06o ; dis=%06o sym='%s'\n", + $adr, $val, $dis, $sym if $DEBUG; $i += 6; } elsif ($ent == 005) { - # global additive relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + # global additive relocation ... OK my $dis = $rec->[$i+1]; my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process - printf $LOG "..RLD(GAR): adr=?????? val=?????? ; dis=%06o con=%06o sym='%s'\n", - $dis, $con, $sym if $DEBUG; + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS} + $con); + # store + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print + printf $LOG "..RLD(GAR): adr=%06o val=%06o ; dis=%06o con=%06o sym='%s'\n", + $adr, $val, $dis, $con, $sym if $DEBUG; $i += 8; } elsif ($ent == 006) { - # global additive displaced relocation ... TBD <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + # global additive displaced relocation ... OK my $dis = $rec->[$i+1]; my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process - printf $LOG "..RLD(GADR): adr=?????? val=?????? ; dis=%06o con=%06o sym='%s'\n", - $dis, $con, $sym if $DEBUG; + my $adr = $adrmsk & ($textaddr + $dis - 4); + my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS} + $con - ($adr+2)); + # store + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print + printf $LOG "..RLD(GADR): adr=%06o val=%06o ; dis=%06o con=%06o sym='%s'\n", + $adr, $val, $dis, $con, $sym if $DEBUG; $i += 8; } elsif ($ent == 007) { # location counter definition ... OK @@ -945,6 +981,7 @@ sub parse_rec ($$$) { # process $psectname = $nam; $textaddr = $datmsk & ($con); + # print printf $LOG "..RLD(LCD): adr=%06o ; dis=%06o con=%06o nam='%s'\n", $textaddr, $dis, $con, $nam if $DEBUG; $i += 8; @@ -954,6 +991,7 @@ sub parse_rec ($$$) { my $con = ($rec->[$i+3]<<8)|($rec->[$i+2]<<0); # process $textaddr = $datmsk & ($con); + # print printf $LOG "..RLD(LCM): adr=%06o ; dis=%06o con=%06o\n", $textaddr, $dis, $con if $DEBUG; $i += 4; @@ -963,15 +1001,20 @@ sub parse_rec ($$$) { # process my $adr = $adrmsk & ($textaddr + $dis - 4); my $val = $datmsk & ( 01000 ); # make this up, no easy way to compute it + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(LIM1): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; + # process $dis += 2; $adr += 2; $val = $datmsk & ($program{END}{ADDRESS}); + # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); + # print printf $LOG "..RLD(LIM2): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; $i += 2; @@ -1032,13 +1075,13 @@ sub parse_rec ($$$) { $opc = "STO"; $dun = 1; } elsif ($rec->[$i] == 013) { - ############## may need tweaking ################ + ############## may need tweaking ################ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my @arg = splice(@stk,-1,1); $val = $arg[0]; $opc = "STO+DIS"; $dun = 1; } elsif ($rec->[$i] == 016) { - ############## may need tweaking ################ + ############## may need tweaking ################ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $nam = &rad2asc(($rec->[$i+2]<<8)|($rec->[$i+1]<<0), ($rec->[$i+4]<<8)|($rec->[$i+3]<<0)); $con = $gblsym{$nam}{DEF}{VALUE}; From ac453f8a0b4cf0883613c25cb04cb20c5cfc7eee Mon Sep 17 00:00:00 2001 From: AK6DN Date: Sat, 8 Apr 2017 14:29:46 -0700 Subject: [PATCH 014/174] Added global symbol redefinition/undefined warnings; reformat debug output; change some die to warn --- obj2bin.pl | 58 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/obj2bin.pl b/obj2bin.pl index a645aac..85cdd8c 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -293,6 +293,7 @@ sub rad2asc (@); sub crc (%); sub sym2psect ($$); sub read_rec ($); +sub get_global ($); sub parse_rec ($$$); #---------------------------------------------------------------------------------------------------- @@ -692,11 +693,11 @@ sub read_rec ($) { } # check we have a well formatted record - die sprintf("Error: invalid object file record format (%d)", $err) if $err; + warn sprintf("Warning: 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; + warn sprintf("Warning: Bad checksum exp=0x%02X rcv=0x%02X", $exp, $rcv) unless $exp == $rcv; # all is well, return the record return @dat; @@ -704,6 +705,24 @@ sub read_rec ($) { #---------------------------------------------------------------------------------------------------- +# get a global symbol target value + +sub get_global ($) { + + my ($sym) = @_; + + # return target value if exists + return $gblsym{$sym}{DEF}{ADDRESS} if exists $gblsym{$sym}{DEF}{ADDRESS}; + + # issue a warning for multiple definition with a different address + warn sprintf("Warning: global symbol undefined: symbol=%s, assuming value of 000000\n", $sym); + + # and return nil + return 0; +} + +#---------------------------------------------------------------------------------------------------- + # parse an input object file record, update data structures sub parse_rec ($$$) { @@ -731,12 +750,21 @@ sub parse_rec ($$$) { $program{START}{VALUE} = $val; } elsif ($ent == 4) { # GBLSYM flags + my $adr = $val + $psect{$psectname}{START}; $def = $flg&(1<<3) ? "DEF" : "REF"; - $gblsym{$sym}{$def}{FLG}{$flg&(1<<0) ? "WEA" : "STR"}++; - $gblsym{$sym}{$def}{FLG}{$flg&(1<<3) ? "DEF" : "REF"}++; - $gblsym{$sym}{$def}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; - $gblsym{$sym}{$def}{PSECT} = $psectname; - $gblsym{$sym}{$def}{VALUE} = $val; + if ($def eq "DEF" && exists $gblsym{$sym}{$def} && $adr != $gblsym{$sym}{$def}{ADDRESS}) { + # issue a warning for multiple definition with a different address + warn sprintf("Warning: attempted global symbol redefinition: symbol=%s (address/psect) old=%06o/%s new=%06o/%s -- IGNORING\n", + &trim($sym), $gblsym{$sym}{$def}{ADDRESS}, &trim($gblsym{$sym}{$def}{PSECT}), $adr, &trim($psectname)); + } else { + # define first time only ... ignore any redefinition attempt + $gblsym{$sym}{$def}{FLG}{$flg&(1<<0) ? "WEA" : "STR"}++; + $gblsym{$sym}{$def}{FLG}{$flg&(1<<3) ? "DEF" : "REF"}++; + $gblsym{$sym}{$def}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; + $gblsym{$sym}{$def}{PSECT} = $psectname; + $gblsym{$sym}{$def}{VALUE} = $val; + $gblsym{$sym}{$def}{ADDRESS} = $adr; + } } elsif ($ent == 5) { # PSECT flags $psect[++$psectnumb] = $nam; @@ -786,7 +814,6 @@ sub parse_rec ($$$) { printf $LOG "\n" if $DEBUG; foreach my $nam (sort(keys(%gblsym))) { if (exists $gblsym{$nam}{DEF}) { - $gblsym{$nam}{DEF}{ADDRESS} = $gblsym{$nam}{DEF}{VALUE} + $psect{$gblsym{$nam}{DEF}{PSECT}}{START}; printf $LOG "....GBLSYM(%s) PSECT='%s' VALUE=%06o : ADDRESS=%06o\n", $nam, $gblsym{$nam}{DEF}{PSECT}, $gblsym{$nam}{DEF}{VALUE}, $gblsym{$nam}{DEF}{ADDRESS} if $DEBUG; } @@ -921,7 +948,7 @@ sub parse_rec ($$$) { my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); # process my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS}); + my $val = $datmsk & (&get_global($sym)); # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); @@ -935,7 +962,7 @@ sub parse_rec ($$$) { my $sym = &rad2asc(($rec->[$i+3]<<8)|($rec->[$i+2]<<0),($rec->[$i+5]<<8)|($rec->[$i+4]<<0)); # process my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS} - ($adr+2)); + my $val = $datmsk & (&get_global($sym) - ($adr+2)); # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); @@ -950,7 +977,7 @@ sub parse_rec ($$$) { my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS} + $con); + my $val = $datmsk & (&get_global($sym) + $con); # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); @@ -965,7 +992,7 @@ sub parse_rec ($$$) { my $con = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); # process my $adr = $adrmsk & ($textaddr + $dis - 4); - my $val = $datmsk & ($gblsym{$sym}{DEF}{ADDRESS} + $con - ($adr+2)); + my $val = $datmsk & (&get_global($sym) + $con - ($adr+2)); # store $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); @@ -1070,6 +1097,7 @@ sub parse_rec ($$$) { push(@stk, ~$arg[0]); $opc = "COM"; } elsif ($rec->[$i] == 012) { + ############## may need tweaking ################ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< my @arg = splice(@stk,-1,1); $val = $arg[0]; $opc = "STO"; @@ -1084,7 +1112,7 @@ sub parse_rec ($$$) { ############## may need tweaking ################ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $nam = &rad2asc(($rec->[$i+2]<<8)|($rec->[$i+1]<<0), ($rec->[$i+4]<<8)|($rec->[$i+3]<<0)); - $con = $gblsym{$nam}{DEF}{VALUE}; + $con = &get_global($nam); push(@stk, $con); $opc = sprintf("GLB[%s]=(%o)", &trim($nam), $con); $i += 4; @@ -1106,7 +1134,7 @@ sub parse_rec ($$$) { } printf $LOG "..RLD(CPXR): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; } else { - die sprintf("Error: Unknown RLD entry 0%o (%d)", $ent, $ent); + warn sprintf("Warning: Unknown RLD entry 0%o (%d)", $ent, $ent); } } @@ -1133,7 +1161,7 @@ sub parse_rec ($$$) { } elsif ($key == 000 || $key >= 011) { # unknown # invalid record type in the object file - die sprintf("Error: unknown record type 0%o (%d)", $key, $key); + warn sprintf("Warning: unknown record type 0%o (%d)", $key, $key); } From f58c4268f95386ee5171eb97e0e8b575264dca2f Mon Sep 17 00:00:00 2001 From: AK6DN Date: Sat, 8 Apr 2017 22:46:48 -0700 Subject: [PATCH 015/174] Update complex relocation evaluation so that it now works, and stores correct value at correct location --- obj2bin.pl | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/obj2bin.pl b/obj2bin.pl index 85cdd8c..26452cb 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -1051,7 +1051,7 @@ sub parse_rec ($$$) { my $nam = &sym2psect($file,'. ABS.'); my $con = 0; # process - my $adr = $adrmsk & ($textaddr + $dis - 4); + my $adr = 0; my $loc = 0; my $val = 0; my $opc = ""; @@ -1059,64 +1059,76 @@ sub parse_rec ($$$) { my $dun = 0; for ($i += 2; !$dun; $i += 1) { if ($rec->[$i] == 000) { + # NOP do nothing $opc = "NOP"; } elsif ($rec->[$i] == 001) { + # ADD : pop + pop => push my @arg = splice(@stk,-2,2); push(@stk, $arg[0] + $arg[1]); $opc = "ADD"; } elsif ($rec->[$i] == 002) { + # SUB : pop - pop => push my @arg = splice(@stk,-2,2); push(@stk, $arg[0] - $arg[1]); $opc = "SUB"; } elsif ($rec->[$i] == 003) { + # MUL : pop * pop => push my @arg = splice(@stk,-2,2); push(@stk, $arg[0] * $arg[1]); $opc = "MUL"; } elsif ($rec->[$i] == 004) { + # DIV : pop / pop => push my @arg = splice(@stk,-2,2); push(@stk, $arg[1] == 0 ? 0 : int($arg[0] / $arg[1])); $opc = "DIV"; } elsif ($rec->[$i] == 005) { + # AND : pop & pop => push my @arg = splice(@stk,-2,2); push(@stk, $arg[0] & $arg[1]); $opc = "AND"; } elsif ($rec->[$i] == 006) { + # IOR : pop | pop => push my @arg = splice(@stk,-2,2); push(@stk, $arg[0] | $arg[1]); $opc = "IOR"; } elsif ($rec->[$i] == 007) { + # XOR : pop ^ pop => push my @arg = splice(@stk,-2,2); push(@stk, $arg[0] ^ $arg[1]); $opc = "XOR"; } elsif ($rec->[$i] == 010) { + # NEG : pop - => push my @arg = splice(@stk,-1,1); push(@stk, -$arg[0]); $opc = "NEG"; } elsif ($rec->[$i] == 011) { + # COM : pop ~ => push my @arg = splice(@stk,-1,1); push(@stk, ~$arg[0]); $opc = "COM"; } elsif ($rec->[$i] == 012) { - ############## may need tweaking ################ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + # STO : pop => store @ address my @arg = splice(@stk,-1,1); - $val = $arg[0]; + $adr = $adrmsk & ($textaddr + $dis - 4); + $val = $datmsk & ($arg[0]); $opc = "STO"; $dun = 1; } elsif ($rec->[$i] == 013) { - ############## may need tweaking ################ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + # STO : pop => store @ address + disp my @arg = splice(@stk,-1,1); - $val = $arg[0]; + $adr = $adrmsk & ($textaddr + $dis - 4); + $val = $datmsk & ($arg[0] - ($adr+2)); $opc = "STO+DIS"; $dun = 1; } elsif ($rec->[$i] == 016) { - ############## may need tweaking ################ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - $nam = &rad2asc(($rec->[$i+2]<<8)|($rec->[$i+1]<<0), - ($rec->[$i+4]<<8)|($rec->[$i+3]<<0)); + # FET : global => push + $nam = &rad2asc(($rec->[$i+2]<<8)|($rec->[$i+1]<<0),($rec->[$i+4]<<8)|($rec->[$i+3]<<0)); $con = &get_global($nam); push(@stk, $con); $opc = sprintf("GLB[%s]=(%o)", &trim($nam), $con); $i += 4; } elsif ($rec->[$i] == 017) { + # FET : local => push $nam = $psect[$rec->[$i+1]]; $con = ($rec->[$i+3]<<8) | ($rec->[$i+2]<<0); $loc = $psect{$nam}{START} + $con; @@ -1124,6 +1136,7 @@ sub parse_rec ($$$) { $opc = sprintf("FET[%s+%o]=(%o)", &trim($nam), $con, $loc); $i += 3; } elsif ($rec->[$i] == 020) { + # CONstant : value => push $con = ($rec->[$i+2]<<8) | ($rec->[$i+1]<<0); push(@stk, $con); $opc = "CON"; @@ -1132,7 +1145,11 @@ sub parse_rec ($$$) { $stk[-1] = $datmsk & $stk[-1] if @stk; printf $LOG "....OPC=%-20s STK=(%s)\n", $opc, join(",",map(sprintf("%o",$_),@stk)) if $DEBUG; } + # print printf $LOG "..RLD(CPXR): adr=%06o val=%06o ; dis=%06o\n", $adr, $val, $dis if $DEBUG; + # store + $mem[($adr+0)&$adrmsk] = $memmsk & ($val>>0); + $mem[($adr+1)&$adrmsk] = $memmsk & ($val>>8); } else { warn sprintf("Warning: Unknown RLD entry 0%o (%d)", $ent, $ent); } From 688828abd09dadd15258fe9c3e585a3a48c55a26 Mon Sep 17 00:00:00 2001 From: AK6DN Date: Sun, 9 Apr 2017 17:55:34 -0700 Subject: [PATCH 016/174] Always block out a psect length to be even --- obj2bin.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/obj2bin.pl b/obj2bin.pl index 26452cb..312567f 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -754,7 +754,7 @@ sub parse_rec ($$$) { $def = $flg&(1<<3) ? "DEF" : "REF"; if ($def eq "DEF" && exists $gblsym{$sym}{$def} && $adr != $gblsym{$sym}{$def}{ADDRESS}) { # issue a warning for multiple definition with a different address - warn sprintf("Warning: attempted global symbol redefinition: symbol=%s (address/psect) old=%06o/%s new=%06o/%s -- IGNORING\n", + warn sprintf("Warning: global symbol redefinition: symbol=%s (address/psect) old=%06o/%s new=%06o/%s -- IGNORING\n", &trim($sym), $gblsym{$sym}{$def}{ADDRESS}, &trim($gblsym{$sym}{$def}{PSECT}), $adr, &trim($psectname)); } else { # define first time only ... ignore any redefinition attempt @@ -774,6 +774,7 @@ sub parse_rec ($$$) { $psect{$nam}{FLG}{$flg&(1<<4) ? "R/O" : "R/W"}++; $psect{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; $psect{$nam}{FLG}{$flg&(1<<7) ? "D" : "I/D"}++; + $val++ if $val & 1; if ($psect{$nam}{FLG}{CON}) { $psect{$nam}{LENGTH} = $val; $psect{$nam}{START} = $psectaddr; From e7d126f682249dd148ce50eb4a7b817e380c2aa5 Mon Sep 17 00:00:00 2001 From: AK6DN Date: Sun, 9 Apr 2017 19:41:18 -0700 Subject: [PATCH 017/174] Updated PSECT address/length processing --- obj2bin.pl | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/obj2bin.pl b/obj2bin.pl index 312567f..b9a63ee 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -774,16 +774,28 @@ sub parse_rec ($$$) { $psect{$nam}{FLG}{$flg&(1<<4) ? "R/O" : "R/W"}++; $psect{$nam}{FLG}{$flg&(1<<5) ? "REL" : "ABS"}++; $psect{$nam}{FLG}{$flg&(1<<7) ? "D" : "I/D"}++; - $val++ if $val & 1; - if ($psect{$nam}{FLG}{CON}) { - $psect{$nam}{LENGTH} = $val; - $psect{$nam}{START} = $psectaddr; - $psectname = $nam; - $psectaddr += $val; - } elsif ($psect{$nam}{FLG}{ABS}) { - $psect{$nam}{LENGTH} = $val; - $psect{$nam}{START} = 0; - $psectname = $nam; + $psectname = $nam; + if ($psect{$nam}{FLG}{ABS}) { + # absolute + if ($psect{$nam}{FLG}{CON}) { + # concatenated + warn sprintf("Warning: psect ABS,CON is not supported, psect='%s'\n", $psectname); + } else { + # overlaid + $psect{$nam}{LENGTH} = $val; + $psect{$nam}{START} = 0; + } + } else { + # relative + if ($psect{$nam}{FLG}{CON}) { + # concatenated + $psect{$nam}{LENGTH} = $val; + $psect{$nam}{START} = $psectaddr & 1 ? ++$psectaddr : $psectaddr; + $psectaddr += $val; + } else { + # overlaid + warn sprintf("Warning: psect REL,OVR is not supported, psect='%s'\n", $psectname); + } } } if ($DEBUG) { From 3d380827cbebf432260bdae75c718bb51a9e3b4a Mon Sep 17 00:00:00 2001 From: AK6DN Date: Sun, 9 Apr 2017 21:03:19 -0700 Subject: [PATCH 018/174] Minor update to psect flag processing --- obj2bin.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/obj2bin.pl b/obj2bin.pl index b9a63ee..4c6ba9f 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -780,19 +780,19 @@ sub parse_rec ($$$) { if ($psect{$nam}{FLG}{CON}) { # concatenated warn sprintf("Warning: psect ABS,CON is not supported, psect='%s'\n", $psectname); - } else { + } elsif ($psect{$nam}{FLG}{OVR}) { # overlaid $psect{$nam}{LENGTH} = $val; $psect{$nam}{START} = 0; } - } else { + } elsif ($psect{$nam}{FLG}{REL}) { # relative if ($psect{$nam}{FLG}{CON}) { # concatenated $psect{$nam}{LENGTH} = $val; $psect{$nam}{START} = $psectaddr & 1 ? ++$psectaddr : $psectaddr; $psectaddr += $val; - } else { + } elsif ($psect{$nam}{FLG}{OVR}) { # overlaid warn sprintf("Warning: psect REL,OVR is not supported, psect='%s'\n", $psectname); } From e3b33ef330421ab3b4a6ba1e3577a15bf766b890 Mon Sep 17 00:00:00 2001 From: AK6DN Date: Mon, 10 Apr 2017 00:17:00 -0700 Subject: [PATCH 019/174] Updated debug output for GSD psect processing --- obj2bin.pl | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/obj2bin.pl b/obj2bin.pl index 4c6ba9f..d501a91 100644 --- a/obj2bin.pl +++ b/obj2bin.pl @@ -738,7 +738,6 @@ sub parse_rec ($$$) { for (my $i = 2; $i < scalar(@$rec); ) { # GSD records are fixed 8B length all in the same format my $sym = &rad2asc(($rec->[$i+1]<<8)|($rec->[$i+0]<<0),($rec->[$i+3]<<8)|($rec->[$i+2]<<0)); - my $nam = &sym2psect($file,$sym); my $flg = $rec->[$i+4]; my $ent = $rec->[$i+5]; my $val = ($rec->[$i+7]<<8)|($rec->[$i+6]<<0); @@ -746,8 +745,12 @@ sub parse_rec ($$$) { my $def = undef; if ($ent == 3) { # XFRADR - $program{START}{PSECT} = $nam; + $program{START}{PSECT} = &sym2psect($file,$sym); $program{START}{VALUE} = $val; + if ($DEBUG) { + printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o\n", + $ent[$ent], $ent, $program{START}{PSECT}, $program{START}{VALUE}; + } } elsif ($ent == 4) { # GBLSYM flags my $adr = $val + $psect{$psectname}{START}; @@ -765,9 +768,16 @@ sub parse_rec ($$$) { $gblsym{$sym}{$def}{VALUE} = $val; $gblsym{$sym}{$def}{ADDRESS} = $adr; } + if ($DEBUG) { + printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, $sym, $val; + printf $LOG " psect='%s' value=%06o", $gblsym{$sym}{$def}{PSECT}, $gblsym{$sym}{$def}{VALUE}; + printf $LOG " flags=%s\n", join(",", sort(keys(%{$gblsym{$sym}{$def}{FLG}}))); + } } elsif ($ent == 5) { # PSECT flags + my $nam = &sym2psect($file,$sym); $psect[++$psectnumb] = $nam; + $psect{$nam}{FILE} = $file; $psect{$nam}{NUMBER} = $psectnumb; $psect{$nam}{FLG}{$flg&(1<<0) ? "GBL" : $flg&(1<<6) ? "GBL" : "LCL"}++; $psect{$nam}{FLG}{$flg&(1<<2) ? "OVR" : "CON"}++; @@ -797,14 +807,11 @@ sub parse_rec ($$$) { warn sprintf("Warning: psect REL,OVR is not supported, psect='%s'\n", $psectname); } } - } - if ($DEBUG) { - printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, ($ent == 4 ? $sym : $nam), $val; - printf $LOG " psect='%s' value=%06o", $gblsym{$sym}{$def}{PSECT}, $gblsym{$sym}{$def}{VALUE} if $ent == 4; - printf $LOG " length=%06o start=%06o", $psect{$nam}{LENGTH}, $psect{$nam}{START} if $ent == 5; - printf $LOG " flags=%s", join(",", sort(keys(%{$gblsym{$sym}{$def}{FLG}}))) if $ent == 4; - printf $LOG " flags=%s", join(",", sort(keys(%{$psect{$nam}{FLG}}))) if $ent == 5; - printf $LOG "\n"; + if ($DEBUG) { + printf $LOG "..GSD: type='%-6s'(%03o) name='%s' value=%06o", $ent[$ent], $ent, $nam, $val; + printf $LOG " length=%06o start=%06o", $psect{$nam}{LENGTH}, $psect{$nam}{START}; + printf $LOG " flags=%s\n", join(",", sort(keys(%{$psect{$nam}{FLG}}))); + } } $i += 8; } From c771c875cbc1ddd347a001ba9912aac6cfc6dd7b Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sun, 23 Apr 2017 13:54:13 +0200 Subject: [PATCH 020/174] Fix a use-after-free. Found by Don North. Also adjust test case to include this code. Fixes #2. --- assemble.c | 4 +++- tests/test-include.lst.ok | 7 ++++++- tests/test-include.mac | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/assemble.c b/assemble.c index b162147..a4df153 100644 --- a/assemble.c +++ b/assemble.c @@ -469,13 +469,15 @@ static int assemble( } my_searchenv(name, "INCLUDE", hitfile, sizeof(hitfile)); - free(name); if (hitfile[0] == '\0') { report(stack->top, "Unable to find .INCLUDE file \"%s\"\n", name); + free(name); return 0; } + free(name); + incl = new_file_stream(hitfile); if (incl == NULL) { report(stack->top, "Unable to open .INCLUDE file \"%s\"\n", hitfile); diff --git a/tests/test-include.lst.ok b/tests/test-include.lst.ok index a5b991f..2a1f6cf 100644 --- a/tests/test-include.lst.ok +++ b/tests/test-include.lst.ok @@ -48,7 +48,12 @@ test-include.mac:15: ***ERROR Bad .INCLUDE file name 16 .include =incl.mac= ; looks like assignment test-include.mac:17: ***ERROR Invalid expression 17 000012 000000G 000000 .include :incl.mac: ; looks like a label - 17 + 18 + 19 ; this is an error: file does not existst + 20 +test-include.mac:21: ***ERROR Unable to find .INCLUDE file "does-not-exist.mac" + 21 .include "does-not-exist.mac" + 21 Symbol table diff --git a/tests/test-include.mac b/tests/test-include.mac index 0cf5393..6b4a203 100644 --- a/tests/test-include.mac +++ b/tests/test-include.mac @@ -15,3 +15,7 @@ .include Date: Sun, 23 Apr 2017 13:51:53 +0200 Subject: [PATCH 021/174] Very simple .LIST and .NLIST implementation. Thanks to Don North. Also added a simple test. Fixes #3. --- assemble.c | 10 +++++++--- tests/RunTests | 1 + tests/test-listing.lst.ok | 26 ++++++++++++++++++++++++++ tests/test-listing.mac | 22 ++++++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 tests/test-listing.lst.ok create mode 100644 tests/test-listing.mac diff --git a/assemble.c b/assemble.c index a4df153..b20c866 100644 --- a/assemble.c +++ b/assemble.c @@ -277,12 +277,16 @@ static int assemble( case P_ENDR: case P_ENDM: case P_SBTTL: - case P_LIST: - case P_NLIST: case P_PRINT: return 1; /* Accepted, ignored. (An obvious need: get assembly listing - controls working. ) */ + controls working fully. ) */ + case P_LIST: + if (pass > 0) list_level++; + return 1; + case P_NLIST: + if (pass > 0) list_level--; + return 1; case P_IDENT: { diff --git a/tests/RunTests b/tests/RunTests index d9c28d6..b9796be 100755 --- a/tests/RunTests +++ b/tests/RunTests @@ -14,6 +14,7 @@ TESTS="test-asciz \ test-impword \ test-include \ test-jmp \ + test-listing \ test-locals \ test-macro-comma \ test-prec \ diff --git a/tests/test-listing.lst.ok b/tests/test-listing.lst.ok new file mode 100644 index 0000000..176e53e --- /dev/null +++ b/tests/test-listing.lst.ok @@ -0,0 +1,26 @@ + 1 ;;;;;; + 2 ; + 3 ; Test the (so far very basic) .LIST and .NLIST directives. + 4 ; + 5 + 6 ; This should get listed (list_level 1) + 7 .nlist + 10 ; This should get listed (list_level 1) + 11 .list + 12 ; This should get listed (list_level 2) + 13 .nlist + 14 ; This should get listed (list_level 1) + 15 .nlist + 22 ; This should get listed (list_level 1) + 22 + + +Symbol table + +. ******R 001 + + +Program sections: + +. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) + 000000 001 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/test-listing.mac b/tests/test-listing.mac new file mode 100644 index 0000000..1b8dd7d --- /dev/null +++ b/tests/test-listing.mac @@ -0,0 +1,22 @@ +;;;;;; +; +; Test the (so far very basic) .LIST and .NLIST directives. +; + +; This should get listed (list_level 1) + .nlist +; This should NOT get listed (list_level 0) + .list +; This should get listed (list_level 1) + .list +; This should get listed (list_level 2) + .nlist +; This should get listed (list_level 1) + .nlist +; This should NOT get listed (list_level 0) + .nlist +; This should NOT get listed (list_level -1) + .list +; This should NOT get listed (list_level 0) + .list +; This should get listed (list_level 1) From 96cfd4a152193fea86b71dd731a20137bdd17cba Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Wed, 26 Apr 2017 22:21:39 +0200 Subject: [PATCH 022/174] First step in the support of multiple formats of macro (or object) libraries. No test included since I don't have a distributable RSX .MLB file available at this time. --- mlb-rsx.c | 59 ++++++++++++++++++++++++++++++++++++------------------- mlb2.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 mlb2.c diff --git a/mlb-rsx.c b/mlb-rsx.c index 9e3545a..ea24046 100644 --- a/mlb-rsx.c +++ b/mlb-rsx.c @@ -156,6 +156,24 @@ DAMAGE. #include "mlb.h" #include "util.h" +static MLB *mlb_rsx_open( + char *name, + int allow_object_library); +static BUFFER *mlb_rsx_entry( + MLB *mlb, + char *name); +static void mlb_rsx_close( + MLB *mlb); +static void mlb_rsx_extract( + MLB *mlb); + +struct mlb_vtbl mlb_rsx_vtbl = { + mlb_rsx_open, + mlb_rsx_entry, + mlb_rsx_extract, + mlb_rsx_close, +}; + #define BLOCKSIZE 512 #define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8)) @@ -178,7 +196,7 @@ static void trim( /* mlb_open opens a file which is given to be a macro library. */ /* Returns NULL on failure. */ -MLB *mlb_open( +MLB *mlb_rsx_open( char *name, int allow_objlib) { @@ -189,11 +207,12 @@ MLB *mlb_open( unsigned start_block; int i; + mlb->vtbl = &mlb_rsx_vtbl; mlb->directory = NULL; mlb->fp = fopen(name, "rb"); if (mlb->fp == NULL) { - mlb_close(mlb); + mlb_rsx_close(mlb); return NULL; } @@ -201,7 +220,7 @@ MLB *mlb_open( if (fread(buff, 1, 060, mlb->fp) < 060) { fprintf(stderr, "error: can't read full header\n"); - mlb_close(mlb); + mlb_rsx_close(mlb); free(buff); return NULL; } @@ -210,8 +229,8 @@ MLB *mlb_open( if (allow_objlib && WORD(buff) == 01000) { /* Is it an object library? */ mlb->is_objlib = 1; } else if (WORD(buff) != 01001) { /* Is this really a macro library? */ - fprintf(stderr, "error: first word not correct value\n"); - mlb_close(mlb); /* Nope. */ + /* fprintf(stderr, "error: first word not correct value\n"); */ + mlb_rsx_close(mlb); /* Nope. */ return NULL; } @@ -222,7 +241,7 @@ MLB *mlb_open( directory */ if (entsize < 8) { /* Is this really a macro library? */ - mlb_close(mlb); /* Nope. */ + mlb_rsx_close(mlb); /* Nope. */ fprintf(stderr, "error: entsize too small: %d\n", entsize); return NULL; } @@ -237,7 +256,7 @@ MLB *mlb_open( /* Read the disk directory */ if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) { - mlb_close(mlb); /* Sorry, read error. */ + mlb_rsx_close(mlb); /* Sorry, read error. */ free(buff); return NULL; } @@ -306,8 +325,8 @@ MLB *mlb_open( return mlb; } -/* mlb_close discards MLB and closes the file. */ -void mlb_close( +/* mlb_rsx_close discards MLB and closes the file. */ +void mlb_rsx_close( MLB *mlb) { if (mlb) { @@ -326,10 +345,10 @@ void mlb_close( } } -/* mlb_entry returns a BUFFER containing the specified entry from the +/* mlb_rsx_entry returns a BUFFER containing the specified entry from the macro library, or NULL if not found. */ -BUFFER *mlb_entry( +BUFFER *mlb_rsx_entry( MLB *mlb, char *name) { @@ -347,17 +366,17 @@ BUFFER *mlb_entry( } if (i >= mlb->nentries) { -// fprintf(stderr, "mlb_entry: %s not found\n", name); +// fprintf(stderr, "mlb_rsx_entry: %s not found\n", name); return NULL; } fseek(mlb->fp, ent->position, SEEK_SET); -// fprintf(stderr, "mlb_entry: %s at position %ld\n", name, (long)ent->position); +// fprintf(stderr, "mlb_rsx_entry: %s at position %ld\n", name, (long)ent->position); #define MODULE_HEADER_SIZE 022 if (fread(module_header, MODULE_HEADER_SIZE, 1, mlb->fp) < 1) { -// fprintf(stderr, "mlb_entry: %s at position %lx can't read 022 bytes\n", name, (long)ent->position); +// fprintf(stderr, "mlb_rsx_entry: %s at position %lx can't read 022 bytes\n", name, (long)ent->position); return NULL; } @@ -368,10 +387,10 @@ BUFFER *mlb_entry( ent->length = (WORD(module_header + 04) << 16) + WORD(module_header + 06); ent->length -= MODULE_HEADER_SIZE; /* length is including this header */ -// fprintf(stderr, "mlb_entry: %s at position %lx length = %d\n", name, (long)ent->position, ent->length); +// fprintf(stderr, "mlb_rsx_entry: %s at position %lx length = %d\n", name, (long)ent->position, ent->length); if (module_header[02] == 1) { - fprintf(stderr, "mlb_entry: %s at position %lx deleted entry\n", name, (long)ent->position); + fprintf(stderr, "mlb_rsx_entry: %s at position %lx deleted entry\n", name, (long)ent->position); /* Deleted Entry */ return NULL; } @@ -398,7 +417,7 @@ BUFFER *mlb_entry( i = fread(bp, 1, ent->length, mlb->fp); bp += i; } else if (module_header[0] & 0x10) { -// fprintf(stderr, "mlb_entry: %s at position %lx variable length records\n", name, (long)ent->position); +// fprintf(stderr, "mlb_rsx_entry: %s at position %lx variable length records\n", name, (long)ent->position); /* Variable length records with size before them */ i = ent->length; while (i > 0) { @@ -437,7 +456,7 @@ BUFFER *mlb_entry( } } } else { -// fprintf(stderr, "mlb_entry: %s at position %lx byte stream records\n", name, (long)ent->position); +// fprintf(stderr, "mlb_rsx_entry: %s at position %lx byte stream records\n", name, (long)ent->position); for (i = 0; i < ent->length; i++) { c = fgetc(mlb->fp); /* Get macro byte */ if (c == '\r' || c == 0) /* If it's a carriage return or 0, @@ -453,7 +472,7 @@ BUFFER *mlb_entry( return buf; } -/* mlb_extract - walk thru a macro library and store its contents +/* mlb_rsx_extract - walk thru a macro library and store its contents into files in the current directory. See, I had decided not to bother writing macro library maintenance @@ -463,7 +482,7 @@ BUFFER *mlb_entry( in the file system from thence forward. */ -void mlb_extract( +void mlb_rsx_extract( MLB *mlb) { int i; diff --git a/mlb2.c b/mlb2.c new file mode 100644 index 0000000..46b9d8a --- /dev/null +++ b/mlb2.c @@ -0,0 +1,49 @@ +#include +#include +#include "mlb.h" + +MLB_VTBL *mlb_vtbls[] = { + &mlb_rsx_vtbl, + NULL +}; + +MLB *mlb_open( + char *name, + int allow_object_library) +{ + MLB_VTBL *vtbl; + MLB *mlb = NULL; + int i; + + for (i = 0; (vtbl = mlb_vtbls[i]); i++) { + mlb = vtbl->mlb_open(name, allow_object_library); + if (mlb != NULL) { + mlb->name = strdup(name); + break; + } + } + + return mlb; +} + +BUFFER *mlb_entry( + MLB *mlb, + char *name) +{ + return mlb->vtbl->mlb_entry(mlb, name); +} + +void mlb_close( + MLB *mlb) +{ + free(mlb->name); + mlb->vtbl->mlb_close(mlb); +} + +void mlb_extract( + MLB *mlb) +{ + mlb->vtbl->mlb_extract(mlb); +} + + From e4ec481d3d9d367cf3ded790402fba751de2bfff Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Thu, 27 Apr 2017 20:29:04 +0200 Subject: [PATCH 023/174] Add RT11 macro libraries. Hopefully they won't open as RSX ones, because then they still won't work. Can't test this now. --- Makefile | 2 +- macro11.c | 2 +- mlb.c => mlb-rt11.c | 51 +++++++++++++++++++++++++++++++++------------ mlb.h | 14 +++++++++++++ mlb2.c | 4 +++- 5 files changed, 57 insertions(+), 16 deletions(-) rename mlb.c => mlb-rt11.c (88%) diff --git a/Makefile b/Makefile index a330a95..52410c6 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ CFLAGS ?= -O -ggdb -std=gnu99 $(WARNS) MACRO11_SRCS = macro11.c \ assemble.c assemble_globals.c assemble_aux.c \ extree.c listing.c macros.c parse.c rept_irpc.c symbols.c \ - mlb-rsx.c object.c stream2.c util.c rad50.c + mlb2.c mlb-rsx.c mlb-rt11.c object.c stream2.c util.c rad50.c MACRO11_OBJS = $(MACRO11_SRCS:.c=.o) diff --git a/macro11.c b/macro11.c index ef50f88..e134729 100644 --- a/macro11.c +++ b/macro11.c @@ -133,7 +133,7 @@ static void print_help( printf("-h print this help\n"); printf("-l gives the listing file name (.LST)\n"); printf(" -l - enables listing to stdout.\n"); - printf("-m load RT-11 compatible macro library from which\n"); + printf("-m load RSX-11 or RT-11 compatible macro library from which\n"); printf(" .MCALLed macros can be found.\n"); printf(" Multiple allowed.\n"); printf("-o gives the object file name (.OBJ)\n"); diff --git a/mlb.c b/mlb-rt11.c similarity index 88% rename from mlb.c rename to mlb-rt11.c index b5c7d8b..36d2165 100644 --- a/mlb.c +++ b/mlb-rt11.c @@ -48,6 +48,24 @@ DAMAGE. #include "util.h" +static MLB *mlb_rt11_open( + char *name, + int allow_object_library); +static BUFFER *mlb_rt11_entry( + MLB *mlb, + char *name); +static void mlb_rt11_close( + MLB *mlb); +static void mlb_rt11_extract( + MLB *mlb); + +struct mlb_vtbl mlb_rt11_vtbl = { + mlb_rt11_open, + mlb_rt11_entry, + mlb_rt11_extract, + mlb_rt11_close, +}; + #define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8)) /* BYTEPOS calculates the byte position within the macro libray file. @@ -84,11 +102,13 @@ static void trim( *cp = 0; } -/* mlb_open opens a file which is given to be a macro library. */ +/* mlb_rt11_open opens a file which is given to be a macro library. */ /* Returns NULL on failure. */ -MLB *mlb_open( - char *name) +static +MLB *mlb_rt11_open( + char *name, + int allow_object_library) { MLB *mlb = memcheck(malloc(sizeof(MLB))); char *buff; @@ -97,24 +117,26 @@ MLB *mlb_open( unsigned start_block; int i; + (void)allow_object_library; /* This parameter is not supported */ + mlb->vtbl = &mlb_rt11_vtbl; mlb->directory = NULL; mlb->fp = fopen(name, "rb"); if (mlb->fp == NULL) { - mlb_close(mlb); + mlb_rt11_close(mlb); return NULL; } buff = memcheck(malloc(044)); /* Size of MLB library header */ if (fread(buff, 1, 044, mlb->fp) < 044) { - mlb_close(mlb); + mlb_rt11_close(mlb); free(buff); return NULL; } if (WORD(buff) != 01001) { /* Is this really a macro library? */ - mlb_close(mlb); /* Nope. */ + mlb_rt11_close(mlb); /* Nope. */ return NULL; } @@ -132,7 +154,7 @@ MLB *mlb_open( /* Read the disk directory */ if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) { - mlb_close(mlb); /* Sorry, read error. */ + mlb_rt11_close(mlb); /* Sorry, read error. */ free(buff); return NULL; } @@ -214,8 +236,9 @@ MLB *mlb_open( return mlb; } -/* mlb_close discards MLB and closes the file. */ -void mlb_close( +/* mlb_rt11_close discards MLB and closes the file. */ +static +void mlb_rt11_close( MLB *mlb) { if (mlb) { @@ -234,10 +257,11 @@ void mlb_close( } } -/* mlb_entry returns a BUFFER containing the specified entry from the +/* mlb_rt11_entry returns a BUFFER containing the specified entry from the macro library, or NULL if not found. */ -BUFFER *mlb_entry( +static +BUFFER *mlb_rt11_entry( MLB *mlb, char *name) { @@ -278,7 +302,7 @@ BUFFER *mlb_entry( return buf; } -/* mlb_extract - walk thru a macro library and store its contents +/* mlb_rt11_extract - walk thru a macro library and store its contents into files in the current directory. See, I had decided not to bother writing macro library maintenance @@ -288,7 +312,8 @@ BUFFER *mlb_entry( in the file system from thence forward. */ -void mlb_extract( +static +void mlb_rt11_extract( MLB *mlb) { int i; diff --git a/mlb.h b/mlb.h index 4d65202..e9db913 100644 --- a/mlb.h +++ b/mlb.h @@ -46,13 +46,24 @@ typedef struct mlbent { int length; } MLBENT; +struct mlb_vtbl; + typedef struct mlb { + struct mlb_vtbl *vtbl; + char *name; FILE *fp; MLBENT *directory; int nentries; int is_objlib; /* is really an object library */ } MLB; +typedef struct mlb_vtbl { + MLB *(*mlb_open)(char *name, int allow_object_library); + BUFFER *(*mlb_entry)(MLB *mlb, char *name); + void (*mlb_extract)(MLB *mlb); + void (*mlb_close)(MLB *mlb); +} MLB_VTBL; + extern MLB *mlb_open( char *name, int allow_object_library); @@ -64,4 +75,7 @@ extern void mlb_close( extern void mlb_extract( MLB *mlb); +extern struct mlb_vtbl mlb_rsx_vtbl; +extern struct mlb_vtbl mlb_rt11_vtbl; + #endif /* MLB_H */ diff --git a/mlb2.c b/mlb2.c index 46b9d8a..3f4c25f 100644 --- a/mlb2.c +++ b/mlb2.c @@ -1,9 +1,11 @@ #include #include +#include "util.h" #include "mlb.h" MLB_VTBL *mlb_vtbls[] = { &mlb_rsx_vtbl, + &mlb_rt11_vtbl, NULL }; @@ -18,7 +20,7 @@ MLB *mlb_open( for (i = 0; (vtbl = mlb_vtbls[i]); i++) { mlb = vtbl->mlb_open(name, allow_object_library); if (mlb != NULL) { - mlb->name = strdup(name); + mlb->name = memcheck(strdup(name)); break; } } From f07c9045f5bf60ccd821a33bb4ebf06d06fe7c48 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Thu, 27 Apr 2017 20:43:28 +0200 Subject: [PATCH 024/174] Prepare for macros being defined in "other ways" which are not yet put in the macro definition table. --- assemble.c | 4 ++-- macros.c | 23 ++++++++++++++--------- macros.h | 4 ++++ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/assemble.c b/assemble.c index b20c866..e1b1b9a 100644 --- a/assemble.c +++ b/assemble.c @@ -632,7 +632,7 @@ static int assemble( saveline = stmtno; list_level = -1; - mac = defmacro(maccp, &macstack, TRUE); + mac = defmacro(maccp, &macstack, CALLED_NOLIST); if (mac == NULL) { report(stack->top, "Failed to define macro " "called %s\n", label); } @@ -652,7 +652,7 @@ static int assemble( case P_MACRO: { - MACRO *mac = defmacro(cp, stack, FALSE); + MACRO *mac = defmacro(cp, stack, CALLED_NORMAL); return mac != NULL; } diff --git a/macros.c b/macros.c index 5dbc810..6b440b2 100644 --- a/macros.c +++ b/macros.c @@ -91,7 +91,8 @@ void read_body( break; } - if (!called && (list_level - 1 + list_md) > 0) { + if (!(called & CALLED_NOLIST) && + (list_level - 1 + list_md) > 0) { list_flush(); list_source(stack->top, nextline); } @@ -185,17 +186,21 @@ MACRO *defmacro( return NULL; } - /* Allow redefinition of a macro; new definition replaces the old. */ - mac = (MACRO *) lookup_sym(label, ¯o_st); - if (mac) { - /* Remove from the symbol table... */ - remove_sym(&mac->sym, ¯o_st); - free_macro(mac); + if (!(called & CALLED_NODEFINE)) { + /* Allow redefinition of a macro; new definition replaces the old. */ + mac = (MACRO *) lookup_sym(label, ¯o_st); + if (mac) { + /* Remove from the symbol table... */ + remove_sym(&mac->sym, ¯o_st); + free_macro(mac); + } } mac = new_macro(label); - add_table(&mac->sym, ¯o_st); + if (!(called & CALLED_NODEFINE)) { + add_table(&mac->sym, ¯o_st); + } argtail = &mac->args; cp = skipdelim(cp); @@ -245,7 +250,7 @@ MACRO *defmacro( gb = new_buffer(); - if (!called && !list_md) { + if (!(called & CALLED_NOLIST) && !list_md) { list_level--; levelmod = 1; } diff --git a/macros.h b/macros.h index 212ecc7..b4af2a6 100644 --- a/macros.h +++ b/macros.h @@ -46,6 +46,10 @@ MACRO *defmacro( STACK *stack, int called); +#define CALLED_NORMAL 0 +#define CALLED_NOLIST 1 +#define CALLED_NODEFINE 2 + STREAM *expandmacro( STREAM *refstr, MACRO *mac, From 65f29a6497104bac77a8767b67c1c2e9718bb83f Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Thu, 27 Apr 2017 20:44:30 +0200 Subject: [PATCH 025/174] Recognize, but ignore, the BSD m11 syntax .MCALL (macrolibname)macroname --- assemble.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/assemble.c b/assemble.c index e1b1b9a..a73b45a 100644 --- a/assemble.c +++ b/assemble.c @@ -572,6 +572,18 @@ static int assemble( if (EOL(*cp)) return 1; + /* (lib)macro syntax. Ignore (lib) for now. */ + if (*cp == '(') { + char *close = strchr(cp + 1, ')'); + + if (close != NULL) { + char *libname = cp + 1; + (void)libname; + *close = '\0'; + cp = close + 1; + } + } + label = get_symbol(cp, &cp, NULL); if (!label) { report(stack->top, "Illegal .MCALL format\n"); From d61cad6bb4ac30b27f4c9151f068da484526d257 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Thu, 27 Apr 2017 21:56:02 +0200 Subject: [PATCH 026/174] Add some tests for .BLKB .BLKW .ODD .EVEN .BLKB and .BLKW should have an argument, but if missing it is 1. .ODD and .EVEN are not allowed to have an argument. --- assemble.c | 19 ++++++++++++++++++- tests/RunTests | 1 + tests/test-blkb.lst.ok | 41 +++++++++++++++++++++++++++++++++++++++++ tests/test-blkb.mac | 25 +++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 tests/test-blkb.lst.ok create mode 100644 tests/test-blkb.mac diff --git a/assemble.c b/assemble.c index b20c866..71c7d00 100644 --- a/assemble.c +++ b/assemble.c @@ -926,6 +926,10 @@ static int assemble( return 1; case P_EVEN: + cp = skipwhite(cp); + if (!EOL(*cp)) { + report(stack->top, ".EVEN must not have an argument\n"); + } if (DOT & 1) { list_word(stack->top, DOT, 0, 1, ""); DOT++; @@ -934,6 +938,9 @@ static int assemble( return 1; case P_ODD: + if (!EOL(*cp)) { + report(stack->top, ".EVEN must not have an argument\n"); + } if (!(DOT & 1)) { list_word(stack->top, DOT, 0, 1, ""); DOT++; @@ -1121,9 +1128,19 @@ static int assemble( case P_BLKW: case P_BLKB: { - EX_TREE *value = parse_expr(cp, 0); + EX_TREE *value; int ok = 1; + cp = skipwhite(cp); + if (EOL(*cp)) { + /* If no argument, assume 1. Documented but + * discouraged. Par 6.5.3, page 6-32. */ + /* warning(stack->top, "Argument to .BLKB/.BLKW should be present; 1 assumed\n"); */ + value = new_ex_lit(1); + } else { + value = parse_expr(cp, 0); + } + if (value->type != EX_LIT) { report(stack->top, "Argument to .BLKB/.BLKW " "must be constant\n"); ok = 0; diff --git a/tests/RunTests b/tests/RunTests index b9796be..76e506e 100755 --- a/tests/RunTests +++ b/tests/RunTests @@ -8,6 +8,7 @@ TESTS="test-asciz \ test-backpatch \ + test-blkb \ test-bsl-mac-arg \ test-complex-reloc \ test-endm \ diff --git a/tests/test-blkb.lst.ok b/tests/test-blkb.lst.ok new file mode 100644 index 0000000..0ccced9 --- /dev/null +++ b/tests/test-blkb.lst.ok @@ -0,0 +1,41 @@ + 1 ;;;;; + 2 ; + 3 ; Test .BLKB and .BLKW + 4 ; + 5 000000 label: .blkb ; not recommended, but default argument is 1 + 6 000001 .blkb 1 + 7 000002 .blkb 2 + 8 000004 .blkb 100. +test-blkb.mac:9: ***ERROR Argument to .BLKB/.BLKW must be constant + 9 .blkb label ; error: not an constant expression + 10 + 11 000150 000 .odd + 12 + 13 000151 .blkw 1 ; should maybe be an error: odd address + 14 + 15 000153 000 .even + 16 + 17 000154 label2: .blkb ; not recommended, but default argument is 1 + 18 000155 .blkb 1 + 19 000156 .blkb 2 + 20 000160 .blkb 100. +test-blkb.mac:21: ***ERROR Argument to .BLKB/.BLKW must be constant + 21 .blkb label2 ; error: not an constant expression + 22 + 23 +test-blkb.mac:24: ***ERROR .EVEN must not have an argument + 24 .even 1 ; error: no argument allowed +test-blkb.mac:25: ***ERROR .EVEN must not have an argument + 25 000324 000 .odd 1 ; error: no argument allowed + 25 + + +Symbol table + +. ******R 001 LABEL 000000R 001 LABEL2 000154R 001 + + +Program sections: + +. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) + 000325 001 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/test-blkb.mac b/tests/test-blkb.mac new file mode 100644 index 0000000..88e39eb --- /dev/null +++ b/tests/test-blkb.mac @@ -0,0 +1,25 @@ +;;;;; +; +; Test .BLKB and .BLKW +; +label: .blkb ; not recommended, but default argument is 1 + .blkb 1 + .blkb 2 + .blkb 100. + .blkb label ; error: not an constant expression + + .odd + + .blkw 1 ; should maybe be an error: odd address + + .even + +label2: .blkb ; not recommended, but default argument is 1 + .blkb 1 + .blkb 2 + .blkb 100. + .blkb label2 ; error: not an constant expression + + + .even 1 ; error: no argument allowed + .odd 1 ; error: no argument allowed From 27abf32bf43fd598408fa28914160ed4da7f85b1 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Thu, 27 Apr 2017 22:11:31 +0200 Subject: [PATCH 027/174] Let .LIST and .NLIST affect listing only if they have no argument. --- assemble.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/assemble.c b/assemble.c index 71c7d00..41a8c5e 100644 --- a/assemble.c +++ b/assemble.c @@ -282,10 +282,18 @@ static int assemble( need: get assembly listing controls working fully. ) */ case P_LIST: - if (pass > 0) list_level++; + if (pass > 0) { + cp = skipwhite(cp); + if (EOL(*cp)) + list_level++; + } return 1; case P_NLIST: - if (pass > 0) list_level--; + if (pass > 0) { + cp = skipwhite(cp); + if (EOL(*cp)) + list_level--; + } return 1; case P_IDENT: From 4916b699fa54ba2ce3db502850f399576759146e Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Fri, 28 Apr 2017 22:39:51 +0200 Subject: [PATCH 028/174] Add ^pl and ^ph expressions from 2.11BSD's m11. I hope I understood what this is doing! --- parse.c | 36 ++++++++++++++++++++++++++++++++++++ tests/RunTests | 1 + tests/test-ua-pl.lst.ok | 35 +++++++++++++++++++++++++++++++++++ tests/test-ua-pl.mac | 21 +++++++++++++++++++++ tests/test-ua-pl.objd.ok | 29 +++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 tests/test-ua-pl.lst.ok create mode 100644 tests/test-ua-pl.mac create mode 100644 tests/test-ua-pl.objd.ok diff --git a/parse.c b/parse.c index 78a3119..843cb40 100644 --- a/parse.c +++ b/parse.c @@ -755,6 +755,42 @@ EX_TREE *parse_unary( tp = new_ex_lit(flt[0]); tp->cp = endcp; } + return tp; + } + case 'p': + /* psect limits, low or high */ { + char bound = tolower((unsigned char)cp[2]); + char *cp2 = skipwhite(cp + 3); + int islocal = 0; + char *endcp; + char *psectname = get_symbol(cp2, &endcp, &islocal); + SYMBOL *sectsym = lookup_sym(psectname, §ion_st); + + if (sectsym && !islocal) { + SECTION *psect = sectsym->section; + + tp = new_ex_tree(); + tp->type = EX_SYM; + tp->data.symbol = sectsym; + tp->cp = cp; + + if (bound == 'l') { + ; /* that's it */ + } else if (bound == 'h') { + EX_TREE *rightp = new_ex_lit(psect->size); + tp = new_ex_bin(EX_ADD, tp, rightp); + } else { + tp = ex_err(tp, endcp); + /* report(stack->top, "^p: %c not recognized", bound); */ + } + } else { + /* report(stack->top, "psect name %s not found"); */ + tp = ex_err(new_ex_lit(0), endcp); + } + free(psectname); + tp->cp = endcp; + cp = endcp; + return tp; } } diff --git a/tests/RunTests b/tests/RunTests index 76e506e..df7532b 100755 --- a/tests/RunTests +++ b/tests/RunTests @@ -21,6 +21,7 @@ TESTS="test-asciz \ test-prec \ test-psect \ test-rad50 \ + test-ua-pl \ test-undef \ test-word-comma" diff --git a/tests/test-ua-pl.lst.ok b/tests/test-ua-pl.lst.ok new file mode 100644 index 0000000..db5836e --- /dev/null +++ b/tests/test-ua-pl.lst.ok @@ -0,0 +1,35 @@ + 1 ;;;;; + 2 ; + 3 ; Test ^pl and ^ph + 4 + 5 000000 .PSECT section + 6 + 7 000000 000000' .word <^pl section> + 8 000002 000014' .word <^ph section> + 9 000004 000000' .word <^pl code> + 10 000006 000010' .word <^ph code> + 11 000010 010' .byte <^ph code> + 12 000011 000C .byte <^ph code> / 256 + 13 + 14 000000 .PSECT code + 15 + 16 000000 000000' .word <^pl section> + 17 000002 000014' .word <^ph section> + 18 000004 000000' .word <^pl code> + 19 000006 000010' .word <^ph code> + 20 + 21 .end + 21 + + +Symbol table + +. ******R 003 + + +Program sections: + +. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) + 000000 001 (RW,I,LCL,REL,CON,NOSAV) +SECTIO 000014 002 (RW,I,LCL,REL,CON,NOSAV) +CODE 000010 003 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/test-ua-pl.mac b/tests/test-ua-pl.mac new file mode 100644 index 0000000..60106a9 --- /dev/null +++ b/tests/test-ua-pl.mac @@ -0,0 +1,21 @@ +;;;;; +; +; Test ^pl and ^ph + + .PSECT section + + .word <^pl section> + .word <^ph section> + .word <^pl code> + .word <^ph code> + .byte <^ph code> + .byte <^ph code> / 256 + + .PSECT code + + .word <^pl section> + .word <^ph section> + .word <^pl code> + .word <^ph code> + + .end diff --git a/tests/test-ua-pl.objd.ok b/tests/test-ua-pl.objd.ok new file mode 100644 index 0000000..7c487c5 --- /dev/null +++ b/tests/test-ua-pl.objd.ok @@ -0,0 +1,29 @@ +GSD: + MODNAME .MAIN.=0 flags=0 + PSECT =0 CON RW REL LCL I flags=40 + PSECT . ABS.=0 OVR RW ABS GBL I flags=104 + PSECT CODE =10 CON RW REL LCL I flags=40 + PSECT SECTIO=14 CON RW REL LCL I flags=40 + XFER . ABS.=1 flags=10 +ENDGSD +RLD + Location counter definition SECTIO+0 +TEXT ADDR=0 LEN=12 + 000000: 000000 000014 000000 000010 ........ + 000010: 000010 .. +RLD + Internal 0=0 + Internal 2=14 + PSECT plus offset 4=CODE+0 + PSECT plus offset 6=CODE+10 + PSECT plus offset byte 10=CODE+10 + Complex byte 11=CODE:10 256 / store + Location counter definition CODE+0 +TEXT ADDR=0 LEN=10 + 000000: 000000 000014 000000 000010 ........ +RLD + PSECT plus offset 0=SECTIO+0 + PSECT plus offset 2=SECTIO+14 + Internal 4=0 + Internal 6=10 +ENDMOD From f5e122731737ac05fdcde31d64294227d932f932 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Thu, 4 May 2017 23:00:43 +0200 Subject: [PATCH 029/174] Add some tests for .if etc. Fix a sign bit. --- assemble.c | 2 +- tests/RunTests | 1 + tests/test-if.lst.ok | 115 +++++++++++++++++++++++++++++++++++++++++++ tests/test-if.mac | 103 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 tests/test-if.lst.ok create mode 100644 tests/test-if.mac diff --git a/assemble.c b/assemble.c index 41a8c5e..255520b 100644 --- a/assemble.c +++ b/assemble.c @@ -847,7 +847,7 @@ static int assemble( /* FIXME I don't know if the following is portable enough. */ if (tvalue->data.lit & 0x8000) - sword |= ~0xFFFF; /* Render negative */ + sword |= ~0x7FFF; /* Render negative */ /* Reduce unsigned value to 16 bits */ uword = tvalue->data.lit & 0xffff; diff --git a/tests/RunTests b/tests/RunTests index df7532b..ae6a7d2 100755 --- a/tests/RunTests +++ b/tests/RunTests @@ -12,6 +12,7 @@ TESTS="test-asciz \ test-bsl-mac-arg \ test-complex-reloc \ test-endm \ + test-if \ test-impword \ test-include \ test-jmp \ diff --git a/tests/test-if.lst.ok b/tests/test-if.lst.ok new file mode 100644 index 0000000..b604df6 --- /dev/null +++ b/tests/test-if.lst.ok @@ -0,0 +1,115 @@ + 1 ;;;;; + 2 ; + 3 ; Test various conditions of the condition directive + 4 ; + 5 + 6 000000 zero = 0 + 7 000001 one = 1 + 8 000002 defd = 2 + 9 177777 min1 = -1 + 10 + 11 ; defined + 12 000000 001 .iif df defd .byte 1 + 13 .iif df undf .byte 0 + 14 .iif ndf defd .byte 0 + 15 000001 001 .iif ndf undf .byte 1 + 16 + 17 .ifdf defd + 18 000002 001 .byte 1 + 19 .endc + 20 .ifdf undf + 21 .byte 0 + 22 .endc + 23 .ifndf defd + 24 .byte 0 + 25 .endc + 26 .ifndf undf + 27 000003 001 .byte 1 + 28 .endc + 29 + 30 ; blank (string) + 31 000004 001 .iif b ^// .byte 1 + 32 .iif b .byte 0 + 33 .iif nb <> .byte 0 + 34 000005 001 .iif nb ^/x/ .byte 1 + 35 + 36 ; identical (strings) + 37 000006 001 .iif idn ^/a/ .byte 1 + 38 .iif idn ^/a/ .byte 0 + 39 .iif dif ^/a/ .byte 0 + 40 000007 001 .iif dif ^/a/ .byte 1 + 41 + 42 ; skip P1 and P2 + 43 + 44 ; equal to zero (value) + 45 000000 001 .iif eq zero .byte 1 + 46 000001 .iif eq one .byte 0 + 47 000000 .iif ne zero .byte 0 + 48 000001 001 .iif ne one .byte 1 + 49 + 50 000000 001 .iif z zero .byte 1 + 51 000001 .iif z one .byte 0 + 52 000000 .iif nz zero .byte 0 + 53 000001 001 .iif nz one .byte 1 + 54 + 55 ; greater than zero (value) + 56 177777 .iif gt min1 .byte 0 + 57 000000 .iif gt zero .byte 0 + 58 000001 001 .iif gt one .byte 1 + 59 + 60 177777 .iif g min1 .byte 0 + 61 000000 .iif g zero .byte 0 + 62 000001 001 .iif g one .byte 1 + 63 + 64 ; greater than or equal to zero (value) + 65 177777 .iif ge min1 .byte 0 + 66 000000 001 .iif ge zero .byte 1 + 67 000001 001 .iif ge one .byte 1 + 68 + 69 ; less than zero (value) + 70 177777 001 .iif lt min1 .byte 1 + 71 000000 .iif lt zero .byte 0 + 72 000001 .iif lt one .byte 0 + 73 + 74 177777 001 .iif l min1 .byte 1 + 75 000000 .iif l zero .byte 0 + 76 000001 .iif l one .byte 0 + 77 + 78 ; less than or equal to zero (value) + 79 177777 001 .iif le min1 .byte 1 + 80 000000 001 .iif le zero .byte 1 + 81 000001 .iif le one .byte 0 + 82 + 83 + 84 ; multiline conditions + 85 000001 .if ne one + 86 000024 001 .byte 1 + 87 .iff + 88 .byte 0 + 89 .ift + 90 000025 001 .byte 1 + 91 .iftf + 92 000026 001 .byte 1 + 93 .endc + 94 + 95 000001 .if eq one + 96 .byte 0 + 97 .iff + 98 000027 001 .byte 1 + 99 .ift + 100 .byte 0 + 101 .iftf + 102 000030 001 .byte 1 + 103 .endc + 103 + + +Symbol table + +. ******R 001 DEFD =000002 MIN1 =177777 ONE =000001 ZERO =000000 + + +Program sections: + +. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) + 000031 001 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/test-if.mac b/tests/test-if.mac new file mode 100644 index 0000000..4f79b90 --- /dev/null +++ b/tests/test-if.mac @@ -0,0 +1,103 @@ +;;;;; +; +; Test various conditions of the condition directive +; + +zero = 0 +one = 1 +defd = 2 +min1 = -1 + + ; defined + .iif df defd .byte 1 + .iif df undf .byte 0 + .iif ndf defd .byte 0 + .iif ndf undf .byte 1 + + .ifdf defd + .byte 1 + .endc + .ifdf undf + .byte 0 + .endc + .ifndf defd + .byte 0 + .endc + .ifndf undf + .byte 1 + .endc + + ; blank (string) + .iif b ^// .byte 1 + .iif b .byte 0 + .iif nb <> .byte 0 + .iif nb ^/x/ .byte 1 + + ; identical (strings) + .iif idn ^/a/ .byte 1 + .iif idn ^/a/ .byte 0 + .iif dif ^/a/ .byte 0 + .iif dif ^/a/ .byte 1 + + ; skip P1 and P2 + + ; equal to zero (value) + .iif eq zero .byte 1 + .iif eq one .byte 0 + .iif ne zero .byte 0 + .iif ne one .byte 1 + + .iif z zero .byte 1 + .iif z one .byte 0 + .iif nz zero .byte 0 + .iif nz one .byte 1 + + ; greater than zero (value) + .iif gt min1 .byte 0 + .iif gt zero .byte 0 + .iif gt one .byte 1 + + .iif g min1 .byte 0 + .iif g zero .byte 0 + .iif g one .byte 1 + + ; greater than or equal to zero (value) + .iif ge min1 .byte 0 + .iif ge zero .byte 1 + .iif ge one .byte 1 + + ; less than zero (value) + .iif lt min1 .byte 1 + .iif lt zero .byte 0 + .iif lt one .byte 0 + + .iif l min1 .byte 1 + .iif l zero .byte 0 + .iif l one .byte 0 + + ; less than or equal to zero (value) + .iif le min1 .byte 1 + .iif le zero .byte 1 + .iif le one .byte 0 + + + ; multiline conditions + .if ne one + .byte 1 + .iff + .byte 0 + .ift + .byte 1 + .iftf + .byte 1 + .endc + + .if eq one + .byte 0 + .iff + .byte 1 + .ift + .byte 0 + .iftf + .byte 1 + .endc From 203a812664d9a6e8905a28a3f0879e1da0550b9d Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 6 May 2017 15:49:18 +0200 Subject: [PATCH 030/174] Add 2.11BSD's m11 sources as regression tests. --- CHANGES | 6 + tests/2.11BSD-m11-code.lst.ok | 1294 ++++++++ tests/2.11BSD-m11-debug.lst.ok | 659 ++++ tests/2.11BSD-m11-errs.lst.ok | 1247 ++++++++ tests/2.11BSD-m11-exec.lst.ok | 4694 +++++++++++++++++++++++++++++ tests/2.11BSD-m11-expr.lst.ok | 1779 +++++++++++ tests/2.11BSD-m11-fltg.lst.ok | 1007 +++++++ tests/2.11BSD-m11-getl.lst.ok | 1620 ++++++++++ tests/2.11BSD-m11-lout.lst.ok | 2656 ++++++++++++++++ tests/2.11BSD-m11-mac.lst.ok | 2314 ++++++++++++++ tests/2.11BSD-m11-macro.lst.ok | 1335 ++++++++ tests/2.11BSD-m11-misc.lst.ok | 1244 ++++++++ tests/2.11BSD-m11-often.lst.ok | 737 +++++ tests/2.11BSD-m11-pst.lst.ok | 3071 +++++++++++++++++++ tests/2.11BSD-m11-srch.lst.ok | 989 ++++++ tests/2.11BSD-m11-syscalls.lst.ok | 473 +++ tests/2.11BSD-m11-xlat.lst.ok | 3089 +++++++++++++++++++ tests/2.11BSD-m11-xpcor.lst.ok | 472 +++ tests/2.11BSD/00SOURCE | 7 + tests/2.11BSD/m11/Document | 287 ++ tests/2.11BSD/m11/Makefile | 49 + tests/2.11BSD/m11/READme | 38 + tests/2.11BSD/m11/at.sml | 425 +++ tests/2.11BSD/m11/code.m11 | 473 +++ tests/2.11BSD/m11/debug.m11 | 53 + tests/2.11BSD/m11/errs.m11 | 83 + tests/2.11BSD/m11/exec.m11 | 1473 +++++++++ tests/2.11BSD/m11/expr.m11 | 567 ++++ tests/2.11BSD/m11/fltg.m11 | 250 ++ tests/2.11BSD/m11/getl.m11 | 453 +++ tests/2.11BSD/m11/l11.x | Bin 0 -> 20126 bytes tests/2.11BSD/m11/lout.m11 | 958 ++++++ tests/2.11BSD/m11/m11.1 | 292 ++ tests/2.11BSD/m11/m11.x | Bin 0 -> 21630 bytes tests/2.11BSD/m11/mac.m11 | 886 ++++++ tests/2.11BSD/m11/macro.m11 | 221 ++ tests/2.11BSD/m11/macxrf.c | 352 +++ tests/2.11BSD/m11/misc.m11 | 305 ++ tests/2.11BSD/m11/often.m11 | 77 + tests/2.11BSD/m11/pst.m11 | 286 ++ tests/2.11BSD/m11/srch.m11 | 323 ++ tests/2.11BSD/m11/syscalls.m11 | 17 + tests/2.11BSD/m11/xlat.m11 | 1059 +++++++ tests/2.11BSD/m11/xpcor.m11 | 16 + tests/RunTests | 28 +- 45 files changed, 37662 insertions(+), 2 deletions(-) create mode 100644 tests/2.11BSD-m11-code.lst.ok create mode 100644 tests/2.11BSD-m11-debug.lst.ok create mode 100644 tests/2.11BSD-m11-errs.lst.ok create mode 100644 tests/2.11BSD-m11-exec.lst.ok create mode 100644 tests/2.11BSD-m11-expr.lst.ok create mode 100644 tests/2.11BSD-m11-fltg.lst.ok create mode 100644 tests/2.11BSD-m11-getl.lst.ok create mode 100644 tests/2.11BSD-m11-lout.lst.ok create mode 100644 tests/2.11BSD-m11-mac.lst.ok create mode 100644 tests/2.11BSD-m11-macro.lst.ok create mode 100644 tests/2.11BSD-m11-misc.lst.ok create mode 100644 tests/2.11BSD-m11-often.lst.ok create mode 100644 tests/2.11BSD-m11-pst.lst.ok create mode 100644 tests/2.11BSD-m11-srch.lst.ok create mode 100644 tests/2.11BSD-m11-syscalls.lst.ok create mode 100644 tests/2.11BSD-m11-xlat.lst.ok create mode 100644 tests/2.11BSD-m11-xpcor.lst.ok create mode 100644 tests/2.11BSD/00SOURCE create mode 100644 tests/2.11BSD/m11/Document create mode 100644 tests/2.11BSD/m11/Makefile create mode 100644 tests/2.11BSD/m11/READme create mode 100644 tests/2.11BSD/m11/at.sml create mode 100644 tests/2.11BSD/m11/code.m11 create mode 100644 tests/2.11BSD/m11/debug.m11 create mode 100644 tests/2.11BSD/m11/errs.m11 create mode 100644 tests/2.11BSD/m11/exec.m11 create mode 100644 tests/2.11BSD/m11/expr.m11 create mode 100644 tests/2.11BSD/m11/fltg.m11 create mode 100644 tests/2.11BSD/m11/getl.m11 create mode 100644 tests/2.11BSD/m11/l11.x create mode 100644 tests/2.11BSD/m11/lout.m11 create mode 100644 tests/2.11BSD/m11/m11.1 create mode 100644 tests/2.11BSD/m11/m11.x create mode 100644 tests/2.11BSD/m11/mac.m11 create mode 100644 tests/2.11BSD/m11/macro.m11 create mode 100644 tests/2.11BSD/m11/macxrf.c create mode 100644 tests/2.11BSD/m11/misc.m11 create mode 100644 tests/2.11BSD/m11/often.m11 create mode 100644 tests/2.11BSD/m11/pst.m11 create mode 100644 tests/2.11BSD/m11/srch.m11 create mode 100644 tests/2.11BSD/m11/syscalls.m11 create mode 100644 tests/2.11BSD/m11/xlat.m11 create mode 100644 tests/2.11BSD/m11/xpcor.m11 diff --git a/CHANGES b/CHANGES index e66dc9c..f4333bb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,11 @@ ??.??.201?: Rhialto version 0.5: + - Object-ified macro libraries with an eye to support the .sml + files from 2.11BSD's m11. But since the given file does not + just contain .MACROs (it even contains conditionals) I'm not + sure how it is supposed to work. + - Added 2.11BSD/m11 as test files. To make this reasonable, a + few small features they use have been recognized and ignored. 09.11.2015: Rhialto version 0.4: diff --git a/tests/2.11BSD-m11-code.lst.ok b/tests/2.11BSD-m11-code.lst.ok new file mode 100644 index 0000000..98f997d --- /dev/null +++ b/tests/2.11BSD-m11-code.lst.ok @@ -0,0 +1,1294 @@ + 1 ;;;; Wrapper for 2.11BSD/m11/code.m11 + 2 .list + 3 .list + 4 .list + 5 .enabl lc + 6 000001 debug = 1 + 7 .include "2.11BSD/m11/at.sml" + 1 .title at.sml - assembler/translator system macros + 2 ; @(#)at.sml 1.3 11/3/82 + 3 + 4 .ident /10may4/ + 5 + 6 .macro always ;all files of macro + 7 + 8 .macro .data + 9 entsec .data + 10 .endm .data + 11 + 12 .macro .text + 13 entsec .text + 14 .endm + 15 + 16 .macro .bss + 17 entsec .bss + 18 .endm + 19 + 20 mk.symbol=1 ;one to make symbols, 0 otherwise + 21 x40= 0 + 22 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs. + 23 ; if not you will have to write macros for them + 24 $timdf= 7 ; California Time Zone + 25 ; should really use ftime(2) for this and for + 26 ; DST. + 27 ;xfltg= 0 ;define to assmbl out floating hardware + 28 rsx11d = 0 ; rsx11d features + 29 debug = 0 ; <<< REEDS if non zero includes debug junk + 30 + 31 ft.id= 1 ;have set i & d. set =0 if not + 32 + 33 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not. + 34 + 35 .nlist bex + 36 + 37 tab= 11 + 38 lf= 12 + 39 vt= 13 + 40 ff= 14 + 41 cr= 15 + 42 space= 40 + 43 + 44 bpmb = 20 ;bytes per macro block + 45 + 46 + 47 + 48 + 49 + 50 .psect .text con, shr, gbl,ins + 51 .psect .data con, dat, prv, gbl + 52 .psect .bss con, bss, gbl + 53 + 54 .psect dpure con, dat, prv, gbl + 55 .psect mixed con, prv, gbl + 56 .psect errmes con, dat, prv, gbl + 57 .psect impure con, bss, gbl + 58 .psect imppas con, bss, gbl + 59 .psect implin con, bss, gbl + 60 .psect swtsec con, dat, prv, gbl ; unix command line flags + 61 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if' + 62 .psect crfsec con, dat, prv, gbl ; args for -cr flag + 63 .psect edtsec con, dat, prv, gbl ; args for .enabl + 64 .psect lctsec con, dat, prv, gbl ; args for .list + 65 .psect psasec con, dat, prv, gbl + 66 .psect pstsec con, dat, prv, gbl + 67 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables + 68 .psect rolsiz con, dat, prv, gbl ; sizes of table entries + 69 .psect roltop con, dat, prv, gbl ; tops of tables + 70 .psect xpcor con,bss , gbl ; this one MUST come last in core + 71 + 72 + 72 + 73 .macro entsec name ;init a section + 74 .psect name con + 75 .endm entsec + 76 + 77 + 78 + 79 .macro jeq x,?fred + 80 bne fred + 81 jmp x + 82 fred: + 83 .endm + 84 .macro jne x,?fred + 85 beq fred + 86 jmp x + 87 fred: + 88 .endm + 89 .macro xitsec + 90 entsec .text + 91 .endm xitsec + 92 + 93 + 94 .macro call address + 95 jsr pc,address + 96 .endm + 97 + 98 .macro return + 99 rts pc + 100 .endm + 101 + 102 + 103 .macro always + 104 .nlist bex + 105 .endm always + 106 .endm always + 107 + 108 + 109 000001 .if ne debug + 110 + 111 .macro ndebug n + 112 .globl ndebug,..z + 113 mov n,..z + 114 call ndebug + 115 .endm + 116 + 117 .macro sdebug string + 118 .globl sdebug,..z,..zbuf + 119 x = 0 + 120 .irpc t, + 121 movb #''t,..zbuf+x + 122 x = x+1 + 123 .endm + 124 movb #0,..zbuf+x + 125 mov #..zbuf,..z + 126 call sdebug + 127 .endm + 128 + 129 .iff + 130 + 131 .macro ndebug n + 132 .endm + 133 + 134 .macro sdebug string + 135 .endm + 136 + 137 .endc + 138 + 139 + 140 .macro param mne, value ;define default parameters + 141 .iif ndf mne, mne= value + 142 .list + 143 mne= mne + 144 .nlist + 145 .endm + 145 + 146 .macro putkb addr ;list to kb + 147 .globl putkb + 148 mov addr,r0 + 149 call putkb + 150 .endm + 151 + 152 .macro putlp addr ;list to lp + 153 .globl putlp + 154 mov addr,r0 + 155 call putlp + 156 .endm + 157 + 158 .macro putkbl addr ;list to kb and lp + 159 .globl putkbl + 160 mov addr,r0 + 161 call putkbl + 162 .endm + 163 + 164 + 165 .macro xmit wrdcnt ;move small # of words + 166 .globl xmit0 + 167 call xmit0- + 168 .endm xmit + 169 + 170 + 171 ;the macro "genswt" is used to specify a command + 172 ;string switch (1st argument) and the address of + 173 ;the routine to be called when encountered (2nd arg). + 174 ; the switch is made upper-case. + 175 + 176 .macro genswt mne,addr,?label + 177 entsec swtsec + 178 label: .irpc x,mne + 179 .if ge ''x-141 + 180 .if le ''x-172 + 181 .byte ''x-40 + 182 .iff + 183 .byte ''x + 184 .endc + 185 .iff + 186 .byte ''x + 187 .endc + 188 .endm + 189 .iif ne <.-label&1>, .byte 0 + 190 .word addr + 191 xitsec + 192 .endm + 192 + 193 .macro zread chan + 194 .globl zread + 195 mov #chan'chn,r0 + 196 call zread + 197 .endm zread + 198 + 199 .macro zwrite chan + 200 .globl zwrite + 201 mov #chan'chn,r0 + 202 call zwrite + 203 .endm zwrite + 203 + 204 .macro genedt mne,subr ;gen enable/disable table + 205 entsec edtsec + 206 .rad50 /mne/ + 207 .if nb subr + 208 .word subr + 209 .iff + 210 .word cpopj + 211 .endc + 212 .word ed.'mne + 213 xitsec + 214 .endm genedt + 215 + 216 + 217 ;the macro "gencnd" is used to specify conditional + 218 ;arguments. it takes two or three arguments: + 219 + 220 ; 1- mnemonic + 221 ; 2- subroutine to be called + 222 ; 3- if non-blank, complement condition + 223 + 224 .macro gencnd mne,subr,toggle ;generate conditional + 225 entsec cndsec + 226 .rad50 /mne/ + 227 .if b + 228 .word subr + 229 .iff + 230 .word subr+1 + 231 .endc + 232 xitsec + 233 .endm + 233 + 234 .macro ch.mne + 235 + 236 ch.ior= '! + 237 ch.qtm= '" + 238 ch.hsh= '# + 239 ch.dol= '$ + 240 ch.pct= '% + 241 ch.and= '& + 242 ch.xcl= '' + 243 + 244 ch.lp= '( + 245 ch.rp= ') + 246 ch.mul= '* + 247 ch.add= '+ + 248 ch.com= ', + 249 ch.sub= '- + 250 ch.dot= '. + 251 ch.div= '/ + 252 + 253 ch.col= ': + 254 ch.smc= '; + 255 ch.lab= '< + 256 ch.equ= '= + 257 ch.rab= '> + 258 ch.qm= '? + 259 + 260 ch.ind= '@ + 261 ch.bsl= '\ + 262 ch.uar= '^ + 263 + 264 let.a= 'a&^c40 + 265 let.b= 'b&^c40 + 266 let.c= 'c&^c40 + 267 let.d= 'd&^c40 + 268 let.e= 'e&^c40 + 269 let.f= 'f&^c40 + 270 let.g= 'g&^c40 + 271 let.o= 'o&^c40 + 272 let.p= 'p&^c40 + 273 let.r= 'r&^c40 + 274 let.z= 'z&^c40 + 275 + 276 dig.0= '0 + 277 dig.9= '9 + 278 .macro ch.mne + 279 .endm ch.mne + 280 .endm ch.mne + 281 + 282 .macro error num,arg, mess ,?x + 283 sdebug + 284 .globl err.'arg,ern'num, errbts,errref + 285 .if b + 286 deliberate error mistake + 287 .endc + 288 .if dif 0,num + 289 .globl err.xx + 290 tst err.xx + 291 bne x + 292 mov #ern'num,err.xx + 293 x: + 294 .endc + 295 bis #err.'arg,errbts + 296 .endm + 297 + 298 + 299 + 300 .macro setnz addr ;set addr to non-zero for t/f flags + 301 mov sp,addr + 302 .endm + 303 + 304 + 305 .macro bisbic arg ; used by .list/.nlist, .enabl/.dsabl + 306 .globl bisbic + 307 mov #arg,-(sp) + 308 call bisbic + 309 tst (sp)+ + 310 .endm + 310 + 311 ;roll handler calls + 312 + 313 .macro search rolnum ;binary search + 314 mov #rolnum,r0 + 315 .globl search + 316 call search + 317 .endm + 318 + 319 .macro scan rolnum ;linear scan + 320 mov #rolnum,r0 + 321 .globl scan + 322 call scan + 323 .endm + 324 + 325 .macro scanw rolnum ;linear scan, one word + 326 mov #rolnum,r0 + 327 .globl scanw + 328 call scanw + 329 .endm + 330 + 331 .macro next rolnum ;fetch next entry + 332 mov #rolnum,r0 + 333 .globl next + 334 call next + 335 .endm + 336 + 337 .macro append rolnum ;append to end of roll + 338 mov #rolnum,r0 + 339 .globl append + 340 call append + 341 .endm + 342 + 343 .macro zap rolnum ;clear roll + 344 mov #rolnum,r0 + 345 .globl zap + 346 call zap + 347 .endm + 348 + 349 ; call insert ;insert (must be preceded by one + 350 ;of the above to set pointers) + 351 ; call setrol ;save and set regs for above + 351 + 352 ;flags used in symbol table mode + 353 + 354 .macro st.flg + 355 + 356 .if le ft.unx + 357 + 358 ovrflg= 000004 ;overlay (psect only) + 359 defflg= 000010 ;defined + 360 relflg= 000040 ;relocatable + 361 glbflg= 000100 ;global + 362 dfgflg= 000200 ; default global ... reeds's guess + 363 + 364 + 365 .endc + 366 + 367 .if gt ft.unx + 368 + 369 ; ****** these should not be changed!! ****** + 370 shrflg= 000001 ;shareable (psect only) + 371 .if gt ft.id + 372 insflg= shrflg*2 ;instruction space (psect only) + 373 bssflg= insflg*2 ;blank section (psect only) + 374 m.idf= shrflg!insflg!bssflg ;mask to turn them off + 375 .iff + 376 bssflg= shrflg*2 + 377 m.idf= shrflg!bssflg + 378 .endc + 379 b.idf= 1 ;shift count to make above bits word offset + 380 ; *********************************** + 381 defflg= 000010 ;defined + 382 ovrflg= 000020 ;overlay (psect only) + 383 relflg= 000040 ;relocatable + 384 glbflg= 000100 ;global + 385 dfgflg= 000200 ; default global ... reeds's guess + 386 + 387 .endc + 388 + 389 ; + 390 ; default psect attribs. + 391 ; can be changed, but make sure all customers know about + 392 ; it, including all the linkers. + 393 ; + 394 pattrs=relflg!defflg ; For .psects and blank .csects + 395 aattrs=glbflg!defflg!ovrflg ; For .asect + 396 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects + 397 + 398 regflg= 000001 ;register + 399 lblflg= 000002 ;label + 400 mdfflg= 000004 ;multilpy defined + 401 .macro st.flg + 402 .endm + 403 .endm st.flg + 404 + 405 + 406 + 407 .macro ct.mne + 408 .globl cttbl + 409 ct.eol = 000 ; eol + 410 ct.com = 001 ; comma + 411 ct.tab = 002 ; tab + 412 ct.sp = 004 ; space + 413 ct.pcx = 010 ; printing character + 414 ct.num = 020 ; numeric + 415 ct.alp = 040 ; alpha, dot, dollar + 416 ct.lc = 100 ; lower case alpha + 417 ct.smc = 200 ; semi-colon (sign bit) + 418 + 419 ct.pc = ct.com!ct.smc!ct.pcx!ct.num!ct.alp + 420 .macro ct.mne + 421 .endm ct.mne + 422 .endm ct.mne + 423 + 424 + 425 .end + 425 + 8 .include "2.11BSD/m11/code.m11" + 1 .title code + 2 + 3 .ident /10may4/ + 4 + 5 .mcall (at)always,st.flg,xmit,zwrite + 6 000000 always + 1 + 2 .macro .data + 3 entsec .data + 4 .endm .data + 5 + 6 .macro .text + 7 entsec .text + 8 .endm + 9 + 10 .macro .bss + 11 entsec .bss + 12 .endm + 13 + 14 000001 mk.symbol=1 ;one to make symbols, 0 otherwise + 15 000000 x40= 0 + 16 000000 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs. + 17 ; if not you will have to write macros for them + 18 000007 $timdf= 7 ; California Time Zone + 19 ; should really use ftime(2) for this and for + 20 ; DST. + 21 ;xfltg= 0 ;define to assmbl out floating hardware + 22 000000 rsx11d = 0 ; rsx11d features + 23 000000 debug = 0 ; <<< REEDS if non zero includes debug junk + 24 + 25 000001 ft.id= 1 ;have set i & d. set =0 if not + 26 + 27 000001 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not. + 28 + 29 .nlist bex + 30 + 31 000011 tab= 11 + 32 000012 lf= 12 + 33 000013 vt= 13 + 34 000014 ff= 14 + 35 000015 cr= 15 + 36 000040 space= 40 + 37 + 38 000020 bpmb = 20 ;bytes per macro block + 39 + 40 + 41 + 42 + 43 +./2.11BSD/m11/code.m11:6->ALWAYS:44: ***ERROR Unknown flag SHR given to .PSECT directive + 44 .psect .text con, shr, gbl,ins +./2.11BSD/m11/code.m11:6->ALWAYS:45: ***ERROR Unknown flag DAT given to .PSECT directive + 45 .psect .data con, dat, prv, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:46: ***ERROR Unknown flag BSS given to .PSECT directive + 46 .psect .bss con, bss, gbl + 47 +./2.11BSD/m11/code.m11:6->ALWAYS:48: ***ERROR Unknown flag DAT given to .PSECT directive + 48 .psect dpure con, dat, prv, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:49: ***ERROR Unknown flag PRV given to .PSECT directive + 49 .psect mixed con, prv, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:50: ***ERROR Unknown flag DAT given to .PSECT directive + 50 .psect errmes con, dat, prv, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:51: ***ERROR Unknown flag BSS given to .PSECT directive + 51 .psect impure con, bss, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:52: ***ERROR Unknown flag BSS given to .PSECT directive + 52 .psect imppas con, bss, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:53: ***ERROR Unknown flag BSS given to .PSECT directive + 53 .psect implin con, bss, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:54: ***ERROR Unknown flag DAT given to .PSECT directive + 54 .psect swtsec con, dat, prv, gbl ; unix command line flags +./2.11BSD/m11/code.m11:6->ALWAYS:55: ***ERROR Unknown flag DAT given to .PSECT directive + 55 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if' +./2.11BSD/m11/code.m11:6->ALWAYS:56: ***ERROR Unknown flag DAT given to .PSECT directive + 56 .psect crfsec con, dat, prv, gbl ; args for -cr flag +./2.11BSD/m11/code.m11:6->ALWAYS:57: ***ERROR Unknown flag DAT given to .PSECT directive + 57 .psect edtsec con, dat, prv, gbl ; args for .enabl +./2.11BSD/m11/code.m11:6->ALWAYS:58: ***ERROR Unknown flag DAT given to .PSECT directive + 58 .psect lctsec con, dat, prv, gbl ; args for .list +./2.11BSD/m11/code.m11:6->ALWAYS:59: ***ERROR Unknown flag DAT given to .PSECT directive + 59 .psect psasec con, dat, prv, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:60: ***ERROR Unknown flag DAT given to .PSECT directive + 60 .psect pstsec con, dat, prv, gbl +./2.11BSD/m11/code.m11:6->ALWAYS:61: ***ERROR Unknown flag DAT given to .PSECT directive + 61 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables +./2.11BSD/m11/code.m11:6->ALWAYS:62: ***ERROR Unknown flag DAT given to .PSECT directive + 62 .psect rolsiz con, dat, prv, gbl ; sizes of table entries +./2.11BSD/m11/code.m11:6->ALWAYS:63: ***ERROR Unknown flag DAT given to .PSECT directive + 63 .psect roltop con, dat, prv, gbl ; tops of tables +./2.11BSD/m11/code.m11:6->ALWAYS:64: ***ERROR Unknown flag BSS given to .PSECT directive + 64 .psect xpcor con,bss , gbl ; this one MUST come last in core + 65 + 66 + 67 + 68 .macro entsec name ;init a section + 69 .psect name con + 70 .endm entsec + 71 + 72 + 73 + 74 .macro jeq x,?fred + 75 bne fred + 76 jmp x + 77 fred: + 78 .endm + 79 .macro jne x,?fred + 80 beq fred + 81 jmp x + 82 fred: + 83 .endm + 84 .macro xitsec + 85 entsec .text + 86 .endm xitsec + 87 + 88 + 89 .macro call address + 90 jsr pc,address + 91 .endm + 92 + 93 .macro return + 94 rts pc + 95 .endm + 96 + 97 + 98 .macro always + 99 .nlist bex + 100 .endm always + 7 000000 st.flg + 1 + 2 000001 .if le ft.unx + 3 + 4 ovrflg= 000004 ;overlay (psect only) + 5 defflg= 000010 ;defined + 6 relflg= 000040 ;relocatable + 7 glbflg= 000100 ;global + 8 dfgflg= 000200 ; default global ... reeds's guess + 9 + 10 + 11 .endc + 12 + 13 000001 .if gt ft.unx + 14 + 15 ; ****** these should not be changed!! ****** + 16 000001 shrflg= 000001 ;shareable (psect only) + 17 000001 .if gt ft.id + 18 000002 insflg= shrflg*2 ;instruction space (psect only) + 19 000004 bssflg= insflg*2 ;blank section (psect only) + 20 000007 m.idf= shrflg!insflg!bssflg ;mask to turn them off + 21 .iff + 22 bssflg= shrflg*2 + 23 m.idf= shrflg!bssflg + 24 .endc + 25 000001 b.idf= 1 ;shift count to make above bits word offset + 26 ; *********************************** + 27 000010 defflg= 000010 ;defined + 28 000020 ovrflg= 000020 ;overlay (psect only) + 29 000040 relflg= 000040 ;relocatable + 30 000100 glbflg= 000100 ;global + 31 000200 dfgflg= 000200 ; default global ... reeds's guess + 32 + 33 .endc + 34 + 35 ; + 36 ; default psect attribs. + 37 ; can be changed, but make sure all customers know about + 38 ; it, including all the linkers. + 39 ; + 40 000050 pattrs=relflg!defflg ; For .psects and blank .csects + 41 000130 aattrs=glbflg!defflg!ovrflg ; For .asect + 42 000170 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects + 43 + 44 000001 regflg= 000001 ;register + 45 000002 lblflg= 000002 ;label + 46 000004 mdfflg= 000004 ;multilpy defined + 47 .macro st.flg + 48 .endm + 8 + 9 .mcall (at)genedt,setnz,next,append,zap,error + 10 + 11 .globl objchn, objlen + 12 .globl savreg, ioftbl, buftbl, cnttbl + 13 + 14 .globl dmprld, endp1c, endp2c, pcroll, prgttl + 15 .globl setdsp, setimm, setrld, stcode + 16 + 17 .globl abserr, clcloc, clcnam, clcsec + 18 .globl codrol, endvec, mode, objsec + 19 ;.globl pass, psaflg, rolupd, secrol + 20 .globl pass, rolupd, secrol + 21 .globl sector, setpf0, setpf1, setsec, setxpr + 22 .globl symbol, symrol, value + 23 .globl edmask, ed.abs, ed.pnc + 24 .globl dflgbm, opclas + 24 + 25 000040 cc.opr = 040 + 26 000020 cc.nam = 020 + 27 000010 cc.sec = 010 + 28 000004 cc.val = 004 + 29 000002 cc.dsp = 002 + 30 + 31 + 32 000000 gsdt00= 00*400 ; object module name + 33 000400 gsdt01= 01*400 ; program section name + 34 001000 gsdt02= 02*400 ; internal symbol table + 35 001400 gsdt03= 03*400 ; transfer address + 36 002000 gsdt04= 04*400 ; symbol declaration + 37 002400 gsdt05= 05*400 ; local section name + 38 003000 gsdt06= 06*400 ; version identification + 39 + 40 000001 blkt01= 01 ; gsd + 41 000002 blkt02= 02 ; gsd end + 42 000003 blkt03= 03 ; text block + 43 000004 blkt04= 04 ; rld block + 44 000005 blkt05= 05 ; isd + 45 000006 blkt06= 06 ; module end + 46 000017 blkt17= 17 + 46 + 47 .sbttl expression to code-roll conversions + 48 + 49 000000 xitsec ;start in default psect + 1 000000 entsec .text + 1 000000 .psect .text con + 50 + 51 setimm: ; + 52 000000 call savreg + 1 000000 004767 000000G jsr pc,savreg + 53 000004 call setxpr + 1 000004 004767 000000G jsr pc,setxpr + 54 000010 005046 clr -(sp) + 55 000012 132713 000100 bitb #glbflg,(r3) + 56 000016 001047 bne setds3 + 57 000020 032713 000040 bit #relflg,(r3) + 58 000024 001446 beq setdsx + 59 000026 121267 000000G cmpb (r2),clcsec + 60 000032 001022 bne setds1 + 61 000034 052716 000010 bis #cc.sec,(sp) + 62 000040 000440 br setdsx + 63 + 64 setdsp: + 65 000042 call savreg + 1 000042 004767 000000G jsr pc,savreg + 66 000046 call setxpr + 1 000046 004767 000000G jsr pc,setxpr + 67 000052 012746 000002 mov #cc.dsp,-(sp) + 68 000056 032713 000100 bit #glbflg,(r3) + 69 000062 001025 bne setds3 + 70 000064 121267 000000G cmpb (r2),clcsec + 71 000070 001410 beq setds2 + 72 000072 032713 000040 bit #relflg,(r3) + 73 000076 001421 beq setdsx + 74 000100 setds1: call setsec + 1 000100 004767 000000G jsr pc,setsec + 75 000104 052716 000030 bis #cc.sec!cc.nam,(sp) + 76 000110 000414 br setdsx + 77 + 78 000112 005013 setds2: clr (r3) + 79 000114 005016 clr (sp) + 80 000116 116700 000000C movb <^pl rolsiz>+codrol+1,r0 + 81 ;movb @(pc)+,r0 + 82 ; .word <^pl rolsiz>+codrol+1 + 83 000122 005200 inc r0 + 84 000124 006300 asl r0 + 85 000126 066700 000000G add clcloc,r0 + 86 000132 160014 sub r0,(r4) + 87 000134 000402 br setdsx + 88 + 89 000136 052716 000020 setds3: bis #cc.nam,(sp) + 90 000142 032767 000000G 000000G setdsx: bit #dflgbm,opclas + 91 000150 001415 beq 4$ + 92 000152 105724 tstb (r4)+ + 93 000154 111400 movb (r4),r0 + 94 000156 001402 beq 1$ + 95 000160 005200 inc r0 + 96 000162 001003 bne 2$ + 97 000164 032716 000010 1$: bit #cc.sec,(sp) + 98 000170 001402 beq 3$ + 99 000172 2$: call abserr + 1 000172 004767 000000G jsr pc,abserr + 100 000176 105014 3$: clrb (r4) + 101 000200 052716 000200 bis #200,(sp) + 102 000204 112612 4$: movb (sp)+,(r2) + 103 000206 return + 1 000206 000207 rts pc + 103 + 104 .globl limit + 105 + 106 limit: + 107 000210 call setrld + 1 000210 004767 001270 jsr pc,setrld + 108 000214 005203 1$: inc r3 + 109 000216 112722 000040 movb #cc.opr,(r2)+ + 110 000222 110322 movb r3,(r2)+ + 111 000224 110322 movb r3,(r2)+ + 112 000226 call dmprld + 1 000226 004767 001166 jsr pc,dmprld + 113 000232 012700 000000G mov #symbol,r0 + 114 000236 005020 clr (r0)+ + 115 000240 010320 mov r3,(r0)+ + 116 000242 012720 010000 mov #cc.nam*400,(r0)+ + 117 000246 005020 clr (r0)+ + 118 000250 call stcode + 1 000250 004767 000552 jsr pc,stcode + 119 000254 020327 000002 cmp r3,#2 + 120 000260 103755 blo 1$ + 121 000262 return + 1 000262 000207 rts pc + 122 + 123 .globl ident, rad50 + 124 ident: ;"ident" directive + 125 000264 call rad50 ;treat as rad 50 + 1 000264 004767 000000G jsr pc,rad50 + 126 000270 005067 000000G clr rolupd ;point to start of code roll + 127 000274 012702 000010' mov #prgidn,r2 ; and to ident block + 128 000300 1$: next codrol ;get the next entry + 1 000300 012700 000000G mov #codrol,r0 + 2 .globl next + 3 000304 call next + 1 000304 004767 000000G jsr pc,next + 129 000310 016722 000000G mov value,(r2)+ ;stuff it + 130 000314 020227 000014' cmp r2,#prgidn+4 ;two words? + 131 000320 103767 blo 1$ ; no + 132 000322 012722 003000 mov #gsdt06,(r2)+ ;yes, set gsd type + 133 000326 zap codrol ;clear code + 1 000326 012700 000000G mov #codrol,r0 + 2 .globl zap + 3 000332 call zap + 1 000332 004767 000000G jsr pc,zap + 134 000336 return + 1 000336 000207 rts pc + 135 + 136 + 137 000340 entsec impure + 1 000000 .psect impure con + 138 000000 prgttl: .blkw 4 ;title block + 139 000010 prgidn: .blkw 4 ;ident " + 140 000020 xitsec + 1 000020 entsec .text + 1 000340 .psect .text con + 140 + 141 .sbttl object code handlers + 142 + 143 endp1c: ;end pass1 code init + 144 000340 105767 000000C tstb ioftbl+objchn ;any obj file? + 145 000344 001522 beq 9$ ; no + 146 000346 call objini ;init output + 1 000346 004767 001030 jsr pc,objini + 147 000352 012777 000001 000000C mov #blkt01,@buftbl+objchn ;set block type 1 + 148 000360 012701 000000' mov #prgttl,r1 ;set "from" index + 149 000364 call gsddmp ;output gsd block + 1 000364 004767 000230 jsr pc,gsddmp + 150 000370 012701 000010' mov #prgidn,r1 ;point to sub-ttl buffer + 151 000374 005761 000004 tst 4(r1) ;set? + 152 000400 001402 beq 1$ ; no + 153 000402 call gsddmp ;yes, stuff it + 1 000402 004767 000212 jsr pc,gsddmp + 154 000406 005046 1$: clr -(sp) ;init for sector scan + 155 000410 012667 000000G 2$: mov (sp)+,rolupd ;set scan marker + 156 000414 next secrol ;get the next sector + 1 000414 012700 000000G mov #secrol,r0 + 2 .globl next + 3 000420 call next + 1 000420 004767 000000G jsr pc,next + 157 000424 001446 beq 6$ ;branch if through + 158 000426 016746 000000G mov rolupd,-(sp) ;save marker + 159 000432 012701 000002G mov #value+2,r1 + 160 000436 011141 mov (r1),-(r1) + 161 000440 005005 clr r5 + 162 000442 154105 bisb -(r1),r5 + 163 000444 112711 000005 movb #gsdt05/400,(r1) + 164 ;tst psaflg ; who cares? a .csect is a + 165 ;bne 3$ ;special kind of .psect + 166 ;movb #gsdt01/400,(r1) ; so dont need this code + 167 ;bicb #^c,-(r1) ; j reeds sept 81. + 168 000450 005067 000000G 3$: clr rolupd ;set for inner scan + 169 000454 012701 000000G 4$: mov #symbol,r1 + 170 000460 call gsddmp ;output this block + 1 000460 004767 000134 jsr pc,gsddmp + 171 000464 5$: next symrol ;fetch the next symbol + 1 000464 012700 000000G mov #symrol,r0 + 2 .globl next + 3 000470 call next + 1 000470 004767 000000G jsr pc,next + 172 000474 001745 beq 2$ ; finished with this guy + 173 000476 032767 000100 000000G bit #glbflg,mode ;global? + 174 000504 001767 beq 5$ ; no + 175 000506 032767 000001 000000G bit #regflg,mode ;is register (prevent god's wrath) + 176 000514 001363 bne 5$ ;no global registers with ==* + 177 000516 126705 000000G cmpb sector,r5 ;yes, proper sector? + 178 000522 001360 bne 5$ ; no + 179 000524 042767 177427 000000G bic #^c,mode ;clear most (leave hk up) + 180 000532 052767 002000 000000G bis #gsdt04,mode ;set type 4 + 181 000540 000745 br 4$ ;output it + 182 + 183 + 184 000542 042767 177737 000004G 6$: bic #^c,endvec+4 ;clear all but rel flag + 185 000550 052767 001410 000004G bis #gsdt03+defflg,endvec+4 + 186 000556 012701 000000G mov #endvec,r1 + 187 000562 call gsddmp ;output end block + 1 000562 004767 000032 jsr pc,gsddmp + 188 000566 call objdmp ;dump it + 1 000566 004767 000542 jsr pc,objdmp + 189 000572 012777 000002 000000C mov #blkt02,@buftbl+objchn ;set "end of gsd" + 190 000600 call objdmf + 1 000600 004767 000552 jsr pc,objdmf + 191 000604 012777 000017 000000C mov #blkt17,@buftbl+objchn ;init for text blocks + 192 9$: + 193 000612 005267 000000G inc pass ;set for pass 2 + 194 000616 return + 1 000616 000207 rts pc + 195 + 196 + 197 gsddmp: ;dump a gsd block + 198 000620 call setrld + 1 000620 004767 000660 jsr pc,setrld + 199 000624 xmit 4 + 1 .globl xmit0 + 2 000624 call xmit0-<4*2> + 1 000624 004767 177770G jsr pc,xmit0-<4*2> + 200 000630 000167 000564 jmp dmprld + 200 + 201 endp2c: + 202 000634 005767 000022' tst objpnt ;any object output? + 203 000640 001426 beq 1$ ; no + 204 000642 call objdmp ;yes, dump it + 1 000642 004767 000466 jsr pc,objdmp + 205 000001 .if ne,mk.symbol + 206 000646 005767 000020' tst out$ym + 207 000652 001422 beq 22$ + 208 .endc + 209 000654 012777 000006 000000C 32$: mov #blkt06,@buftbl+objchn ;set end + 210 000662 call objdmf ;dump it + 1 000662 004767 000470 jsr pc,objdmf + 211 .if ndf xedabs + 212 000666 032767 000000G 000000G bit #ed.abs,edmask ;abs output? + 213 000674 001010 bne 1$ ; no + 214 000676 016700 000022' mov objpnt,r0 + 215 000702 016720 000006G mov endvec+6,(r0)+ ;set end vector + 216 000706 010067 000022' mov r0,objpnt + 217 000712 call objdmp + 1 000712 004767 000416 jsr pc,objdmp + 218 .endc + 219 000716 1$: return + 1 000716 000207 rts pc + 220 + 221 000001 .if ne,mk.symbol + 222 000720 012777 000022 000000C 22$: mov #blkssym,@buftbl+objchn + 223 000726 005067 000000G clr rolupd + 224 000732 3$: next symrol + 1 000732 012700 000000G mov #symrol,r0 + 2 .globl next + 3 000736 call next + 1 000736 004767 000000G jsr pc,next + 225 000742 001411 beq 31$ + 226 000744 032767 000100 000000G bit #glbflg,mode + 227 000752 001367 bne 3$ + 228 000754 012701 000000G mov #symbol,r1 + 229 000760 call gsddmp + 1 000760 004767 177634 jsr pc,gsddmp + 230 000764 000762 br 3$ + 231 + 232 000766 005767 000022' 31$: tst objpnt + 233 000772 001402 beq 30$ + 234 000774 call objdmp + 1 000774 004767 000334 jsr pc,objdmp + 235 30$: + 236 001000 call locdmp + 1 001000 004767 000506 jsr pc,locdmp + 237 001004 012777 000021 000000C mov #blksye,@buftbl+objchn + 238 001012 005767 000022' tst objpnt + 239 001016 001716 beq 32$ + 240 001020 call objdmf + 1 001020 004767 000332 jsr pc,objdmf + 241 001024 000713 br 32$ + 242 + 243 001026 entsec impure + 1 000020 .psect impure con + 244 000020 out$ym: .blkw 1 + 245 000022 xitsec + 1 000022 entsec .text + 1 001026 .psect .text con + 246 + 247 000021 blksye=21 + 248 000022 blkssys=22 + 249 + 250 .globl out$ym + 251 .endc + 252 + 252 + 253 .sbttl code roll handlers + 254 + 255 001026 stcode: append codrol ;append to codrol + 1 001026 012700 000000G mov #codrol,r0 + 2 .globl append + 3 001032 call append + 1 001032 004767 000000G jsr pc,append + 256 001036 return + 1 001036 000207 rts pc + 257 + 258 .globl pcrcnt + 259 pcroll: ; + 260 001040 next codrol + 1 001040 012700 000000G mov #codrol,r0 + 2 .globl next + 3 001044 call next + 1 001044 004767 000000G jsr pc,next + 261 001050 001477 beq 9$ + 262 001052 call savreg + 1 001052 004767 000000G jsr pc,savreg + 263 001056 116704 000000G movb sector,r4 + 264 001062 005767 000000G tst pass + 265 001066 001453 beq 7$ + 266 001070 005267 000000' inc pcrcnt + 267 001074 001002 bne 1$ + 268 001076 call setpf0 + 1 001076 004767 000000G jsr pc,setpf0 + 269 001102 1$: call setpf1 + 1 001102 004767 000000G jsr pc,setpf1 + 270 001106 005767 000022' tst objpnt + 271 001112 001441 beq 7$ + 272 .if ndf xedpnc + 273 001114 032767 000000G 000000G bit #ed.pnc,edmask + 274 001122 001035 bne 7$ + 275 .endc + 276 001124 call setrld + 1 001124 004767 000354 jsr pc,setrld + 277 001130 010446 mov r4,-(sp) + 278 001132 012704 000070 mov #cc.sec!cc.nam!cc.opr,r4 + 279 001136 126767 000000G 000001' cmpb clcsec,objsec + 280 001144 001006 bne 2$ + 281 001146 026767 000000G 000002' cmp clcloc,objloc + 282 001154 001411 beq 3$ + 283 001156 042704 000020 bic #cc.nam,r4 + 284 001162 012701 000000G 2$: mov #clcnam,r1 + 285 001166 call pcrolx + 1 001166 004767 000060 jsr pc,pcrolx + 286 001172 105022 clrb (r2)+ + 287 001174 call dmprld + 1 001174 004767 000220 jsr pc,dmprld + 288 001200 012604 3$: mov (sp)+,r4 + 289 001202 012701 000000G mov #symbol,r1 + 290 001206 call pcrolx + 1 001206 004767 000040 jsr pc,pcrolx + 291 001212 call dmprld + 1 001212 004767 000202 jsr pc,dmprld + 292 001216 005267 000000G 7$: inc clcloc + 293 001222 105704 tstb r4 + 294 001224 100402 bmi 8$ + 295 001226 005267 000000G inc clcloc + 296 001232 116767 000000G 000001' 8$: movb clcsec,objsec + 297 001240 016767 000000G 000002' mov clcloc,objloc + 298 001246 setnz r0 + 1 001246 010600 mov sp,r0 + 299 001250 9$: return + 1 001250 000207 rts pc + 299 + 300 pcrolx: + 301 001252 110422 movb r4,(r2)+ + 302 001254 032704 000020 bit #cc.nam,r4 + 303 001260 001405 beq 3$ + 304 .rept 4 + 305 movb (r1)+,(r2)+ + 306 .endm + 1 001262 112122 movb (r1)+,(r2)+ + 1 001264 112122 movb (r1)+,(r2)+ + 1 001266 112122 movb (r1)+,(r2)+ + 1 001270 112122 movb (r1)+,(r2)+ + 307 001272 024141 cmp -(r1),-(r1) + 308 001274 062701 000006 3$: add #6,r1 + 309 001300 005711 tst (r1) + 310 001302 001407 beq 4$ + 311 001304 112122 movb (r1)+,(r2)+ + 312 001306 152767 000004 000024' bisb #cc.val,rldtmp + 313 001314 105704 tstb r4 + 314 001316 100401 bmi 4$ + 315 001320 112122 movb (r1)+,(r2)+ + 316 001322 4$: return + 1 001322 000207 rts pc + 317 + 318 001324 entsec implin + 1 000000 .psect implin con + 319 000000 pcrcnt: .blkw ;extension line flag + 319 + 320 000002 entsec imppas + 1 000000 .psect imppas con + 321 000000 000 .odd + 322 000001 objsec: .blkb 1 ;object file sector + 323 000002 objloc: .blkw 1 ;object file location + 324 + 325 + 326 + 327 + 328 + 329 .if ndf xedpnc + 330 000004 genedt pnc,pncset ;punch control + 1 000004 entsec edtsec + 1 000000 .psect edtsec con + 2 000000 063063 .rad50 /pnc/ + 3 .if nb pncset + 4 000002 001324' .word pncset + 5 .iff + 6 .word cpopj + 7 .endc + 8 000004 000000G .word ed.pnc + 9 000006 xitsec + 1 000006 entsec .text + 1 001324 .psect .text con + 331 + 332 001324 112767 000377 000001' pncset: movb #377,objsec ;force sequence break + 333 001332 return + 1 001332 000207 rts pc + 334 .endc + 334 + 335 objdmp: ;dump the object buffer + 336 001334 005767 000022' tst objpnt + 337 001340 001426 beq objinx ;exit if not pre-set + 338 001342 016700 000000C mov buftbl+objchn,r0 + 339 001346 005720 tst (r0)+ ;ignore first word + 340 001350 026700 000022' cmp objpnt,r0 ;anything in rld? + 341 001354 101412 blos objini ; no, just init + 342 objdmf: + 343 001356 016777 000022' 000000C mov objpnt,@cnttbl+objchn + 344 001364 166777 000000C 000000C sub buftbl+objchn,@cnttbl+objchn ;compute byte count + 345 001372 zwrite obj + 1 .globl zwrite + 2 001372 012700 000000G mov #objchn,r0 + 3 001376 call zwrite + 1 001376 004767 000000G jsr pc,zwrite + 346 + 347 001402 016767 000000C 000022' objini: mov buftbl+objchn,objpnt + 348 001410 062767 000002 000022' add #2,objpnt ;reserve word for block type + 349 001416 objinx: return + 1 001416 000207 rts pc + 350 + 351 001420 005767 000022' dmprld: tst objpnt + 352 001424 001427 beq setrld + 353 001426 010146 mov r1,-(sp) ;save byte count + 354 001430 012701 000024' mov #rldtmp,r1 + 355 001434 010200 mov r2,r0 + 356 001436 160100 sub r1,r0 + 357 001440 001420 beq 9$ + 358 001442 066700 000022' add objpnt,r0 + 359 001446 166700 000000C sub buftbl+objchn,r0 + 360 001452 020027 000000G cmp r0,#objlen ;room to store? + 361 001456 101402 blos 1$ ; yes + 362 001460 call objdmp ;no, dump current + 1 001460 004767 177650 jsr pc,objdmp + 363 001464 016700 000022' 1$: mov objpnt,r0 ;return with pointer in r2 + 364 001470 112120 2$: movb (r1)+,(r0)+ + 365 001472 020102 cmp r1,r2 + 366 001474 103775 blo 2$ + 367 001476 010067 000022' mov r0,objpnt + 368 001502 012601 9$: mov (sp)+,r1 + 369 001504 012702 000024' setrld: mov #rldtmp,r2 + 370 001510 return + 1 001510 000207 rts pc + 371 + 372 001512 entsec impure + 1 000022 .psect impure con + 373 000022 objpnt: .blkw + 374 000024 rldtmp: .blkb 100. + 375 000170 xitsec + 1 000170 entsec .text + 1 001512 .psect .text con + 376 + 377 + 378 001512 xitsec + 1 001512 entsec .text + 1 001512 .psect .text con + 379 .globl sx.flg ,lsyrol + 380 locdmp: + 381 001512 call savreg + 1 001512 004767 000000G jsr pc,savreg + 382 001516 010046 mov r0,-(sp) + 383 001520 005767 000000G tst sx.flg + 384 001524 001427 beq 9$ + 385 001526 005067 000000G clr rolupd + 386 1$: + 387 001532 next lsyrol + 1 001532 012700 000000G mov #lsyrol,r0 + 2 .globl next + 3 001536 call next + 1 001536 004767 000000G jsr pc,next + 388 001542 001413 beq 2$ + 389 001544 032767 000100 000000G bit #glbflg,mode + 390 001552 001367 bne 1$ + 391 001554 call unlocl + 1 001554 004767 000030 jsr pc,unlocl + 392 001560 012701 000000G mov #symbol,r1 + 393 001564 call gsddmp + 1 001564 004767 177030 jsr pc,gsddmp + 394 001570 000760 br 1$ + 395 2$: + 396 001572 005767 000022' tst objpnt + 397 001576 001402 beq 9$ + 398 001600 call objdmp + 1 001600 004767 177530 jsr pc,objdmp + 399 9$: + 400 001604 012600 mov (sp)+,r0 + 401 001606 return + 1 001606 000207 rts pc + 402 + 403 .globl dnc ,chrpnt, getsym,..z + 404 unlocl: + 405 001610 call savreg + 1 001610 004767 000000G jsr pc,savreg + 406 001614 010046 mov r0,-(sp) + 407 001616 012702 000000' mov #work.x,r2 + 408 001622 016701 000002G mov symbol+2,r1 + 409 001626 call dnc + 1 001626 004767 000000G jsr pc,dnc + 410 001632 112722 000044 movb #'$,(r2)+ + 411 001636 112722 000000 movb #0,(r2)+ + 412 001642 call tor50 + 1 001642 004767 000004 jsr pc,tor50 + 413 001646 012600 mov (sp)+,r0 + 414 001650 return + 1 001650 000207 rts pc + 415 001652 entsec mixed + 1 000000 .psect mixed con + 416 000000 work.x: .blkw 5 + 417 000012 xitsec + 1 000012 entsec .text + 1 001652 .psect .text con + 418 tor50: + 419 001652 call savreg + 1 001652 004767 000000G jsr pc,savreg + 420 001656 012704 000000' mov #work.x,r4 + 421 001662 call 1$ + 1 001662 004767 000022 jsr pc,1$ + 422 001666 010067 000000G mov r0,symbol + 423 001672 012704 000003' mov #3+work.x,r4 + 424 001676 call 1$ + 1 001676 004767 000006 jsr pc,1$ + 425 001702 010067 000002G mov r0,2+symbol + 426 001706 return + 1 001706 000207 rts pc + 427 1$: + 428 001710 005003 clr r3 + 429 001712 105714 tstb (r4) + 430 001714 001402 beq 10$ + 431 001716 112400 movb (r4)+,r0 + 432 001720 000401 br 20$ + 433 001722 111400 10$: movb (r4),r0 + 434 001724 010002 20$: mov r0,r2 + 435 001726 call 40$ + 1 001726 004767 000062 jsr pc,40$ + 436 001732 010003 mov r0,r3 + 437 001734 010301 mov r3,r1 + 438 001736 070127 000050 mul #50,r1 + 439 001742 010103 mov r1,r3 + 440 001744 105714 tstb (r4) + 441 001746 001402 beq 12$ + 442 001750 112400 movb (r4)+,r0 + 443 001752 000401 br 21$ + 444 001754 111400 12$: movb (r4),r0 + 445 001756 010002 21$: mov r0,r2 + 446 001760 call 40$ + 1 001760 004767 000030 jsr pc,40$ + 447 001764 060003 add r0,r3 + 448 001766 010301 mov r3,r1 + 449 001770 070127 000050 mul #50,r1 + 450 001774 010103 mov r1,r3 + 451 001776 111400 movb (r4),r0 + 452 002000 010002 mov r0,r2 + 453 002002 call 40$ + 1 002002 004767 000006 jsr pc,40$ + 454 002006 060003 add r0,r3 + 455 002010 010300 mov r3,r0 + 456 002012 return + 1 002012 000207 rts pc + 457 40$: + 458 002014 122702 000044 cmpb #44,r2 + 459 002020 001005 bne 30$ + 460 002022 012700 000033 mov #33,r0 + 461 002026 000401 br 9$ + 462 002030 005000 14$: clr r0 + 463 002032 9$: return + 1 002032 000207 rts pc + 464 002034 105702 30$: tstb r2 + 465 002036 001774 beq 14$ + 466 002040 122702 000040 cmpb #40,r2 + 467 002044 001771 beq 14$ + 468 002046 110200 movb r2,r0 + 469 002050 062700 177756 add #-22,r0 + 470 002054 000766 br 9$ + 471 .end + 472 + 473 .end + 473 + 8 + + +Symbol table + +$TIMDF=000007 4$6 001322R L 002 CLCLOC=****** G LBLFLG=000002 RLDTMP 000024R 008 +. ******R 002 40$9 002014R L 002 CLCNAM=****** G LF =000012 ROLUPD=****** G +..Z =****** G 5$3 000464R L 002 CLCSEC=****** G LIMIT 000210RG 002 RSX11D=000000 +1$0 000164R L 002 6$3 000542R L 002 CNTTBL=****** G LOCDMP 001512R 002 SAVREG=****** G +1$1 000214R L 002 7$5 001216R L 002 CODROL=****** G LSYROL=****** G SECROL=****** G +1$2 000300R L 002 8$5 001232R L 002 CR =000015 M.IDF =000007 SECTOR=****** G +1$3 000406R L 002 9$3 000612R L 002 DEBUG =000000 MDFFLG=000004 SETDS1 000100R 002 +1$4 000716R L 002 9$5 001250R L 002 DEFFLG=000010 MK.SYM=000001 SETDS2 000112R 002 +1$5 001102R L 002 9$7 001502R L 002 DFGFLG=000200 MODE =****** G SETDS3 000136R 002 +1$7 001464R L 002 9$8 001604R L 002 DFLGBM=****** G NEXT =****** G SETDSP 000042RG 002 +1$8 001532R L 002 9$9 002032R L 002 DMPRLD 001420RG 002 OBJCHN=****** G SETDSX 000142R 002 +1$9 001710R L 002 AATTRS=000130 DNC =****** G OBJDMF 001356R 002 SETIMM 000000RG 002 +10$9 001722R L 002 ABSERR=****** G ED.ABS=****** G OBJDMP 001334R 002 SETPF0=****** G +12$9 001754R L 002 APPEND=****** G ED.PNC=****** G OBJINI 001402R 002 SETPF1=****** G +14$9 002030R L 002 B.IDF =000001 EDMASK=****** G OBJINX 001416R 002 SETRLD 001504RG 002 +2$0 000172R L 002 BLKSSY=000022 ENDP1C 000340RG 002 OBJLEN=****** G SETSEC=****** G +2$3 000410R L 002 BLKSYE=000021 ENDP2C 000634RG 002 OBJLOC 000002R 009 SETXPR=****** G +2$5 001162R L 002 BLKT01=000001 ENDVEC=****** G OBJPNT 000022R 008 SHRFLG=000001 +2$7 001470R L 002 BLKT02=000002 FF =000014 OBJSEC 000001RG 009 SPACE =000040 +2$8 001572R L 002 BLKT03=000003 FT.ID =000001 OPCLAS=****** G STCODE 001026RG 002 +20$9 001724R L 002 BLKT04=000004 FT.UNX=000001 OUT$YM 000020RG 008 SX.FLG=****** G +21$9 001756R L 002 BLKT05=000005 GETSYM=****** G OVRFLG=000020 SYMBOL=****** G +22$4 000720R L 002 BLKT06=000006 GLBFLG=000100 PASS =****** G SYMROL=****** G +3$0 000176R L 002 BLKT17=000017 GSDDMP 000620R 002 PATTRS=000050 TAB =000011 +3$3 000450R L 002 BPMB =000020 GSDT00=000000 PCRCNT 000000RG 010 TOR50 001652R 002 +3$4 000732R L 002 BSSFLG=000004 GSDT01=000400 PCROLL 001040RG 002 UNLOCL 001610R 002 +3$5 001200R L 002 BUFTBL=****** G GSDT02=001000 PCROLX 001252R 002 VALUE =****** G +3$6 001274R L 002 CATTRS=000170 GSDT03=001400 PDPV45=000000 VT =000013 +30$4 001000R L 002 CC.DSP=000002 GSDT04=002000 PNCSET 001324R 002 WORK.X 000000R 006 +30$9 002034R L 002 CC.NAM=000020 GSDT05=002400 PRGIDN 000010R 008 X40 =000000 +31$4 000766R L 002 CC.OPR=000040 GSDT06=003000 PRGTTL 000000RG 008 XMIT0 =****** G +32$4 000654R L 002 CC.SEC=000010 IDENT 000264RG 002 RAD50 =****** G ZAP =****** G +4$0 000204R L 002 CC.VAL=000004 INSFLG=000002 REGFLG=000001 ZWRITE=****** G +4$3 000454R L 002 CHRPNT=****** G IOFTBL=****** G RELFLG=000040 + + +Program sections: + +. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) + 000000 001 (RW,I,LCL,REL,CON,NOSAV) +.TEXT 002056 002 (RW,I,LCL,REL,CON,NOSAV) +.DATA 000000 003 (RW,I,LCL,REL,CON,NOSAV) +.BSS 000000 004 (RW,I,LCL,REL,CON,NOSAV) +DPURE 000000 005 (RW,I,LCL,REL,CON,NOSAV) +MIXED 000012 006 (RW,I,LCL,REL,CON,NOSAV) +ERRMES 000000 007 (RW,I,LCL,REL,CON,NOSAV) +IMPURE 000170 008 (RW,I,LCL,REL,CON,NOSAV) +IMPPAS 000004 009 (RW,I,LCL,REL,CON,NOSAV) +IMPLIN 000002 010 (RW,I,LCL,REL,CON,NOSAV) +SWTSEC 000000 011 (RW,I,LCL,REL,CON,NOSAV) +CNDSEC 000000 012 (RW,I,LCL,REL,CON,NOSAV) +CRFSEC 000000 013 (RW,I,LCL,REL,CON,NOSAV) +EDTSEC 000006 014 (RW,I,LCL,REL,CON,NOSAV) +LCTSEC 000000 015 (RW,I,LCL,REL,CON,NOSAV) +PSASEC 000000 016 (RW,I,LCL,REL,CON,NOSAV) +PSTSEC 000000 017 (RW,I,LCL,REL,CON,NOSAV) +ROLBAS 000000 018 (RW,I,LCL,REL,CON,NOSAV) +ROLSIZ 000000 019 (RW,I,LCL,REL,CON,NOSAV) +ROLTOP 000000 020 (RW,I,LCL,REL,CON,NOSAV) +XPCOR 000000 021 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/2.11BSD-m11-debug.lst.ok b/tests/2.11BSD-m11-debug.lst.ok new file mode 100644 index 0000000..b5ce3f1 --- /dev/null +++ b/tests/2.11BSD-m11-debug.lst.ok @@ -0,0 +1,659 @@ + 1 ;;;; Wrapper for 2.11BSD/m11/debug.m11 + 2 .list + 3 .list + 4 .list + 5 .enabl lc + 6 000001 debug = 1 + 7 .include "2.11BSD/m11/at.sml" + 1 .title at.sml - assembler/translator system macros + 2 ; @(#)at.sml 1.3 11/3/82 + 3 + 4 .ident /10may4/ + 5 + 6 .macro always ;all files of macro + 7 + 8 .macro .data + 9 entsec .data + 10 .endm .data + 11 + 12 .macro .text + 13 entsec .text + 14 .endm + 15 + 16 .macro .bss + 17 entsec .bss + 18 .endm + 19 + 20 mk.symbol=1 ;one to make symbols, 0 otherwise + 21 x40= 0 + 22 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs. + 23 ; if not you will have to write macros for them + 24 $timdf= 7 ; California Time Zone + 25 ; should really use ftime(2) for this and for + 26 ; DST. + 27 ;xfltg= 0 ;define to assmbl out floating hardware + 28 rsx11d = 0 ; rsx11d features + 29 debug = 0 ; <<< REEDS if non zero includes debug junk + 30 + 31 ft.id= 1 ;have set i & d. set =0 if not + 32 + 33 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not. + 34 + 35 .nlist bex + 36 + 37 tab= 11 + 38 lf= 12 + 39 vt= 13 + 40 ff= 14 + 41 cr= 15 + 42 space= 40 + 43 + 44 bpmb = 20 ;bytes per macro block + 45 + 46 + 47 + 48 + 49 + 50 .psect .text con, shr, gbl,ins + 51 .psect .data con, dat, prv, gbl + 52 .psect .bss con, bss, gbl + 53 + 54 .psect dpure con, dat, prv, gbl + 55 .psect mixed con, prv, gbl + 56 .psect errmes con, dat, prv, gbl + 57 .psect impure con, bss, gbl + 58 .psect imppas con, bss, gbl + 59 .psect implin con, bss, gbl + 60 .psect swtsec con, dat, prv, gbl ; unix command line flags + 61 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if' + 62 .psect crfsec con, dat, prv, gbl ; args for -cr flag + 63 .psect edtsec con, dat, prv, gbl ; args for .enabl + 64 .psect lctsec con, dat, prv, gbl ; args for .list + 65 .psect psasec con, dat, prv, gbl + 66 .psect pstsec con, dat, prv, gbl + 67 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables + 68 .psect rolsiz con, dat, prv, gbl ; sizes of table entries + 69 .psect roltop con, dat, prv, gbl ; tops of tables + 70 .psect xpcor con,bss , gbl ; this one MUST come last in core + 71 + 72 + 72 + 73 .macro entsec name ;init a section + 74 .psect name con + 75 .endm entsec + 76 + 77 + 78 + 79 .macro jeq x,?fred + 80 bne fred + 81 jmp x + 82 fred: + 83 .endm + 84 .macro jne x,?fred + 85 beq fred + 86 jmp x + 87 fred: + 88 .endm + 89 .macro xitsec + 90 entsec .text + 91 .endm xitsec + 92 + 93 + 94 .macro call address + 95 jsr pc,address + 96 .endm + 97 + 98 .macro return + 99 rts pc + 100 .endm + 101 + 102 + 103 .macro always + 104 .nlist bex + 105 .endm always + 106 .endm always + 107 + 108 + 109 000001 .if ne debug + 110 + 111 .macro ndebug n + 112 .globl ndebug,..z + 113 mov n,..z + 114 call ndebug + 115 .endm + 116 + 117 .macro sdebug string + 118 .globl sdebug,..z,..zbuf + 119 x = 0 + 120 .irpc t, + 121 movb #''t,..zbuf+x + 122 x = x+1 + 123 .endm + 124 movb #0,..zbuf+x + 125 mov #..zbuf,..z + 126 call sdebug + 127 .endm + 128 + 129 .iff + 130 + 131 .macro ndebug n + 132 .endm + 133 + 134 .macro sdebug string + 135 .endm + 136 + 137 .endc + 138 + 139 + 140 .macro param mne, value ;define default parameters + 141 .iif ndf mne, mne= value + 142 .list + 143 mne= mne + 144 .nlist + 145 .endm + 145 + 146 .macro putkb addr ;list to kb + 147 .globl putkb + 148 mov addr,r0 + 149 call putkb + 150 .endm + 151 + 152 .macro putlp addr ;list to lp + 153 .globl putlp + 154 mov addr,r0 + 155 call putlp + 156 .endm + 157 + 158 .macro putkbl addr ;list to kb and lp + 159 .globl putkbl + 160 mov addr,r0 + 161 call putkbl + 162 .endm + 163 + 164 + 165 .macro xmit wrdcnt ;move small # of words + 166 .globl xmit0 + 167 call xmit0- + 168 .endm xmit + 169 + 170 + 171 ;the macro "genswt" is used to specify a command + 172 ;string switch (1st argument) and the address of + 173 ;the routine to be called when encountered (2nd arg). + 174 ; the switch is made upper-case. + 175 + 176 .macro genswt mne,addr,?label + 177 entsec swtsec + 178 label: .irpc x,mne + 179 .if ge ''x-141 + 180 .if le ''x-172 + 181 .byte ''x-40 + 182 .iff + 183 .byte ''x + 184 .endc + 185 .iff + 186 .byte ''x + 187 .endc + 188 .endm + 189 .iif ne <.-label&1>, .byte 0 + 190 .word addr + 191 xitsec + 192 .endm + 192 + 193 .macro zread chan + 194 .globl zread + 195 mov #chan'chn,r0 + 196 call zread + 197 .endm zread + 198 + 199 .macro zwrite chan + 200 .globl zwrite + 201 mov #chan'chn,r0 + 202 call zwrite + 203 .endm zwrite + 203 + 204 .macro genedt mne,subr ;gen enable/disable table + 205 entsec edtsec + 206 .rad50 /mne/ + 207 .if nb subr + 208 .word subr + 209 .iff + 210 .word cpopj + 211 .endc + 212 .word ed.'mne + 213 xitsec + 214 .endm genedt + 215 + 216 + 217 ;the macro "gencnd" is used to specify conditional + 218 ;arguments. it takes two or three arguments: + 219 + 220 ; 1- mnemonic + 221 ; 2- subroutine to be called + 222 ; 3- if non-blank, complement condition + 223 + 224 .macro gencnd mne,subr,toggle ;generate conditional + 225 entsec cndsec + 226 .rad50 /mne/ + 227 .if b + 228 .word subr + 229 .iff + 230 .word subr+1 + 231 .endc + 232 xitsec + 233 .endm + 233 + 234 .macro ch.mne + 235 + 236 ch.ior= '! + 237 ch.qtm= '" + 238 ch.hsh= '# + 239 ch.dol= '$ + 240 ch.pct= '% + 241 ch.and= '& + 242 ch.xcl= '' + 243 + 244 ch.lp= '( + 245 ch.rp= ') + 246 ch.mul= '* + 247 ch.add= '+ + 248 ch.com= ', + 249 ch.sub= '- + 250 ch.dot= '. + 251 ch.div= '/ + 252 + 253 ch.col= ': + 254 ch.smc= '; + 255 ch.lab= '< + 256 ch.equ= '= + 257 ch.rab= '> + 258 ch.qm= '? + 259 + 260 ch.ind= '@ + 261 ch.bsl= '\ + 262 ch.uar= '^ + 263 + 264 let.a= 'a&^c40 + 265 let.b= 'b&^c40 + 266 let.c= 'c&^c40 + 267 let.d= 'd&^c40 + 268 let.e= 'e&^c40 + 269 let.f= 'f&^c40 + 270 let.g= 'g&^c40 + 271 let.o= 'o&^c40 + 272 let.p= 'p&^c40 + 273 let.r= 'r&^c40 + 274 let.z= 'z&^c40 + 275 + 276 dig.0= '0 + 277 dig.9= '9 + 278 .macro ch.mne + 279 .endm ch.mne + 280 .endm ch.mne + 281 + 282 .macro error num,arg, mess ,?x + 283 sdebug + 284 .globl err.'arg,ern'num, errbts,errref + 285 .if b + 286 deliberate error mistake + 287 .endc + 288 .if dif 0,num + 289 .globl err.xx + 290 tst err.xx + 291 bne x + 292 mov #ern'num,err.xx + 293 x: + 294 .endc + 295 bis #err.'arg,errbts + 296 .endm + 297 + 298 + 299 + 300 .macro setnz addr ;set addr to non-zero for t/f flags + 301 mov sp,addr + 302 .endm + 303 + 304 + 305 .macro bisbic arg ; used by .list/.nlist, .enabl/.dsabl + 306 .globl bisbic + 307 mov #arg,-(sp) + 308 call bisbic + 309 tst (sp)+ + 310 .endm + 310 + 311 ;roll handler calls + 312 + 313 .macro search rolnum ;binary search + 314 mov #rolnum,r0 + 315 .globl search + 316 call search + 317 .endm + 318 + 319 .macro scan rolnum ;linear scan + 320 mov #rolnum,r0 + 321 .globl scan + 322 call scan + 323 .endm + 324 + 325 .macro scanw rolnum ;linear scan, one word + 326 mov #rolnum,r0 + 327 .globl scanw + 328 call scanw + 329 .endm + 330 + 331 .macro next rolnum ;fetch next entry + 332 mov #rolnum,r0 + 333 .globl next + 334 call next + 335 .endm + 336 + 337 .macro append rolnum ;append to end of roll + 338 mov #rolnum,r0 + 339 .globl append + 340 call append + 341 .endm + 342 + 343 .macro zap rolnum ;clear roll + 344 mov #rolnum,r0 + 345 .globl zap + 346 call zap + 347 .endm + 348 + 349 ; call insert ;insert (must be preceded by one + 350 ;of the above to set pointers) + 351 ; call setrol ;save and set regs for above + 351 + 352 ;flags used in symbol table mode + 353 + 354 .macro st.flg + 355 + 356 .if le ft.unx + 357 + 358 ovrflg= 000004 ;overlay (psect only) + 359 defflg= 000010 ;defined + 360 relflg= 000040 ;relocatable + 361 glbflg= 000100 ;global + 362 dfgflg= 000200 ; default global ... reeds's guess + 363 + 364 + 365 .endc + 366 + 367 .if gt ft.unx + 368 + 369 ; ****** these should not be changed!! ****** + 370 shrflg= 000001 ;shareable (psect only) + 371 .if gt ft.id + 372 insflg= shrflg*2 ;instruction space (psect only) + 373 bssflg= insflg*2 ;blank section (psect only) + 374 m.idf= shrflg!insflg!bssflg ;mask to turn them off + 375 .iff + 376 bssflg= shrflg*2 + 377 m.idf= shrflg!bssflg + 378 .endc + 379 b.idf= 1 ;shift count to make above bits word offset + 380 ; *********************************** + 381 defflg= 000010 ;defined + 382 ovrflg= 000020 ;overlay (psect only) + 383 relflg= 000040 ;relocatable + 384 glbflg= 000100 ;global + 385 dfgflg= 000200 ; default global ... reeds's guess + 386 + 387 .endc + 388 + 389 ; + 390 ; default psect attribs. + 391 ; can be changed, but make sure all customers know about + 392 ; it, including all the linkers. + 393 ; + 394 pattrs=relflg!defflg ; For .psects and blank .csects + 395 aattrs=glbflg!defflg!ovrflg ; For .asect + 396 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects + 397 + 398 regflg= 000001 ;register + 399 lblflg= 000002 ;label + 400 mdfflg= 000004 ;multilpy defined + 401 .macro st.flg + 402 .endm + 403 .endm st.flg + 404 + 405 + 406 + 407 .macro ct.mne + 408 .globl cttbl + 409 ct.eol = 000 ; eol + 410 ct.com = 001 ; comma + 411 ct.tab = 002 ; tab + 412 ct.sp = 004 ; space + 413 ct.pcx = 010 ; printing character + 414 ct.num = 020 ; numeric + 415 ct.alp = 040 ; alpha, dot, dollar + 416 ct.lc = 100 ; lower case alpha + 417 ct.smc = 200 ; semi-colon (sign bit) + 418 + 419 ct.pc = ct.com!ct.smc!ct.pcx!ct.num!ct.alp + 420 .macro ct.mne + 421 .endm ct.mne + 422 .endm ct.mne + 423 + 424 + 425 .end + 425 + 8 .include "2.11BSD/m11/debug.m11" + 1 .mcall (at) always + 2 .globl $write + 3 + 4 .globl ndebug,sdebug, ..z,..zbuf + 5 .globl savreg,dnc + 6 .globl xx.flg + 7 000000 always + 1 + 2 .macro .data + 3 entsec .data + 4 .endm .data + 5 + 6 .macro .text + 7 entsec .text + 8 .endm + 9 + 10 .macro .bss + 11 entsec .bss + 12 .endm + 13 + 14 000001 mk.symbol=1 ;one to make symbols, 0 otherwise + 15 000000 x40= 0 + 16 000000 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs. + 17 ; if not you will have to write macros for them + 18 000007 $timdf= 7 ; California Time Zone + 19 ; should really use ftime(2) for this and for + 20 ; DST. + 21 ;xfltg= 0 ;define to assmbl out floating hardware + 22 000000 rsx11d = 0 ; rsx11d features + 23 000000 debug = 0 ; <<< REEDS if non zero includes debug junk + 24 + 25 000001 ft.id= 1 ;have set i & d. set =0 if not + 26 + 27 000001 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not. + 28 + 29 .nlist bex + 30 + 31 000011 tab= 11 + 32 000012 lf= 12 + 33 000013 vt= 13 + 34 000014 ff= 14 + 35 000015 cr= 15 + 36 000040 space= 40 + 37 + 38 000020 bpmb = 20 ;bytes per macro block + 39 + 40 + 41 + 42 + 43 +./2.11BSD/m11/debug.m11:7->ALWAYS:44: ***ERROR Unknown flag SHR given to .PSECT directive + 44 .psect .text con, shr, gbl,ins +./2.11BSD/m11/debug.m11:7->ALWAYS:45: ***ERROR Unknown flag DAT given to .PSECT directive + 45 .psect .data con, dat, prv, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:46: ***ERROR Unknown flag BSS given to .PSECT directive + 46 .psect .bss con, bss, gbl + 47 +./2.11BSD/m11/debug.m11:7->ALWAYS:48: ***ERROR Unknown flag DAT given to .PSECT directive + 48 .psect dpure con, dat, prv, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:49: ***ERROR Unknown flag PRV given to .PSECT directive + 49 .psect mixed con, prv, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:50: ***ERROR Unknown flag DAT given to .PSECT directive + 50 .psect errmes con, dat, prv, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:51: ***ERROR Unknown flag BSS given to .PSECT directive + 51 .psect impure con, bss, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:52: ***ERROR Unknown flag BSS given to .PSECT directive + 52 .psect imppas con, bss, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:53: ***ERROR Unknown flag BSS given to .PSECT directive + 53 .psect implin con, bss, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:54: ***ERROR Unknown flag DAT given to .PSECT directive + 54 .psect swtsec con, dat, prv, gbl ; unix command line flags +./2.11BSD/m11/debug.m11:7->ALWAYS:55: ***ERROR Unknown flag DAT given to .PSECT directive + 55 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if' +./2.11BSD/m11/debug.m11:7->ALWAYS:56: ***ERROR Unknown flag DAT given to .PSECT directive + 56 .psect crfsec con, dat, prv, gbl ; args for -cr flag +./2.11BSD/m11/debug.m11:7->ALWAYS:57: ***ERROR Unknown flag DAT given to .PSECT directive + 57 .psect edtsec con, dat, prv, gbl ; args for .enabl +./2.11BSD/m11/debug.m11:7->ALWAYS:58: ***ERROR Unknown flag DAT given to .PSECT directive + 58 .psect lctsec con, dat, prv, gbl ; args for .list +./2.11BSD/m11/debug.m11:7->ALWAYS:59: ***ERROR Unknown flag DAT given to .PSECT directive + 59 .psect psasec con, dat, prv, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:60: ***ERROR Unknown flag DAT given to .PSECT directive + 60 .psect pstsec con, dat, prv, gbl +./2.11BSD/m11/debug.m11:7->ALWAYS:61: ***ERROR Unknown flag DAT given to .PSECT directive + 61 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables +./2.11BSD/m11/debug.m11:7->ALWAYS:62: ***ERROR Unknown flag DAT given to .PSECT directive + 62 .psect rolsiz con, dat, prv, gbl ; sizes of table entries +./2.11BSD/m11/debug.m11:7->ALWAYS:63: ***ERROR Unknown flag DAT given to .PSECT directive + 63 .psect roltop con, dat, prv, gbl ; tops of tables +./2.11BSD/m11/debug.m11:7->ALWAYS:64: ***ERROR Unknown flag BSS given to .PSECT directive + 64 .psect xpcor con,bss , gbl ; this one MUST come last in core + 65 + 66 + 67 + 68 .macro entsec name ;init a section + 69 .psect name con + 70 .endm entsec + 71 + 72 + 73 + 74 .macro jeq x,?fred + 75 bne fred + 76 jmp x + 77 fred: + 78 .endm + 79 .macro jne x,?fred + 80 beq fred + 81 jmp x + 82 fred: + 83 .endm + 84 .macro xitsec + 85 entsec .text + 86 .endm xitsec + 87 + 88 + 89 .macro call address + 90 jsr pc,address + 91 .endm + 92 + 93 .macro return + 94 rts pc + 95 .endm + 96 + 97 + 98 .macro always + 99 .nlist bex + 100 .endm always + 8 + 9 000000 xitsec + 1 000000 entsec .text + 1 000000 .psect .text con + 10 sdebug: + 11 000000 call savreg + 1 000000 004767 000000G jsr pc,savreg + 12 000004 010046 mov r0,-(sp) + 13 + 14 000006 012702 000004' mov #..s,r2 + 15 000012 016703 000002' mov ..z,r3 + 16 000016 012700 000002 mov #2,r0 + 17 000022 112322 1$: movb (r3)+,(r2)+ + 18 000024 001402 beq 2$ + 19 000026 005200 inc r0 + 20 000030 000774 br 1$ + 21 2$: + 22 000032 112712 000012 movb #12,(r2) + 23 000036 010067 000000' mov r0,..n + 24 ddd: + 25 000042 005767 000000G tst xx.flg + 26 000046 001412 beq 100$ + 27 000050 016746 000000' mov ..n,-(sp) ;write(2, ..s, ..n) + 28 000054 012746 000004' mov #..s,-(sp) + 29 000060 012746 000002 mov #2,-(sp) + 30 000064 005746 tst -(sp) ;simulate return address stack spacing + 31 000066 000000G $write + 32 000070 062706 000010 add #8.,sp ;toss syscall cruft + 33 100$: + 34 000074 012600 mov (sp)+,r0 + 35 000076 return + 1 000076 000207 rts pc + 36 ndebug: + 37 000100 call savreg + 1 000100 004767 000000G jsr pc,savreg + 38 000104 010046 mov r0,-(sp) + 39 000106 012702 000004' mov #..s,r2 + 40 000112 016701 000002' mov ..z,r1 + 41 000116 call dnc + 1 000116 004767 000000G jsr pc,dnc + 42 000122 112722 000012 movb #12,(r2)+ + 43 000126 010267 000000' mov r2,..n + 44 000132 162767 000004' 000000' sub #..s,..n + 45 000140 000740 br ddd + 46 + 47 000142 entsec mixed + 1 000000 .psect mixed con + 48 000000 ..n: .blkw + 49 000002 000000 ..z: .word + 50 000004 ..s: .blkw 100 + 51 000204 ..zbuf: .blkw 100 + 52 + 53 .end + 53 + 8 + + +Symbol table + +$TIMDF=000007 ..ZBUF 000204RG 006 DDD 000042R 002 LF =000012 SDEBUG 000000RG 002 +$WRITE=****** G 1$0 000022R L 002 DEBUG =000000 MK.SYM=000001 SPACE =000040 +. ******R 006 100$1 000074R L 002 DNC =****** G NDEBUG 000100RG 002 TAB =000011 +..N 000000R 006 2$0 000032R L 002 FF =000014 PDPV45=000000 VT =000013 +..S 000004R 006 BPMB =000020 FT.ID =000001 RSX11D=000000 X40 =000000 +..Z 000002RG 006 CR =000015 FT.UNX=000001 SAVREG=****** G XX.FLG=****** G + + +Program sections: + +. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) + 000000 001 (RW,I,LCL,REL,CON,NOSAV) +.TEXT 000142 002 (RW,I,LCL,REL,CON,NOSAV) +.DATA 000000 003 (RW,I,LCL,REL,CON,NOSAV) +.BSS 000000 004 (RW,I,LCL,REL,CON,NOSAV) +DPURE 000000 005 (RW,I,LCL,REL,CON,NOSAV) +MIXED 000404 006 (RW,I,LCL,REL,CON,NOSAV) +ERRMES 000000 007 (RW,I,LCL,REL,CON,NOSAV) +IMPURE 000000 008 (RW,I,LCL,REL,CON,NOSAV) +IMPPAS 000000 009 (RW,I,LCL,REL,CON,NOSAV) +IMPLIN 000000 010 (RW,I,LCL,REL,CON,NOSAV) +SWTSEC 000000 011 (RW,I,LCL,REL,CON,NOSAV) +CNDSEC 000000 012 (RW,I,LCL,REL,CON,NOSAV) +CRFSEC 000000 013 (RW,I,LCL,REL,CON,NOSAV) +EDTSEC 000000 014 (RW,I,LCL,REL,CON,NOSAV) +LCTSEC 000000 015 (RW,I,LCL,REL,CON,NOSAV) +PSASEC 000000 016 (RW,I,LCL,REL,CON,NOSAV) +PSTSEC 000000 017 (RW,I,LCL,REL,CON,NOSAV) +ROLBAS 000000 018 (RW,I,LCL,REL,CON,NOSAV) +ROLSIZ 000000 019 (RW,I,LCL,REL,CON,NOSAV) +ROLTOP 000000 020 (RW,I,LCL,REL,CON,NOSAV) +XPCOR 000000 021 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/2.11BSD-m11-errs.lst.ok b/tests/2.11BSD-m11-errs.lst.ok new file mode 100644 index 0000000..362513b --- /dev/null +++ b/tests/2.11BSD-m11-errs.lst.ok @@ -0,0 +1,1247 @@ + 1 ;;;; WRAPPER FOR 2.11BSD/M11/ERRS.M11 + 2 .LIST + 3 .LIST + 4 .LIST + 5 .ENABL LC + 6 000001 debug = 1 + 7 .include "2.11BSD/m11/at.sml" + 1 .title at.sml - assembler/translator system macros + 2 ; @(#)at.sml 1.3 11/3/82 + 3 + 4 .ident /10may4/ + 5 + 6 .macro always ;all files of macro + 7 + 8 .macro .data + 9 entsec .data + 10 .endm .data + 11 + 12 .macro .text + 13 entsec .text + 14 .endm + 15 + 16 .macro .bss + 17 entsec .bss + 18 .endm + 19 + 20 mk.symbol=1 ;one to make symbols, 0 otherwise + 21 x40= 0 + 22 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs. + 23 ; if not you will have to write macros for them + 24 $timdf= 7 ; California Time Zone + 25 ; should really use ftime(2) for this and for + 26 ; DST. + 27 ;xfltg= 0 ;define to assmbl out floating hardware + 28 rsx11d = 0 ; rsx11d features + 29 debug = 0 ; <<< REEDS if non zero includes debug junk + 30 + 31 ft.id= 1 ;have set i & d. set =0 if not + 32 + 33 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not. + 34 + 35 .nlist bex + 36 + 37 tab= 11 + 38 lf= 12 + 39 vt= 13 + 40 ff= 14 + 41 cr= 15 + 42 space= 40 + 43 + 44 bpmb = 20 ;bytes per macro block + 45 + 46 + 47 + 48 + 49 + 50 .psect .text con, shr, gbl,ins + 51 .psect .data con, dat, prv, gbl + 52 .psect .bss con, bss, gbl + 53 + 54 .psect dpure con, dat, prv, gbl + 55 .psect mixed con, prv, gbl + 56 .psect errmes con, dat, prv, gbl + 57 .psect impure con, bss, gbl + 58 .psect imppas con, bss, gbl + 59 .psect implin con, bss, gbl + 60 .psect swtsec con, dat, prv, gbl ; unix command line flags + 61 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if' + 62 .psect crfsec con, dat, prv, gbl ; args for -cr flag + 63 .psect edtsec con, dat, prv, gbl ; args for .enabl + 64 .psect lctsec con, dat, prv, gbl ; args for .list + 65 .psect psasec con, dat, prv, gbl + 66 .psect pstsec con, dat, prv, gbl + 67 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables + 68 .psect rolsiz con, dat, prv, gbl ; sizes of table entries + 69 .psect roltop con, dat, prv, gbl ; tops of tables + 70 .psect xpcor con,bss , gbl ; this one MUST come last in core + 71 + 72 + 72 + 73 .macro entsec name ;init a section + 74 .psect name con + 75 .endm entsec + 76 + 77 + 78 + 79 .macro jeq x,?fred + 80 bne fred + 81 jmp x + 82 fred: + 83 .endm + 84 .macro jne x,?fred + 85 beq fred + 86 jmp x + 87 fred: + 88 .endm + 89 .macro xitsec + 90 entsec .text + 91 .endm xitsec + 92 + 93 + 94 .macro call address + 95 jsr pc,address + 96 .endm + 97 + 98 .macro return + 99 rts pc + 100 .endm + 101 + 102 + 103 .macro always + 104 .nlist bex + 105 .endm always + 106 .endm always + 107 + 108 + 109 000001 .if ne debug + 110 + 111 .macro ndebug n + 112 .globl ndebug,..z + 113 mov n,..z + 114 call ndebug + 115 .endm + 116 + 117 .macro sdebug string + 118 .globl sdebug,..z,..zbuf + 119 x = 0 + 120 .irpc t, + 121 movb #''t,..zbuf+x + 122 x = x+1 + 123 .endm + 124 movb #0,..zbuf+x + 125 mov #..zbuf,..z + 126 call sdebug + 127 .endm + 128 + 129 .iff + 130 + 131 .macro ndebug n + 132 .endm + 133 + 134 .macro sdebug string + 135 .endm + 136 + 137 .endc + 138 + 139 + 140 .macro param mne, value ;define default parameters + 141 .iif ndf mne, mne= value + 142 .list + 143 mne= mne + 144 .nlist + 145 .endm + 145 + 146 .macro putkb addr ;list to kb + 147 .globl putkb + 148 mov addr,r0 + 149 call putkb + 150 .endm + 151 + 152 .macro putlp addr ;list to lp + 153 .globl putlp + 154 mov addr,r0 + 155 call putlp + 156 .endm + 157 + 158 .macro putkbl addr ;list to kb and lp + 159 .globl putkbl + 160 mov addr,r0 + 161 call putkbl + 162 .endm + 163 + 164 + 165 .macro xmit wrdcnt ;move small # of words + 166 .globl xmit0 + 167 call xmit0- + 168 .endm xmit + 169 + 170 + 171 ;the macro "genswt" is used to specify a command + 172 ;string switch (1st argument) and the address of + 173 ;the routine to be called when encountered (2nd arg). + 174 ; the switch is made upper-case. + 175 + 176 .macro genswt mne,addr,?label + 177 entsec swtsec + 178 label: .irpc x,mne + 179 .if ge ''x-141 + 180 .if le ''x-172 + 181 .byte ''x-40 + 182 .iff + 183 .byte ''x + 184 .endc + 185 .iff + 186 .byte ''x + 187 .endc + 188 .endm + 189 .iif ne <.-label&1>, .byte 0 + 190 .word addr + 191 xitsec + 192 .endm + 192 + 193 .macro zread chan + 194 .globl zread + 195 mov #chan'chn,r0 + 196 call zread + 197 .endm zread + 198 + 199 .macro zwrite chan + 200 .globl zwrite + 201 mov #chan'chn,r0 + 202 call zwrite + 203 .endm zwrite + 203 + 204 .macro genedt mne,subr ;gen enable/disable table + 205 entsec edtsec + 206 .rad50 /mne/ + 207 .if nb subr + 208 .word subr + 209 .iff + 210 .word cpopj + 211 .endc + 212 .word ed.'mne + 213 xitsec + 214 .endm genedt + 215 + 216 + 217 ;the macro "gencnd" is used to specify conditional + 218 ;arguments. it takes two or three arguments: + 219 + 220 ; 1- mnemonic + 221 ; 2- subroutine to be called + 222 ; 3- if non-blank, complement condition + 223 + 224 .macro gencnd mne,subr,toggle ;generate conditional + 225 entsec cndsec + 226 .rad50 /mne/ + 227 .if b + 228 .word subr + 229 .iff + 230 .word subr+1 + 231 .endc + 232 xitsec + 233 .endm + 233 + 234 .macro ch.mne + 235 + 236 ch.ior= '! + 237 ch.qtm= '" + 238 ch.hsh= '# + 239 ch.dol= '$ + 240 ch.pct= '% + 241 ch.and= '& + 242 ch.xcl= '' + 243 + 244 ch.lp= '( + 245 ch.rp= ') + 246 ch.mul= '* + 247 ch.add= '+ + 248 ch.com= ', + 249 ch.sub= '- + 250 ch.dot= '. + 251 ch.div= '/ + 252 + 253 ch.col= ': + 254 ch.smc= '; + 255 ch.lab= '< + 256 ch.equ= '= + 257 ch.rab= '> + 258 ch.qm= '? + 259 + 260 ch.ind= '@ + 261 ch.bsl= '\ + 262 ch.uar= '^ + 263 + 264 let.a= 'a&^c40 + 265 let.b= 'b&^c40 + 266 let.c= 'c&^c40 + 267 let.d= 'd&^c40 + 268 let.e= 'e&^c40 + 269 let.f= 'f&^c40 + 270 let.g= 'g&^c40 + 271 let.o= 'o&^c40 + 272 let.p= 'p&^c40 + 273 let.r= 'r&^c40 + 274 let.z= 'z&^c40 + 275 + 276 dig.0= '0 + 277 dig.9= '9 + 278 .macro ch.mne + 279 .endm ch.mne + 280 .endm ch.mne + 281 + 282 .macro error num,arg, mess ,?x + 283 sdebug + 284 .globl err.'arg,ern'num, errbts,errref + 285 .if b + 286 deliberate error mistake + 287 .endc + 288 .if dif 0,num + 289 .globl err.xx + 290 tst err.xx + 291 bne x + 292 mov #ern'num,err.xx + 293 x: + 294 .endc + 295 bis #err.'arg,errbts + 296 .endm + 297 + 298 + 299 + 300 .macro setnz addr ;set addr to non-zero for t/f flags + 301 mov sp,addr + 302 .endm + 303 + 304 + 305 .macro bisbic arg ; used by .list/.nlist, .enabl/.dsabl + 306 .globl bisbic + 307 mov #arg,-(sp) + 308 call bisbic + 309 tst (sp)+ + 310 .endm + 310 + 311 ;roll handler calls + 312 + 313 .macro search rolnum ;binary search + 314 mov #rolnum,r0 + 315 .globl search + 316 call search + 317 .endm + 318 + 319 .macro scan rolnum ;linear scan + 320 mov #rolnum,r0 + 321 .globl scan + 322 call scan + 323 .endm + 324 + 325 .macro scanw rolnum ;linear scan, one word + 326 mov #rolnum,r0 + 327 .globl scanw + 328 call scanw + 329 .endm + 330 + 331 .macro next rolnum ;fetch next entry + 332 mov #rolnum,r0 + 333 .globl next + 334 call next + 335 .endm + 336 + 337 .macro append rolnum ;append to end of roll + 338 mov #rolnum,r0 + 339 .globl append + 340 call append + 341 .endm + 342 + 343 .macro zap rolnum ;clear roll + 344 mov #rolnum,r0 + 345 .globl zap + 346 call zap + 347 .endm + 348 + 349 ; call insert ;insert (must be preceded by one + 350 ;of the above to set pointers) + 351 ; call setrol ;save and set regs for above + 351 + 352 ;flags used in symbol table mode + 353 + 354 .macro st.flg + 355 + 356 .if le ft.unx + 357 + 358 ovrflg= 000004 ;overlay (psect only) + 359 defflg= 000010 ;defined + 360 relflg= 000040 ;relocatable + 361 glbflg= 000100 ;global + 362 dfgflg= 000200 ; default global ... reeds's guess + 363 + 364 + 365 .endc + 366 + 367 .if gt ft.unx + 368 + 369 ; ****** these should not be changed!! ****** + 370 shrflg= 000001 ;shareable (psect only) + 371 .if gt ft.id + 372 insflg= shrflg*2 ;instruction space (psect only) + 373 bssflg= insflg*2 ;blank section (psect only) + 374 m.idf= shrflg!insflg!bssflg ;mask to turn them off + 375 .iff + 376 bssflg= shrflg*2 + 377 m.idf= shrflg!bssflg + 378 .endc + 379 b.idf= 1 ;shift count to make above bits word offset + 380 ; *********************************** + 381 defflg= 000010 ;defined + 382 ovrflg= 000020 ;overlay (psect only) + 383 relflg= 000040 ;relocatable + 384 glbflg= 000100 ;global + 385 dfgflg= 000200 ; default global ... reeds's guess + 386 + 387 .endc + 388 + 389 ; + 390 ; default psect attribs. + 391 ; can be changed, but make sure all customers know about + 392 ; it, including all the linkers. + 393 ; + 394 pattrs=relflg!defflg ; For .psects and blank .csects + 395 aattrs=glbflg!defflg!ovrflg ; For .asect + 396 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects + 397 + 398 regflg= 000001 ;register + 399 lblflg= 000002 ;label + 400 mdfflg= 000004 ;multilpy defined + 401 .macro st.flg + 402 .endm + 403 .endm st.flg + 404 + 405 + 406 + 407 .macro ct.mne + 408 .globl cttbl + 409 ct.eol = 000 ; eol + 410 ct.com = 001 ; comma + 411 ct.tab = 002 ; tab + 412 ct.sp = 004 ; space + 413 ct.pcx = 010 ; printing character + 414 ct.num = 020 ; numeric + 415 ct.alp = 040 ; alpha, dot, dollar + 416 ct.lc = 100 ; lower case alpha + 417 ct.smc = 200 ; semi-colon (sign bit) + 418 + 419 ct.pc = ct.com!ct.smc!ct.pcx!ct.num!ct.alp + 420 .macro ct.mne + 421 .endm ct.mne + 422 .endm ct.mne + 423 + 424 + 425 .end + 425 + 8 .include "2.11BSD/m11/errs.m11" + 1 ; + 2 ; m11 error messages + 3 ; jim reeds 4 july 1981 + 4 ; + 5 .mcall (at)always + 6 000000 always + 1 + 2 .macro .data + 3 entsec .data + 4 .endm .data + 5 + 6 .macro .text + 7 entsec .text + 8 .endm + 9 + 10 .macro .bss + 11 entsec .bss + 12 .endm + 13 + 14 000001 mk.symbol=1 ;one to make symbols, 0 otherwise + 15 000000 x40= 0 + 16 000000 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs. + 17 ; if not you will have to write macros for them + 18 000007 $timdf= 7 ; California Time Zone + 19 ; should really use ftime(2) for this and for + 20 ; DST. + 21 ;xfltg= 0 ;define to assmbl out floating hardware + 22 000000 rsx11d = 0 ; rsx11d features + 23 000000 debug = 0 ; <<< REEDS if non zero includes debug junk + 24 + 25 000001 ft.id= 1 ;have set i & d. set =0 if not + 26 + 27 000001 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not. + 28 + 29 .nlist bex + 30 + 31 000011 tab= 11 + 32 000012 lf= 12 + 33 000013 vt= 13 + 34 000014 ff= 14 + 35 000015 cr= 15 + 36 000040 space= 40 + 37 + 38 000020 bpmb = 20 ;bytes per macro block + 39 + 40 + 41 + 42 + 43 +./2.11BSD/m11/errs.m11:6->ALWAYS:44: ***ERROR Unknown flag SHR given to .PSECT directive + 44 .psect .text con, shr, gbl,ins +./2.11BSD/m11/errs.m11:6->ALWAYS:45: ***ERROR Unknown flag DAT given to .PSECT directive + 45 .psect .data con, dat, prv, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:46: ***ERROR Unknown flag BSS given to .PSECT directive + 46 .psect .bss con, bss, gbl + 47 +./2.11BSD/m11/errs.m11:6->ALWAYS:48: ***ERROR Unknown flag DAT given to .PSECT directive + 48 .psect dpure con, dat, prv, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:49: ***ERROR Unknown flag PRV given to .PSECT directive + 49 .psect mixed con, prv, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:50: ***ERROR Unknown flag DAT given to .PSECT directive + 50 .psect errmes con, dat, prv, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:51: ***ERROR Unknown flag BSS given to .PSECT directive + 51 .psect impure con, bss, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:52: ***ERROR Unknown flag BSS given to .PSECT directive + 52 .psect imppas con, bss, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:53: ***ERROR Unknown flag BSS given to .PSECT directive + 53 .psect implin con, bss, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:54: ***ERROR Unknown flag DAT given to .PSECT directive + 54 .psect swtsec con, dat, prv, gbl ; unix command line flags +./2.11BSD/m11/errs.m11:6->ALWAYS:55: ***ERROR Unknown flag DAT given to .PSECT directive + 55 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if' +./2.11BSD/m11/errs.m11:6->ALWAYS:56: ***ERROR Unknown flag DAT given to .PSECT directive + 56 .psect crfsec con, dat, prv, gbl ; args for -cr flag +./2.11BSD/m11/errs.m11:6->ALWAYS:57: ***ERROR Unknown flag DAT given to .PSECT directive + 57 .psect edtsec con, dat, prv, gbl ; args for .enabl +./2.11BSD/m11/errs.m11:6->ALWAYS:58: ***ERROR Unknown flag DAT given to .PSECT directive + 58 .psect lctsec con, dat, prv, gbl ; args for .list +./2.11BSD/m11/errs.m11:6->ALWAYS:59: ***ERROR Unknown flag DAT given to .PSECT directive + 59 .psect psasec con, dat, prv, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:60: ***ERROR Unknown flag DAT given to .PSECT directive + 60 .psect pstsec con, dat, prv, gbl +./2.11BSD/m11/errs.m11:6->ALWAYS:61: ***ERROR Unknown flag DAT given to .PSECT directive + 61 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables +./2.11BSD/m11/errs.m11:6->ALWAYS:62: ***ERROR Unknown flag DAT given to .PSECT directive + 62 .psect rolsiz con, dat, prv, gbl ; sizes of table entries +./2.11BSD/m11/errs.m11:6->ALWAYS:63: ***ERROR Unknown flag DAT given to .PSECT directive + 63 .psect roltop con, dat, prv, gbl ; tops of tables +./2.11BSD/m11/errs.m11:6->ALWAYS:64: ***ERROR Unknown flag BSS given to .PSECT directive + 64 .psect xpcor con,bss , gbl ; this one MUST come last in core + 65 + 66 + 67 + 68 .macro entsec name ;init a section + 69 .psect name con + 70 .endm entsec + 71 + 72 + 73 + 74 .macro jeq x,?fred + 75 bne fred + 76 jmp x + 77 fred: + 78 .endm + 79 .macro jne x,?fred + 80 beq fred + 81 jmp x + 82 fred: + 83 .endm + 84 .macro xitsec + 85 entsec .text + 86 .endm xitsec + 87 + 88 + 89 .macro call address + 90 jsr pc,address + 91 .endm + 92 + 93 .macro return + 94 rts pc + 95 .endm + 96 + 97 + 98 .macro always + 99 .nlist bex + 100 .endm always + 7 + 8 000000 .data + 1 000000 entsec .data + 1 000000 .psect .data con + 9 .dsabl lc + 10 .LIST MD,ME,MC + 11 + 12 .MACRO ERRGEN NUM,CODE,TEXT + 13 ern'num:: .asciz \text\ + 14 .endm + 15 000000 ERRGEN 1,R, + 1 000000 103 101 116 ERN1:: .ASCIZ \CANNOT RELOCATE A REGISTER\ + 000003 116 117 124 + 000006 040 122 105 + 000011 114 117 103 + 000014 101 124 105 + 000017 040 101 040 + 000022 122 105 107 + 000025 111 123 124 + 000030 105 122 000 + 16 000033 ERRGEN 2,A, + 1 000033 111 115 120 ERN2:: .ASCIZ \IMPROPER RELOCATION\ + 000036 122 117 120 + 000041 105 122 040 + 000044 122 105 114 + 000047 117 103 101 + 000052 124 111 117 + 000055 116 000 + 17 000057 ERRGEN 3,A, + 1 000057 102 101 104 ERN3:: .ASCIZ \BAD EXPRESSION\ + 000062 040 105 130 + 000065 120 122 105 + 000070 123 123 111 + 000073 117 116 000 + 18 000076 ERRGEN 4,U, + 1 000076 125 116 104 ERN4:: .ASCIZ \UNDEFINED SYMBOL\ + 000101 105 106 111 + 000104 116 105 104 + 000107 040 123 131 + 000112 115 102 117 + 000115 114 000 + 19 000117 ERRGEN 5,M, + 1 000117 115 125 114 ERN5:: .ASCIZ \MULTIPLY DEFINED\ + 000122 124 111 120 + 000125 114 131 040 + 000130 104 105 106 + 000133 111 116 105 + 000136 104 000 + 20 000140 ERRGEN 6,N, + 1 000140 104 111 107 ERN6:: .ASCIZ \DIGIT ILLEGAL IN CURRENT RADIX\ + 000143 111 124 040 + 000146 111 114 114 + 000151 105 107 101 + 000154 114 040 111 + 000157 116 040 103 + 000162 125 122 122 + 000165 105 116 124 + 000170 040 122 101 + 000173 104 111 130 + 000176 000 + 21 000177 ERRGEN 7,T, + 1 000177 116 125 115 ERN7:: .ASCIZ \NUMBER TOO BIG\ + 000202 102 105 122 + 000205 040 124 117 + 000210 117 040 102 + 000213 111 107 000 + 22 000216 ERRGEN 8,U, + 1 000216 114 117 103 ERN8:: .ASCIZ \LOCAL SYMBOL NOT DEFINED\ + 000221 101 114 040 + 000224 123 131 115 + 000227 102 117 114 + 000232 040 116 117 + 000235 124 040 104 + 000240 105 106 111 + 000243 116 105 104 + 000246 000 + 23 000247 ERRGEN 9,A, + 1 000247 105 115 120 ERN9:: .ASCIZ \EMPTY FLOATING POINT NUMBER\ + 000252 124 131 040 + 000255 106 114 117 + 000260 101 124 111 + 000263 116 107 040 + 000266 120 117 111 + 000271 116 124 040 + 000274 116 125 115 + 000277 102 105 122 + 000302 000 + 24 000303 ERRGEN 10,N, + 1 000303 106 114 117 ERN10:: .ASCIZ \FLOATING POINT OVERFLOW\ + 000306 101 124 111 + 000311 116 107 040 + 000314 120 117 111 + 000317 116 124 040 + 000322 117 126 105 + 000325 122 106 114 + 000330 117 127 000 + 25 000333 ERRGEN 11,T, + 1 000333 124 122 125 ERN11:: .ASCIZ \TRUNCTATION ERROR\ + 000336 116 103 124 + 000341 101 124 111 + 000344 117 116 040 + 000347 105 122 122 + 000352 117 122 000 + 26 000355 ERRGEN 12,L, + 1 000355 114 111 116 ERN12:: .ASCIZ \LINE TOO LONG\ + 000360 105 040 124 + 000363 117 117 040 + 000366 114 117 116 + 000371 107 000 + 27 000373 ERRGEN 13,I, + 1 000373 111 114 114 ERN13:: .ASCIZ \ILLEGAL CHARACTER\ + 000376 105 107 101 + 000401 114 040 103 + 000404 110 101 122 + 000407 101 103 124 + 000412 105 122 000 + 28 000415 ERRGEN 14,E,<.END NOT FOUND> + 1 000415 056 105 116 ERN14:: .ASCIZ \.END NOT FOUND\ + 000420 104 040 116 + 000423 117 124 040 + 000426 106 117 125 + 000431 116 104 000 + 29 000434 ERRGEN 140,E, + 1 000434 105 116 104 ERN140:: .ASCIZ \END OF INPUT WITH UNTERMINATED MACRO OR REPEAT\ + 000437 040 117 106 + 000442 040 111 116 + 000445 120 125 124 + 000450 040 127 111 + 000453 124 110 040 + 000456 125 116 124 + 000461 105 122 115 + 000464 111 116 101 + 000467 124 105 104 + 000472 040 115 101 + 000475 103 122 117 + 000500 040 117 122 + 000503 040 122 105 + 000506 120 105 101 + 000511 124 000 + 30 000513 ERRGEN 15,O, + 1 000513 103 117 116 ERN15:: .ASCIZ \CONDITIONAL NOT IN PROGRESS\ + 000516 104 111 124 + 000521 111 117 116 + 000524 101 114 040 + 000527 116 117 124 + 000532 040 111 116 + 000535 040 120 122 + 000540 117 107 122 + 000543 105 123 123 + 000546 000 + 31 000547 ERRGEN 16,O, + 1 000547 124 117 117 ERN16:: .ASCIZ \TOO MANY NESTED CONDITIONALS\ + 000552 040 115 101 + 000555 116 131 040 + 000560 116 105 123 + 000563 124 105 104 + 000566 040 103 117 + 000571 116 104 111 + 000574 124 111 117 + 000577 116 101 114 + 000602 123 000 + 32 000604 ERRGEN 17,A, + 1 000604 103 117 116 ERN17:: .ASCIZ \CONDITIONAL ARGUMENT NOT SPECIFIED\ + 000607 104 111 124 + 000612 111 117 116 + 000615 101 114 040 + 000620 101 122 107 + 000623 125 115 105 + 000626 116 124 040 + 000631 116 117 124 + 000634 040 123 120 + 000637 105 103 111 + 000642 106 111 105 + 000645 104 000 + 33 000647 ERRGEN 18,T, + 1 000647 111 114 114 ERN18:: .ASCIZ \ILLEGAL LOCAL SYMBOL\ + 000652 105 107 101 + 000655 114 040 114 + 000660 117 103 101 + 000663 114 040 123 + 000666 131 115 102 + 000671 117 114 000 + 34 000674 ERRGEN 19,Q, + 1 000674 122 101 116 ERN19:: .ASCIZ \RANDOM JUNK AT END OF STATEMENT IGNORED\ + 000677 104 117 115 + 000702 040 112 125 + 000705 116 113 040 + 000710 101 124 040 + 000713 105 116 104 + 000716 040 117 106 + 000721 040 123 124 + 000724 101 124 105 + 000727 115 105 116 + 000732 124 040 111 + 000735 107 116 117 + 000740 122 105 104 + 000743 000 + 35 000744 ERRGEN 20,A, + 1 000744 115 111 123 ERN20:: .ASCIZ \MISSING TITLE\ + 000747 123 111 116 + 000752 107 040 124 + 000755 111 124 114 + 000760 105 000 + 36 000762 ERRGEN 0,<>, + 1 000762 125 123 105 ERN0:: .ASCIZ \USER GENERATED ERROR\ + 000765 122 040 107 + 000770 105 116 105 + 000773 122 101 124 + 000776 105 104 040 + 001001 105 122 122 + 001004 117 122 000 + 37 001007 ERRGEN 22,A, + 1 001007 115 111 123 ERN22:: .ASCIZ \MISSING DELIMITING CHARACTER\ + 001012 123 111 116 + 001015 107 040 104 + 001020 105 114 111 + 001023 115 111 124 + 001026 111 116 107 + 001031 040 103 110 + 001034 101 122 101 + 001037 103 124 105 + 001042 122 000 + 38 001044 ERRGEN 23,A, + 1 001044 125 116 113 ERN23:: .ASCIZ \UNKNOWN .LIST/.NLIST ARGUMENT\ + 001047 116 117 127 + 001052 116 040 056 + 001055 114 111 123 + 001060 124 057 056 + 001063 116 114 111 + 001066 123 124 040 + 001071 101 122 107 + 001074 125 115 105 + 001077 116 124 000 + 39 001102 ERRGEN 24,O, + 1 001102 117 120 103 ERN24:: .ASCIZ \OPCODE OUT OF CONTEXT\ + 001105 117 104 105 + 001110 040 117 125 + 001113 124 040 117 + 001116 106 040 103 + 001121 117 116 124 + 001124 105 130 124 + 001127 000 + 40 001130 ERRGEN 25,O, + 1 001130 115 111 123 ERN25:: .ASCIZ \MISSING MACRO NAME\ + 001133 123 111 116 + 001136 107 040 115 + 001141 101 103 122 + 001144 117 040 116 + 001147 101 115 105 + 001152 000 + 41 001153 ERRGEN 26,A,<.ENDM NAME DOESN'T MATCH .MACRO NAME> + 1 001153 056 105 116 ERN26:: .ASCIZ \.ENDM NAME DOESN'T MATCH .MACRO NAME\ + 001156 104 115 040 + 001161 116 101 115 + 001164 105 040 104 + 001167 117 105 123 + 001172 116 047 124 + 001175 040 115 101 + 001200 124 103 110 + 001203 040 056 115 + 001206 101 103 122 + 001211 117 040 116 + 001214 101 115 105 + 001217 000 + 42 001220 ERRGEN 27,A, + 1 001220 111 114 114 ERN27:: .ASCIZ \ILLEGAL ARGUMENTS\ + 001223 105 107 101 + 001226 114 040 101 + 001231 122 107 125 + 001234 115 105 116 + 001237 124 123 000 + 43 001242 ERRGEN 28,A, + 1 001242 116 117 040 ERN28:: .ASCIZ \NO SYMBOL TO ASSIGN TO\ + 001245 123 131 115 + 001250 102 117 114 + 001253 040 124 117 + 001256 040 101 123 + 001261 123 111 107 + 001264 116 040 124 + 001267 117 000 + 44 001271 ERRGEN 29,O, + 1 001271 125 116 102 ERN29:: .ASCIZ \UNBALANCED .ENDM\ + 001274 101 114 101 + 001277 116 103 105 + 001302 104 040 056 + 001305 105 116 104 + 001310 115 000 + 45 001312 ERRGEN 30,A, + 1 001312 115 111 123 ERN30:: .ASCIZ \MISSING ARGUMENT IN 'IF' CONSTRUCTION\ + 001315 123 111 116 + 001320 107 040 101 + 001323 122 107 125 + 001326 115 105 116 + 001331 124 040 111 + 001334 116 040 047 + 001337 111 106 047 + 001342 040 103 117 + 001345 116 123 124 + 001350 122 125 103 + 001353 124 111 117 + 001356 116 000 + 46 001360 ERRGEN 31,A, + 1 001360 115 111 123 ERN31:: .ASCIZ \MISSING ARGUMENT\ + 001363 123 111 116 + 001366 107 040 101 + 001371 122 107 125 + 001374 115 105 116 + 001377 124 000 + 47 001401 ERRGEN 70,A, + 1 001401 114 117 103 ERN70:: .ASCIZ \LOCAL OFFSET OUT OF RANGE\ + 001404 101 114 040 + 001407 117 106 106 + 001412 123 105 124 + 001415 040 117 125 + 001420 124 040 117 + 001423 106 040 122 + 001426 101 116 107 + 001431 105 000 + 48 001433 ERRGEN 71,A, + 1 001433 111 114 114 ERN71:: .ASCIZ \ILLEGAL REGISTER NUMBER\ + 001436 105 107 101 + 001441 114 040 122 + 001444 105 107 111 + 001447 123 124 105 + 001452 122 040 116 + 001455 125 115 102 + 001460 105 122 000 + 49 001463 ERRGEN 32,P, + 1 001463 120 110 101 ERN32:: .ASCIZ \PHASE ERROR IN LABEL DEFINITION\ + 001466 123 105 040 + 001471 105 122 122 + 001474 117 122 040 + 001477 111 116 040 + 001502 114 101 102 + 001505 105 114 040 + 001510 104 105 106 + 001513 111 116 111 + 001516 124 111 117 + 001521 116 000 + 50 001523 ERRGEN 33,Q, + 1 001523 111 114 114 ERN33:: .ASCIZ \ILLEGAL LABEL\ + 001526 105 107 101 + 001531 114 040 114 + 001534 101 102 105 + 001537 114 000 + 51 001541 ERRGEN 34,M,