From dc2d2dd63b75f5dad0031bab6f45fcb2b7960e34 Mon Sep 17 00:00:00 2001 From: Warren Toomey Date: Wed, 2 Mar 2016 20:38:00 +1000 Subject: [PATCH] Phil's change to as7 to implement RELATIVE flag. He says: seems to assemble cat.s and kernel reasonably... (famous last words) I've updated a7out to use the same starting location. It runs cat.s OK. --- tools/a7out | 2 +- tools/as7 | 124 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 95 insertions(+), 31 deletions(-) diff --git a/tools/a7out b/tools/a7out index 322db28..bffc174 100755 --- a/tools/a7out +++ b/tools/a7out @@ -16,7 +16,7 @@ my @Mem; # 8K 18-bit words of main memory my @FD; # Array of open filehandles # Registers -my $PC = 020; # Program counter +my $PC = 010000; # Program counter my $AC = 0; # Accumulator my $LINK = 0; # Link register, either 0 or LINKMASK my $MQ = 0; # MQ register diff --git a/tools/as7 b/tools/as7 index 057e3be..333c340 100755 --- a/tools/as7 +++ b/tools/as7 @@ -4,7 +4,7 @@ # and convert them into PDP-7 machine code # # (c) 2016 Warren Toomey, GPL3 -# Tweaked by Phil Budne (line, expression parsing, "list", "ptr" formats) +# Tweaked by Phil Budne (line, expression parsing, output formats) # use strict; use warnings; @@ -28,21 +28,27 @@ my $errors = 0; # set to non-zero on error my $line_error = ' '; my $file; # current file name my $lineno; # current line number +my $OUTPUT; # output file +my $RELATIVE = 01000000; # set on non-absolute symbol values +my $BASE = 0|$RELATIVE; # starting value for "." +### Main program ### ## command line options my $debug = 0; # Run in debug mode my $format = 'a7out'; # output format +my $namelist = 0; # output n.out file +my $output = 'a.out'; # output file # keep this near the GetOptions call to make it easy to add documentation! sub usage { - die("Usage: $0 [--debug] [--format=a7out|list|ptr ] file1.s [file2.s ...]\n") + die("Usage: $0 [--debug] [--format=a7out|list|ptr|rim ] [--out file] file1.s [file2.s ...]\n") } -### Main program ### - GetOptions( - 'debug|d' => \$debug, + 'debug|d' => \$debug, 'format|f=s' => \$format, + 'namelist|n' => \$namelist, + 'output|o=s' => \$output, ) or usage(); usage() if ( @ARGV < 1 ); @@ -50,7 +56,7 @@ usage() if ( @ARGV < 1 ); # start with the location counter at zero # predefine syscall and opcodes as variables %Var = ( - '.' => 020, + '.' => $BASE, '..' => 4096, # output base addr? # as.s does not have an initial symbol table @@ -179,14 +185,17 @@ usage() if ( @ARGV < 1 ); # Parse all the files foreach my $file (@ARGV) { + print STDERR "I $file\n"; # like the real as parse_file($file); } # Now do it all again, pass two -$Var{'.'} = 020; +$Var{'.'} = $BASE; $stage = 2; -print("PASS 2\n") if ($debug); +open(my $OUT, ">$output") || die "$output"; + foreach my $file (@ARGV) { + print STDERR "II $file\n"; # like the real as parse_file($file); } @@ -194,33 +203,40 @@ if ($format eq 'a7out') { # print out the contents of memory for my $i ( 0 .. $#Mem ) { if ( defined( $Mem[$i] ) ) { - printf( "%06o: %06o\t%s\n", $i, $Mem[$i], $Mline[$i] || "" ); + printf $OUT "%06o: %06o\t%s\n", $i, $Mem[$i], ($Mline[$i] || ""); } } } elsif ($format eq 'list') { - print "\n"; - print "Labels:\n"; - foreach my $key (sort keys %Label) { - printf("%-8.8s %#06o\n", $key, $Label{$key}); - } + print $OUT "\n"; + print $OUT "Labels:\n"; + dump_labels($OUT); } elsif ($format eq 'ptr') { # dump absolute memory in PTR binary for my $loc ( 0 .. $#Mem ) { - my $m = $Mem[$loc] || 0; - printf("%c%c%c", ($m >> 12) & 077, ($m >> 6) & 077, $m & 077); + punch($Mem[$loc] || 0); } } +elsif ($format eq 'rim') { # PDP-7 Read In Mode + for my $loc ( 0 .. $#Mem ) { + if (defined($Mem[$loc])) { + punch(0200000 | $loc ); # LAC addr + punch($Mem[$loc] || 0); + } + } + punch($OUT, 0740040 ); # HLT +} else { die("unknown format $format"); } +close($OUT); -# as.s writes a binary file named n.out, ours is ascii -open (my $NOUT, ">n.out") || die "n.out"; -foreach my $key (sort keys %Label) { - printf $NOUT "%-8.8s %#06o\n", $key, $Label{$key}; +if ($namelist) { + # as.s writes a binary file named n.out, ours is ascii + open (my $NOUT, ">", "n.out") || die "n.out"; + dump_labels($NOUT); + close($NOUT); } -close($NOUT); exit($errors); @@ -234,7 +250,7 @@ sub err { $errors = 1; # exit status if ($stage == 2) { print STDERR "$file:$lineno: $msg\n"; - print "$file:$lineno: $msg\n" if (! -t STDOUT && $format ne 'ptr'); + print $OUT "$file:$lineno: $msg\n" if ($format eq 'list'); } return 0; # expression value } @@ -248,7 +264,8 @@ sub parse_file { $lineno++; chomp($line); # Lose the end of line $origline = $line; - print "\t\t$line\n" if ($stage == 2 && $line ne '' && $format eq 'list'); + print $OUT "\t\t$line\n" + if ($stage == 2 && $line ne '' && $format eq 'list'); parse_line(); } close($IN); @@ -312,7 +329,8 @@ sub parse_line { my $word = parse_expression(); printf( "Setting variable %s to 0%o\n", $lhs, $word ) if ($debug); $Var{$lhs} = $word; - printf("\t%06o %s\n", $word, $line_error) if ($stage == 2 && $format eq 'list'); + printf $OUT "\t%06o %s\n", $word, $line_error + if ($stage == 2 && $format eq 'list'); } else { # bare expression (not assignment) # Get its value on pass two and save to memory @@ -320,11 +338,28 @@ sub parse_line { my $word = parse_expression(); if ( $stage == 2 ) { my $location = $Var{'.'}; - $Mem[$location] = $word; + if ($location & $RELATIVE) { # non-absolute location? + $location &= 0777777; + $location += $Var{'..'} & 0777777; # relocate + # XXX check for overflow? + } + if ($word & $RELATIVE) { # word created from relative addresses? + $word &= 0777777; + $word += $Var{'..'} & 0777777; # relocate + # XXX check for overflow? + } + if ($location < 0) { + err('.', 'below base'); + } + else { + $Mem[$location] = $word; + } $Mline[$location] = $origline; $origline = ''; if ($format eq 'list' and defined($word)) { - printf( "%06o: %06o %s\n", $location, $word, $line_error); + # show flags?? + printf $OUT "%06o: %06o %s\n", + $location, $word, $line_error; } } # Move up to the next location in both passes @@ -342,6 +377,7 @@ sub parse_line { # ORed, added, or subtracted sub parse_expression { my $word = 0; + my $flags = 0; print "expression: '$line'\n" if ($debug); @@ -352,6 +388,7 @@ sub parse_expression { $line =~ s{^\s+}{}; # as.s accepts ",' as whitespace too! if ($line eq '' || $line =~ m{^[";]}) { # EOL ; and " terminate expr + $word |= $flags; printf("\tparse_expression => %#o\n", $word) if ($debug); return $word; } @@ -369,15 +406,15 @@ sub parse_expression { if ($line =~ s{^<(.)}{}) { # }{}) { # char> print "\tfound x>\n" if ($debug); - $syllable = ord($1) + $syllable = ord($1) # absolute } elsif ($line =~ s{^>(.)}{}) { # >char !! print "\tfound >x\n" if ($debug); - $syllable = ord($1) + $syllable = ord($1) # absolute } elsif ($line =~ s{^([a-z\.][a-z0-9\.]*)}{}) { my $sym = $1; @@ -407,7 +444,7 @@ sub parse_expression { else { $syllable = $value + 0; } - $syllable &= 0777777; + $syllable &= 0777777; # absolute } else { # From the BSD fortune file: @@ -423,6 +460,9 @@ sub parse_expression { return undef; } + my $sylflags = $syllable & $RELATIVE; + $syllable &= 0777777; + if ($op eq '+') { $word += $syllable; } @@ -433,6 +473,7 @@ sub parse_expression { $word |= $syllable; } $word &= 0777777; + $flags |= $sylflags; printf("\tsyllable: %#o word: %#o\n", $syllable, $word) if ($debug); } } @@ -471,3 +512,26 @@ sub find_relative_label { } return err('U', "undefined relative reference $label$direction"); } + +sub punch { # output a word in paper tape binary format + my $word = shift; + + printf $OUT "%c%c%c", + (($word >> 12) & 077) | 0200, + (($word >> 6) & 077) | 0200, + ($word & 077) | 0200; +} + +sub dump_labels { # for 'list' and --namelist + my $file = shift; + + foreach my $key (sort keys %Label) { + my $addr = $Label{$key}; + my $flags = ($addr & $RELATIVE) ? "r" : ""; + if ($addr & $RELATIVE) { + $addr &= 0777777; + $addr += $Var{'..'}; + } + printf $file "%-8.8s %#06o %s\n", $key, $addr & 0777777, $flags; + } +}