Devoted to all things RSX related (RSX11M,RSX11M+,RSX11S,P/OS,IAS,XVM/RSX (and even VMS)), and anything else I'm interested in.
Sunday, September 5, 2021
VAX/VMS program to put current time in your DCL prompt
Tuesday, July 13, 2021
RSX11D V4 recovered
Not many folks around these days have ever worked with RSX11D, and apparently not a lot of it survives. I have been looking for a runnable copy of it for decades now. I had started to think it was gone for good. A while back, though, James Fehlinger got ahold of some RSX11D V6.2 tapes (the last version released). They were not in good shape, and he did a whole lot of analysis and recovery to get them into useable condition (a whole heckuva lot of work - some of it really inspired. He's a guy that doesn't take fail for an answer). His work on this is available at Bitsavers, at
http://bitsavers.org/bits/DEC/pdp11/simh_images
So, it's great to have runnable RSX11D V6.2 available. I have a few hobby projects planned for it already. If you ever had any interest in RSX11D, I recommend you check it out. But that's not what I'm writin' about today. A few months back. I spotted several Ebay auctions for the contents of a former DEC engineer's basement computer collection (sadly, he was deceased - at least his relatives were making his collection available, instead of heaving it all into a dumpster). One of the items listed was an RK05 disk, whose labels indicated it might have a bootable RSX11D V4 system on it.
I bought it, and asked around online, looking for someone who had a working RK05. Fritz Mueller replied that he had one, connected to an 11/45, and could try to read it for me. The Great Magnet smiled on his efforts (all energy flows according to the whims of the Great Magnet), and the decades old disk read flawlessly. He copied it to an image file (at the cost of some effort getting it transferred off the 11/45 - thanks again Fritz) and emailed it to me.
So, flush with optimism due to the good progress so far, I mounted a copy of the disk image in SIMH and tried to boot it. No soap...it hung in a loop when I attempted to boot it. Halting SIMH and single stepping it showed that it was looping on a few instructions, doing...something...with some RK11 registers. Fritz tried to boot the physical pack on his 11/45, but, no joy there either. He actually disassembled a goodly slug of the boot code on the pack, which was a bit of a self modifying mess, but, we didn't get the problem figured out enough to make the boot succeed.
This was disappointing. I was starting to think this was going to be a failed computer archaeology project. I had another look at the loop that it executed, and saw that it was looping, waiting for something to happen. If that thing ever happened, it would get to location 164 and take off. I figured, waddahell, let's pretend what it was waiting for occurred, and set the PC to 164 and go from there. When I did that, the rest of the boot worked, and I was presented with a working RSX11D V4 system!
UPDATE - This boot problem has since been analyzed and patched - please see blog entry titled
"RSX11D V4 boot problem update"
for the explanation of the problem and a new version with the patch.
RSX11D V4 is missing a lot of things we take for granted in the later members of the RSX family, so it's mostly of historical interest (the worst lack I've found, is that it doesn't have any form of RMD or DEMO - the memory usage display that helps RSX system programmers while away the idle hours). But, at least it hasn't been lost like so many other pieces of DEC software, and it's interesting to explore it and see where things came from.
Here's a simh disk image and a pdp11.ini file for it.
Here's a look at the loop problem, and how to get past it.
C:\simh40\PDP11\rsx11dpack>pdp11
PDP-11 simulator V4.0-0 Current git commit id: ab3e07a4
Disabling XQ
sim>boot
Simulation stopped, PC: 000152 (BPL 140)
sim> s
sim> s
sim> s
sim> s
sim> s
Step expired, PC: 000146 (TST @#177404)
140: MOV #2,@#177406
146: TST @#177404
152: BPL 140
154: BIT #2000,@#177402
162: BEQ 0
164: MOV #77406,@#177600
200: MOV #144340,-(SP)
RSX-004A
MCR>MOU DK:
MOUNT-**VOLUME INFORMATION**
DEVICE =DK0
CLASS =FILE 11
LABEL =RSXSYS
UIC =[1,1]
ACCESS =[RWED,RWED,RWED,RWED]
CHARAC =[]
MCR>TAS
ALLOCR 11 GEN 050 003400 DK 0-00000004550
BPR... V001A GEN 050 007700 DK 0-00000006363
CR.... V004A GEN 248 003500 DK 0-00000004653
DK.... V003F SYDISK 248 003000 DK 0-00000004671
DT.... V005A GEN 248 003600 DK 0-00000004723
HCRCHK RSX03A GEN 050 071400 DK 0-00000007647
HY.... V002A GEN 246 007600 DK 0-00000007156
LKD RSX03A GEN 050 076500 DK 0-00000007744
LP.... V003E GEN 248 003100 DK 0-00000004732
MO.... V003F GEN 100 003400 DK 0-00000005014
PP.... V003F GEN 248 003100 DK 0-00000004706
PRT... 03 GEN 250 003700 DK 0-00000003775
PR.... V003F GEN 248 003000 DK 0-00000004715
SG2... V001A GEN 230 025300 DK 0-00000007024
TTYN00 GEN 051 001400 DK 0-00000005702
TT.... V003F TTY 248 011600 DK 0-00000004770
.FL000 V003A FILE 248 012500 DK 0-00000004464 FIXED
.FL007 V003A GEN 250 004700 DK 0-00000004502
.FL100 V002A MCR 247 004100 DK 0-00000004512
.FL200 10 MCRDSP 250 003200 DK 0-00000004522
.FL300 V002A GEN 240 011500 DK 0-00000004557
.TKTN. V002A GEN 249 002300 DK 0-00000004241
...ABO V002A MCR 221 001700 DK 0-00000004004
...ACT V002A MCR 221 002200 DK 0-00000004011
...ALT V002A MCR 221 002000 DK 0-00000004017
...BAT 01 GEN 020 022700 DK 0-00000006266
...CAN V002A MCR 221 001400 DK 0-00000004024
...COM V001A MCR 221 002100 DK 0-00000004041
...CON V004A GEN 050 004400 DK 0-00000004370
...DCU V003A GEN 050 013500 DK 0-00000004531
...DEV V001A MCR 221 001400 DK 0-00000004047
...DIS V002A MCR 221 001600 DK 0-00000004054
...DMO V002A GEN 050 003100 DK 0-00000004446
...DMP D04 GEN 050 025200 DK 0-00000002246
...EDI V004C GEN 050 056000 DK 0-00000005147
...ENA V002A MCR 221 001500 DK 0-00000004061
...FIX V002A MCR 221 002400 DK 0-00000004074
...FLX V003F GEN 050 052700 DK 0-00000002376
...FTN V0804 GEN 050 060200 DK 0-00000001773
...IHI V001A GEN 050 072500 DK 0-00000007512
...INI V002A GEN 050 015500 DK 0-00000004411
...INS V004A GEN 050 030000 DK 0-00000004261
...LBR 001 GEN 050 057000 DK 0-00000002531
...LOA V002A MCR 221 002700 DK 0-00000004102
...LUN V001A MCR 221 003600 DK 0-00000004110
...MAC 05.01 GEN 050 126400 DK 0-00000003104
...MCP V002A MCR 221 001100 DK 0-00000004117
...MCR V001A MCRDSP 221 002000 DK 0-00000004124
...MOU V004A GEN 050 010600 DK 0-00000004432
...OPE V002A MCR 221 004000 DK 0-00000004131
...PAR V001A MCR 221 001300 DK 0-00000004140
...PIP D13 GEN 050 042700 DK 0-00000002200
...REA V003A MCR 221 003300 DK 0-00000004146
...RED V003A MCR 221 002000 DK 0-00000004155
...REM V004A GEN 050 025200 DK 0-00000004337
...RUN V004A MCR 221 003400 DK 0-00000004400
...SAV V002A MCR 221 003600 DK 0-00000004176
...SET V004A MCR 221 001500 DK 0-00000004213
...TAS V003A MCR 221 002300 DK 0-00000004226
...TIM V003A MCR 221 002000 DK 0-00000004234
...TKB 08 GEN 050 150200 DK 0-00000003553
...UFD V002A GEN 050 003700 DK 0-00000004455
...UNF V002A MCR 221 001500 DK 0-00000004247
...UNL V003F MCR 221 002000 DK 0-00000004254
...VFY D05 GEN 050 034500 DK 0-00000002277
MCR>
Sunday, February 7, 2021
DECUS APL-11 fixes for ID space and RSX11M-Plus 4.6
Recently, Mark Matlock and I were talking about APL-11. This was a version of Iverson's language, APL, for the PDP11. It was written for DEC by OMSI, and sold as a layered product. Later on, it got donated to the DECUS library.
Mark mentioned that it would be a lot more useful when running on RSX if it had more room in its workspace (an APL workspace is storage for variables and programs). He reckoned that using I&D space with M+ would be a good way to just about double the space available.
I&D space is a feature found on some of the newer members of the PDP11 family. It allows the use of a second set of APRs (Address Page Registers). It allows a full set of APRs to be used to map the code in a program, and a full second set to map the data. If you have the right mix of code and data, you can wind up with double the address space.
APL-11 was pretty old, and predated I&D space for RSX. Apparently people in the past had been able to produce I&D space versions, with mixed results, from the DECUS kit, but attempts to do so on current versions of RSX11M+ produced a task that would start and then immediately exit without doing anything. Even worse, attempts to create even the stock, non-I&D version from the DECUS sources also produced a task that did the same thing. The old .TSK file from the kit, however, runs just fine on M+ 4.6
I figured, waddahell, I'll have a crack at it. I mean, the sources are included, how hard could it be? A month later, I knew the answer to that question - hard - very hard. Ironically enough, this wasn't my first challenging encounter with APL. In 1971, I took a freshman computer science course. It taught the concepts of programming, using APL and PL/1. I hated both of them and swore never to work with computers again. It was 8 years later, when the typesetting company I worked at got automated using an 11/70 running IAS, that I got exposed to computing again.
So, anyway, first I get the source kit and load 'er in. The kit had the ability to produce several different variants - single and double precision, with and without floating point processor, and like that. I picked the double precision variant, with FPP support, and got to work. First thing I wanted to do was try and get this thing to build a normal version, without I&D, that would actually run. Sure enough, following the instructions, assembling and linking it produced a task that would start, and then exit immediately, without printing any error messages. Not a lot to go on there...
>
>run apl7
>
Normally, I'd link in the PDP11 symbolic debugger and see where it was going wrong - but APL-11 uses an ODL from Hell - the damned thing was over 100 lines long. A few abortive attempts to get the symbolic debugger to work with it, and I fell back to stones knives and bearskins - linking in ODT (Odious Debugging Technique), and sprinkling in IOTs. IOT instructions cause a register dump and exit, or a simple breakpoint when in ODT. Note - in order to get IOT dump and exit to work, it's necessary to change the 1 in the SST vector entry in module ERROR.MAC, to a 0 - otherwise it gets trapped.
SSTVT:: ;SST VECTOR TABLE
.WORD SYSER ;ODD OR NON-EXISTENT MEMORY
.WORD 0 ;MEMORY PROTECT ERROR
.WORD SYSER ;T-BIT OR BPT
.WORD 0 ;IOT INSTRUCTION
.WORD SYSER ;RESERVED INSTRUCTION
.WORD TERROR ;BAD EMT
.WORD TERROR ;TRAP INSTRUCTION
The program started, logically enough, in a routine called INIT. INIT called a subroutine called $LOAD, with a RAD50 string argument of APLDF1. If $LOAD returns with the carry bit set, INIT calls EXIT$S and...exits. $LOAD was always returning with the carry bit set. Returning with carry bit set is an RSX convention for reporting failure. So, I was wondering, why does $LOAD return a failure status?
$LOAD turns out to be a system routine that loads an overlay segment, of the name passed as the argument. It was the work of an instant to extract LOAD.OBJ from SYSLIB, and disassemble it with ORCAM (ORCAM is a utility, written by DJ Dunstan and Chris Doran that will disassemble an object file back into MACRO11 source. It's available on the APL11G.DSK virtual disk, UIC [373,221]. ORCAM is MACRO spelled backwards - get it?).
>lbr load.obj = [1,1]syslib.olb/ex:load
>orcam load=load
So, a perusal of routine $LOAD showed it to be pretty straightforward - it loops through a table of segments (pointed to by N.OVPT, offset N.STBL), looking for a segment with a name that matches the RAD50 string in the argument. But - stepping through the loop and examining the name field of each segment showed that all of the segments in the table had all 0's in the name field....what's up with that? When it doesn't match any of the strings with the argument, $LOAD hits the end of the table and returns...carry set.
So...segments got no names...so you can't load them. I recalled that the ZAP utility can list segments in a task, using the /LI switch. I tried it on the APL task I had just made.
>ZAP APL7.TSK/LI
>zap apl7.tsk/li
ZAP Version 04.00 Copyright (c) Mentec, Inc., U.S.A. 1999
Segment table
000002: 000000-056663 Root
000061: 056664-057327 Overlay
000062: 057330-062523 Overlay
000066: 057330-061103 Overlay
and so forth, for all the segments. The name is supposed to be in there between the address extents and the "root" or "overlay". It occurred to me to have a look at the old .TSK that comes with the DECUS kit. Here's how it displayed.
>zap apl7ok.tsk/li
ZAP Version 04.00 Copyright (c) Mentec, Inc., U.S.A. 1999
Segment table
000002: 000000-060103 ACOPY Root
000063: 060104-060577 DECNAM Overlay
000064: 060600-063707 .CSI1 Overlay
000070: 060600-061373 PARSE Overlay
000071: 061374-062567 PARSFN Overlay
000073: 061374-063153 PARSDI Overlay
000075: 060600-061407 DLFNB Overlay
and like that...the names of the segments are clearly there...
So, now I'm seeing why the old one works - it has the names, and newly constructed ones don't - but...what changed and why?
I got to thinking that something changed between the old version of RSX11M the working task that was included in the kit was built on, and the 4.6 version of RSX11M+ I was using. I loaded up a copy of RSX11M 3.2 in SIMH and copied the APL kit to it. Creating a new version of the APL task there produced a task that worked, and that ZAP showed named segments for.
A lengthy reading session with several different versions of the Task Builder manual shed a little light on this situation. Most of the APL program relies on autoload of segments - but in three places in the program, segments are manually loaded by calling $LOAD instead of autoloading. The TKB manual says that segment names are not used by autoloading, and are not included in the segment descriptors of tasks that use autoloading.
The manuals all the way back to RSX11m V1 state that the segment names will be omitted in tasks that use autoloading, and included only in tasks that use manual loading - but, up to at least RSX11m V3.2, the segment names are still present in autoloaded tasks. That allows APL to call the manual $LOAD routine successfully - if it was built on versions of RSX that still had the names in the segment descriptors.
But, how does the Task Builder know if a task is an autoload task or not, so it can decide to include or omit the segment names?? I created some little test programs that used autoload and manual loading, alone and together, to see what caused a task to know it's an autoload task and not include the segment names. to see. Here's the results..
3.2 4.6
ODL has * & $LOAD y n
ODL has $LOAD, no * y y
ODL has * only n n
ODL has no $LOAD, no * n n
So, it looks like, if the ODL file incudes a reference to module LOAD, in M3.2, it will have segment names included in the segment table, even if it has an * (autoload indicator) in the ODL file. However, M+ 4.6, if it has an * in the ODL, the segment table will have no names, module LOAD present or no. That explains how the old task in the kit, and the version I produced on RSX11M 3.2 could work, but the ones I produced on M+ 4.6 couldn't.
OK ,so what to do about it? Well, I fiddled around with trying to get the required modules to autoload, so we could drop the calls to $LOAD, but, no soap. Couldn't get it to go. Maybe I need to know more about how autoload works - but my goal was to produce a bigger version of APL-11, not to spend a lot of time becoming a perfect master of the arcane TKB arts.
As an alternative, I figured, that if $LOAD could be modified to find the right segments, it could LOAD them and things would proceed normally.
A basic Segment Descriptor looks like this.
+----------+------------------------------+
| Status | Relative Disk Address |
+----------+------ -----------------------+
| Load Address |
+-----------------------------------------+
| Length in Bytes |
+-----------------------------------------+
| Link Up (away from root) |
+-----------------------------------------+
| Link Down (toward root) |
+-----------------------------------------+
| Link Next (to neighbor) |
+-----------------------------------------+
| Segment Name |
+--- in ---+
| Radix-50 |
+-----------------------------------------+
| Window Descriptor Address |
+-----------------------------------------+
There's a few additional optional fields at the end of the descriptor, that support memory resident overlays, and for support of I&D, but they aren't of any interest in this caper.
So, I need something unique in the Segment Descriptor to identify it by when $LOAD looks for it, instead of the Segment Name, which is all zeroes. Load Address is right out - every overlay segment at the same level in a tree will have the same load address. The links are not unique either. But, the Relative Disk Address (the relative address of what block the segment occurs in the task file) is unique in each descriptor. You can get it from the ZAP /LI, or read it from the MAP file.
I modified the $LOAD routine to expect a word argument rather than two words of R50, and changed a few lines to it to make it compare that word argument against the Relative Disk Address field while looking for a match. Here's the original (the comments are mine - ORCAM is good, but not THAT good).26$: TST (R2) ;are we at the end of the segment table yet?
SEC ;set status assuming we are
BEQ 236$ ;if we were done, jump to exit
CMP 14(R2),2(R0) ;do the first three R50 chars match in arg?
BNE 54$ ;if not, skip to next entry
CMP 16(R2),4(R0) ;the first three chars matched - do next 3?
BEQ 74$ ;if these match, it's our segment, br to loading
;or fall through to loop to next entry
54$: Here's the changes...not really much to it...26$: TST (R2) ;are we at the end of the segment table yet? SEC ;assume not BEQ 236$ ;if not, get out and fail mov (r2),r3 ;move status and disk addr to r3 bic #170000,r3 ;mask off the 4 status bits
cmp r3,2(r0) ;is this the segment we're looking for?
beq 74$ ;if so, go load it
;else fall through, to loop to next
54$: LOAD also contained a couple of jumps to an unknown global address, D0000000. I just replaced those with JMP 0 - they were for fatal errors, so a bad address stack dump and exit would do just as well. OK, I assemble it,>mac load=load
and add a factor statement for it to the root of the ODLBASE0: .FCTR gload-O1-*(O11,O13,O14,O15,O16,O17,O18,O19)and add the factor gload: .fctr load.obj
While editing the ODL file, I also delete all references to PATCH or PATCH1, and also edit APL7.CMD and remove lineEXTSCT =PATCH1:400 Then I task build it. Trouble - I get errors from the task build - multiply defined symbols for $AUTO and $ALPBL. Those are for autoloading. The map file shows those symbols present in LOAD module - but that's the routine for manual loading - what's up with that? A look in LOAD.MAC tells the tale. There are a couple of "dummy" definitions for those, so that manual loading tasks don't try and access autoloading code. See below...
$AUTO::
RTS PC
$ALBPL::
MOV #<IE.OVR&377>,@#$DSW
But, we need autoloading for most of the program, so highjacking these is right out. I delete from the first occurrence of ".DSABL LSB" to just before the .END in LOAD.MAC (this also gets rid of a few hundred bytes in an ASECT section that we don't need). Success - it task builds with no errors. I run it, and it exits. But, that's what I expect at this point - I haven't put the numbers in for the Relative Block Addresses yet. I edit INIT.MAC, XERROR.MAC, and CLRCOR.MAC (the three macro files that have $LOAD calls in them), and substitute the block numbers for the RAD50 segment names of APLDF1,APLDF2,ROOT1, and ERSEG0 through ERSEG5. I subtract two from the disk number from the map file, since the map file numbers are absolute offsets from the beginning of the task file. Here's one example from INITThis is the call to $LOAD - tells us the argument is at ROTSEG
MOV #ROTSEG,R0 ;load root data segment
CALL $LOAD ;do it Here's ROTSEG, with its original RAD50 argument of APLDF1ROTSEG: .BYTE 3,0 ;load synchronously
.RAD50 /APLDF1/ ;low data Now find segment APLDF1 in the map file and get the block address.
Subtract two from it to make it "relative" and put it in as a word
where APLDF1 R50 string was.*** Segment: APLDF1
R/W mem limits: 074724 074735 000012 00010.
Disk blk limits: 000237 000237 000001 00001.ROTSEG: .BYTE 3,0 ;load synchronously .word 235 ;low data .word 0 ;filler word ; .RAD50 /APLDF1/ ;low data
The filler word is put in there, since the RAD50 name is two words long. Keeping the arglist the same length is not a bad idea, and is absolutely required in the XERROR segments, since they are in a table indexed by length. I leave the RAD 50 argument in, commented out, since it documents what segment we are mucking with.
Finish doing that to the other arguments, reassemble and re-TKB, et viola! We have a runnable task!>run apl7
TERMINAL..tt
WELCOME TO APL-11 X2.1
CLEAR WS
a_1 2 3 4 5 6 7 8 9 10
a
1 2 3 4 5 6 7 8 9 10
Here, the command assigns (APL uses "_" for the assignment operator, instead of "=" - Iverson was one of those fussy math types who hate using "=" for assignment. Why "_" instead? Because ASCII character for 95 used to be the left arrow symbol, before they changed it to the underscore. You see the same thing in RSX-15's MCR commands) a vector to variable "a". Typing "a" causes the value of "a" to be printed out.Looks like it's working...that's progress. OK, so now, after all that work, I'm where I should have started - APL-11, running more or less as it came, with no address space enhancements. This setup can run with a /INC memory increment of 35000 (36000 and above cause "not enough APRs" error message), and produce a workspace of 29720 bytes (.bxwa cause APL to display the workspace size).>run apl7/inc=35000
TERMINAL..tt
WELCOME TO APL-11 X2.1
CLEAR WS
.bxwa
29720 OK, finally, let's try TKB'ing with /ID added to the task build command. I do so, and run the task. Natch, it doesn't do anything...adding /ID to the task build command caused all the segments to shift around in the task, so, I get the new locations from the map file, edit them into INIT, CLRCOR and XERROR, re-assemble. re-LBR and re-TKB. Then, I get a running task. This time, I can use a /INC value of 64000 without getting the "not enough APRs" message. Success! Not so fast...when I run it with /INC that big, it loads and starts, displays the banner- but won't execute any APL commands - it just exits silently when you enter one. Now, after all this work, that's a disappointment.
Trying lots of different values for /INC, a pattern emerges, though. /INC values up to 37000 starts a task that runs correctly and executes commands. Going much higher, though, causes the command failure problem. With /INC=37000, the .bxwa command shows a workspace size of 31752. That's getting close to a suspiciously "binary" number. It's getting close to 32767, hex 7FFF - the largest possible positive value for 16 bit 2's complement numbers. Mark Matlock pointed out a note in a DECUS SIG tape submission, by Bob Awde, about a similar problem that occurred in a previous version, where ASR and ASL got used to convert the amount of free space from the number of bytes to number of words, and vice versa. When the size of the WS got large, it could cause a shift left to turn the size negative, or an unwanted sign extension could similarly gum up the works on a shift right. I thought all of those had been previously fixed, but, I had a look in CLRCOR.MAC and found one case left. I changed ASR R0 ;MAKE A WORD SIZE FOR THE BLOCKto
CLC
ROR R0 ;MAKE A WORD SIZE FOR THE BLOCK
The clear carry keeps a bit set in carry from shifting into the sign bit and making the value negative. OK, now assemble, re-LBR and re-TKB (fortunately a two line change didn't cause the segments to shift locations in the task file, so editing the values into the three MAC files from the map file wasn't needed this time) and run it again. This time, it's all roses. Large /INC values don't cause commands to fail. and a much larger /INC is possible. Max is now 64000 >run apl7/inc=64000
TERMINAL..tt
WELCOME TO APL-11 X2.1
CLEAR WS
.bxwa
53256 Alright Alright Alright.... Not bad - we have a workspace now that is over twice as big as when we started. Next, let's take advantage of another address space conserving tactic - the FCS Supervisor mode library. Most modern 11's have Supervisor mode , as well as I&D. Supervisor mode gets us a whole new set of APRs, and it's easy to add. All we have to do is add the lineSUBLIB=FCSFSL:SVto the TKB command file, and remove all of the references to SYSLIB and NOANSLIB in the ODL file, that called out all the FCS routines by name. Then, re-TKB. Naturally, that caused the segments in the task file to move around...so, edit in the segment disk addresses again, reassemble, re-LBR and re-TKB again...and once again, a running task. However, it didn't gain us much in the way of workspace size. /INC=64000 is still the max /INC you can use (make sense - that's 8 whole APRs worth of increase - ya only get 8 per space).
>run apl7/inc=64000
TERMINAL..tt
WELCOME TO APL-11 X2.1
CLEAR WS
.bxwa
53272
We wind up with an increase of around 20 bytes or so. But, it's still worthwhile to use FCSFSL. FCSFSL saves main memory. FCSFSL also puts all the FCS code into supervisor mode - that means you can now "flatten" the code and remove all of the overlaying there, which will reduce a lot of overlay disk IO. But, that's a whole 'nother story....
Here's the files for the project...aaareadme.txt A step by step guide to changes required to produce APL7.TSK
blog.txt A copy of this article in friendly ascii text mode
apl11.dsk An RSX11 virtual RL02 containing the APL11 DECUS kit, no fixes done
apl11g.dsk An RSX11 virtual RL02 with all fixes and WS increases done. apl7.tsk If you just want to run the task, here's a copy of the final result.
Saturday, December 5, 2020
RSX utility for reading VMS backup tapes
Back in the day, as the sun was setting on the RSX world, VAX/VMS grew strong in the land. As many people and sites migrated from PDP-11s to VAXen, there was a steady demand for a VMS utility that could read BRU format tapes (BRU is the RSX Backup and Restore Utility, used to backup up files and disks). Several pretty good solutions were coded up by the user community, and they all worked pretty well.
Back in September, I had occasion to restore some old VMS files from VMS Backup TK50 and TK70 cassettes. As it happens, at the moment, I don't have any VAXen that have TK tape drives installed. I do, however, have a couple of RSX systems that have TK drives - so I needed the opposite of the assorted VMS BRUREAD utilities. I did a little looking around, and couldn't find any RSX tools that could read a VMS backup tape. I guess that doesn't really come as a surprise - the IT world almost always operates by Italian racing rules (what's behind you is not important).
So, I needed a utility to restore files from a VMS Backup save set to an RSX system. I did a little looking around, and didn't find anything that would do the job. There was a Linux utility that can read VMS Backup tapes (vmsbackup), but it couldn't really deal with getting the file attributes right on the RSX system. I could have modified it to do the job, with a lot of work removing the Linuxisms and inserting RSXisms, but, I'd rather write my own solution in Macro-11 on a clean sheet of paper than spend a lot of time modifying a C program. There was a DECUS RT11 based project to read VMS Backup tapes on RT11, but, it didn't actually ever get completed - and RT11 is a whole lot different from RSX, so it wouldn't have been that helpful.
There's not a whole lot of info available about the format and data structures of a VMS Backup save set. I probably have the sources on microfiche - but, I haven't had access to a microfiche reader since I retired from MegaBig Engineering Corp. Most of the information I needed was gleaned by viewing the output of the still undocumented VMS BACKUP/LIST/ANALYZE command on some example save sets on a VMS system. I found some good info about the breakdown and offsets of the data in a Backup set on a VMS Freeware collection (https://www.digiater.nl/openvms/freeware/v30/logging-virtdisk/), as part of an interesting project by Glenn Everhart that provided automatic logging of writes to a device. More info was found in the file system MACRO definitions on both RSX and VMS systems.
In a nutshell, Backup save sets consist of big blocks, each of which consists of a block header and typically contains one or more "records". The possible type of records are
Null - null records are used at the end of a block to fill it to length
Summary - Each backup save set volume has a summary record, containing info about the block, including the command that created the save set.
Volume - contains summary information for each volume in the save set.
File - each file saved in the backup set has a file record, which contains info about the file, including its name and attributes.
VBN - VBN records contain the virtual blocks of a file. These records come after a file record.
Physical - physical record - prolly from backup/physical - I didn't research this, since I am not interested in BACKUP/PHYSICAL save sets. You occasionally find one in the middle of a save set - not sure what that's all about.
LBN - not sure - probably used with physical backups - didn't see any in my research
FID - These appear to contain a list of all the file IDs of the files that are included in an image backup.
So, to make a long story short, in a nutshell, to summarize, prècis style, as bullet points, generally speaking, to synopsize, from 10,000 feet, glossing over a heckuva lot of details, I whomped up a program that reads tape blocks via QIO, finds records in the blocks, and acts on each record. For each File record, I open a file of the indicated name and of the specified size and extent, with the indicated attributes. For each following VBN record after that, I write it sequentially to the file. When I get a new File record, I close the existing file and start a new one. Until we're done. Sounds pretty straightforward, nicht wahr? Yeah, it took a couple months to get it working just so. All of the IO was done via QIOs, including ACP QIOs, to avoid the space that including FCS would have cost us. Address space was an issue (as Cutler used to say, "Size matters") since Backup save set often used very large tape blocks.
This code doesn't change mode or muck about with the disk or OS internals using non-supported methods, but, like all my work, it's use at your own risk....
So, here's the code
To build...
mac btr=btr
tkb btr/id=btr
It has to be a /ID task, because I and D space is required to allow sufficient address space for the large tape input buffer. Sorry, RSX11M and IAS users (they don't have I&D space available).
To use...
Mount the tape as foreign
>mou mu0: /for
then...
>run btr
You have to "run btr" instead of installing it and doing BTR commands, since BTR doesn't have GCML and CSI command support - they were omitted to conserve address space.
It will prompt as BTR>. Enter the name of the tape drive. If that's all you enter, you get a listing of the backup saveset on the tape.
>BTR>mu0:
[GLEASON.ACCOUNT]SETACCOUNT.MAR;31
[GLEASON.ACCOUNTING]Z.MAR;2
[GLEASON.ACP]ATTMOD.MAR;3
[GLEASON.ACP]CHECKUIC.MAR;1
[GLEASON.ACP]CHGCRE.MAR;3
[GLEASON.ACP]CHGDATE.MAR;5
[GLEASON.ACP]DATE.MAR;38
[GLEASON.ACP]GETFILNAM.MAR;1
And like that.
If you want to restore all the files, specify an output directory
>BTR>mu0:/out=[somedir]
If you want to restore or list just some files, use the FIL switch, with wildcards
>BTR>mu0:/fil=*att*.mar (to list selected files)
>BTR>mu0:/out=[somedir]/fil=*uic*.mar (to restore selected files)
If you want to see some of the inner workings while listing or restoring, you can add the /DBG switch, with one of the following values
a.dbg = 1 ;print a whole bunch of debug info
a.wld = 2 ;print wild card processing
a.iosb = 4 ;print tape dsw and iosb
a.labl = 10 ;print label related stuff
a.file = 20 ;print file activities
a.summ = 40 ;print save set and volume summary info
a.rec = 100 ;print record processing
a.blk = 200 ;print block header info
These are octal values. You can get more than one at a time by adding them together - ie, wild card processing and record processing together, use 102. Note - some dbg options have bugs in them - /dbg:1 can fail in mid tape, for instance, and /dbg:200 occasionally fails as well. They worked well enough to debug the thing, so fixing them isn't a high priority.
BTR also restores the .DIR and .SYS files from the backup, so it would be a pretty bad idea to specify [0,0] as the directory to restore to....
Since a lot of VMS savesets spanned more than one tape, I have included primitive multi-tape support in BTR. When you get to the end of a tape of a multivolume save set, BTR will prompt for the next tape. Hang the next tape and press return to proceed. There's no checking to make sure that you hung the right tape, so...be careful...I also didn't bother adding any support for multi-savesets on a single tape. I mean, who does that? I never did , back when I managed VMS systems.
If you spot any problems using BTR - let me know...I'm working on Version 2, which will have a larger tape buffer, so I'll be fixing any bugs I hear about.
Wednesday, September 16, 2020
RD32 - Nothing Lasts Forever
Lately, I've been using an old Micro PDP-11/73 for some development work. It's compact, fits under the desk, and is plenty fast enough for the project. But, it only had a single RD32 disk drive in it, which left me a little cramped for disk space. There's not enough room to install DECnet, for example, so that means I have to sneakernet things on and off of it using RX50s.
So, I figured I'd add another RD32, which would double the disk space available. I installed a 6 button control panel (not strictly required, but it makes adding a second drive to a BA23 system easier). Time to install the disk... I spent quite a little bit of time on this - the cables I had aren't keyed, so I had to span the vector space of possible orientations looking for how to plug them in. No soap - the thing still wouldn't come on line. I tried some diags, but, since I didn't know how these particular diags acted when everything was working, I couldn't really conclude anything from their results.
It finally started making some odd noises, so I tried another disk, which worked fine. I pulled the one that wouldn't work apart, to see if I could tell what the problem was. Here's a picture of what I found....
It's a picture of the disk arm for the top platter, with a broken wire trailing off from where the read/write head used to be attached. So, no surprise it wasn't working.
Here's a picture of me reflected in the top platter - nothing to do with the problem, it's just how I do a selfie...
Wednesday, September 9, 2020
TU58 emulator for RSX11
So every once in a while I try to retrieve some space here in the War Room (my computer room - we call it that because, during a spirited discussion about how messy it was, I jokingly told my wife "we can't fight in here - this is the War Room") by assembling some of the parts into systems. I have an old BA11-VA QBUS box I got in trade a long time ago.I figured it could consume a few QBUS cards and maybe even do something useful (well, OK, maybe not useful, but at least amusing).
I had a look at the specs for it. The power supply isn't all that powerful in that box, so the choice of cards is a little limited. It could just barely power an 11/23, an MXV11A and an RQDX3 in there. And that would have been a relatively useful system. - I could control a floppy and an old RD disk with it, and the MXV would provide memory and two serial ports.