Wednesday, October 29, 2025

New version of OPIND, the RSX11 ODS-1 disk investigation and patching utility

  So here's a new version of OPIND, the RSX11 ODS-1 explore and fixup utility.

   Truth to tell, the previous version of OPIND was...not very good. I only worked on it long enough to get it able to patch the disk corruption problem I had at the time. It did the basics, but a lot of the fancier functions had bugs in them, and it was hard to predict what radix particular numeric inputs were expecting. As well, it was unclear whether some commands acted on in-memory copies, or directly on actual blocks in the file. This new version has had a lot of debugging done, and a slug of enhancements made. Now you can specify the input radix - HEXadecimal, DECimal, or OCTal. There are also new features that allow easier access to the Index File extension headers (file IDs 6 and 7).

  So let's talk a little bit about how OPIND works and how to use it.

  In this version, there are several data buffers where disk blocks live. The main one is the Current buffer. It is where disk blocks are read from and to, and is the default place where commands act unless a different buffer is specified.

  The other buffers are HOME (contains the Home block), IFH (Index File Header), IF6 (file ID 6, the first Index File Extension Header) and IF7 (file ID 7, the second Index File Extension Header). These are one block sized headers. There is also the Bitmap buffer, a special case among special cases, which contains the Index File Bitmap, and can be up to 8 blocks long. These all get special locations because they are...special...they impose the ODS  structure on the disk.

  These special buffers'  LOAD commands store them in their special locations, not the Current buffer like LOAD BLOCK and LOAD HEADER do. As a result, they have to be COPYed to the Current buffer, to be modified if necessary. Then they can be written to the file, to their approriate locations by their WRITE commands (their WRITE commands write from the Current Buffer, to their location in the file. If you expect, for instance, WRITE HOME to write from the HOME buffer to the file....well, you'll be disappointed).

  So, for example, to patch something in the HOME block, you could LOAD HOME (which is also done automatically at startup BTW), then COPY HOME, which copies it to the Current buffer. You can check the contents  of the Current buffer with FETCH commands, and change contents of the Current buffer with DEPOSIT commands. When your changes are complete, you can then choose to WRITE HOME (or IFH, IF6, or IF7{ and the contents of the Current buffer are copied to the approriate place in the file. Note that at that point, the old contents are still in the HOME buffer, so you'd likely want to do a LOAD HOME to refresh it from the file, so it reflects your recent changes.

  At startup, HOME, IFH, IF6 IF7 and the Bitmap buffer are loaded from the target disk. That is, if the disk isn't too screwed up. If the Home block or the other special blocks  are damaged, lots of the advanced functions that locate by file ID or bitmap bit, or special  buffer name aren't going to work, and your first job will be sorting out the damage and fixing it with the simple commands that only take a disk block number as input - LOAD BLOCK, WRITE BLOCK, GET and PUT commands.

  GET and PUT deserve some mention. They will read and write the current block. This "cut and paste" buffer survives across invocations of the utility - so, for instance , you could use the utlity on a good disk, to load a block of insterest into the Current buffer. You could save the block with a PUT command, and exit the program. Then you could start it up again, this time targeting a problem disk, and use the GET command to load that previously saved block into the Current buffer. perhaps edit it a bit, and then do a WRITE HOME (or, if that's not working so hot, WRITE BLOCK 2) command, to store in in the problem disk's HOME block location.

  Then there's the Bitmap buffer. It's 8 blocks long, so it won't fit in the Current buffer (which is one block long). It gets edited in its special buffer via TEST ID, CLEAR ID and SET ID commands. These edits can then get copied back to the file, direct from the Bitmap buffer, via the WRITE BITMAP command. What could be cimpler?

  Lessee....let's explain how DUMP works. DUMP with no arguments dump the Current buffer. DUMP HEADER 123 reads header 123 from the file and dumps it. DUMP BLOCK 123 reads the block 123 from the file and dumps it. Both of those variants expect the specified number in the currently chosen radix. DUMP HOME, IFH, IF6, IF7 and BITMAP dump the contents of those special buffers. They don't read fresh from the file. All variants of the DUMP command respect the output radix switches /HEX /OCT /DEC /ASC /R50. 

 And a word about the checksum functions. File headers and the Home block contain checksums of their contents. If you edit one of those, you need to update the checksums before you write them back to the file. So, suppose you LOAD HOME, then COPY HOME to copy it to the Current block. You edit it by using FETCH and DEPOSIT. Now you need to CHECKSUM HOME UPDATE, to update the checksum fields. Then you can WRITE HOME, which will write  the newly modified and checksummed block into the disk's home block. For a header, you;d read it into the Current block via the LOAD HEADER xyz command (or COPY IFH, IF6, or IF7 for those special headers). modify it in Current, Checksum it with CHECKSUM HEADER UPDATE, and then WRITE to...where it needs to go, depending on what it is. There is also CHECKSUM HEADER CHECK and CHECKSUM HOME CHECK, which will evaluate the Checksum of a Header or Home block, in the CUrrent Buffer.

Numbers entered as input are interpreted according to current radix
The default input radix is hexadecimal, unless changed by radix command
Output radix is ascii unless set by command line switch.
Output radix switches are /HEX /OCT /DEC /ASC /R50 (specified as /<radix> in the cpmmand summary below. /R50 comes in handy when looking at headers, since file names in headers are encoded in RAD50.

radix hex                                input numbers interpreted as hex
radix oct                                 input numbers interpreted as octal
radix dec                                input numbers interpreted as decimal
load block 23                        read block 23 into current block
load header 23                     read header 23 into current block
load bitmap                           read bitmap into bitmap buffer
load home                              read home block into home buffer
load ifh                                     load index file header into ifh buffer
load if6                                     load 1st index file ext header into if6 buffer
load if7                                      load 2nd index file ext header into if7 buffer
dump                                        dump current block as ascii bytes
dump /<radix>                      dump current block in specified radix (eg, dump /hex)
dump block 23                      dump block 23 as ascii bytes
dump block 23/<radix>     dump block 23 as specified radix  bytes (eg, dump block 23/oct)
dump header 27                   dump header 27 as ascii bytes
dump header 27<radix      dump header 27 as selected radix  bytes
dump bitmap                        dump the header bitmap as ascii
dump bitmap/<radix>       dump the header as specifed radix bytes
dump home                           dump home block as ascii bytes
dump home/<radix>          dump home block as specified radix bytes
dump ifh                                  dump index file header as ascii bytes
dump ifh/<radix>                 dump index file header as specified radix bytes
dump if6                                  dump index file header as ascii bytes
dump if6/<radix>                 dump index file header as specified radix bytes
dump if7                                  dump index file header as ascii bytes
dump if7/<radix>                 dump index file header as specified radix bytes
fetch @200                              display byte at loc 200, current radix, in the current block
deposit 10@123                    deposit 107,current radix,at location 123,current block
put                                              save current block in  file - like a paste buffer
get                                               get saved block from paste file, make it current
write block 123                      write current block to block 123, with 123 in current radix
write header 123                   write current block to header 123, with 123 in current radix 
write bitmap                           write the bitmap out
write home                              write current block to home block
write ifh                                     write current block to index file header
write if6                                     write current block to 1st index file ext heade
write if7                                     write current block to 2nd index file ext header
test id 123                                 test bit 123 in current radix in the header bitmap buffer
set id 123                                  set bit for header 123 in current radix in header bitmap buffer
clear id 123                              clear bit for header 123 in current radix in header bitmap buffer
copy home                               copy home block from its buffer to the current buffer
copy ifh                                      copy index file header from its buffer to the current buffer
copy if6                                      copy  first index file extension header from its buffer to  current buffer
copy if7                                      copy  first index file extension header from its buffer to the current buffer 
checksum home check       check the home block checksums the  current block
checksum home update    update the home block checksums in current block
checksum header check    check checksum in header in current block
checksum header update  update checksum in header in current block

  So much for Version 2. Version 3 will have search functionality, an ANALYZE command that displays the fields in the special buffers. and the ability to follow and operate on the blocks in a particular file.

  But enough of this silly documenting, It's turning into a case of TL;DR. Let's get down to the code. 

opind.mac

  To build,

>mac opind=opind
>tkb opind/pr:0=opind

  It's built /PR:0 so it can do logical block IO to disks, no matter how they are mounted or who has them allocated. LIke I've said - you can do some serious damage with this ultility, so you better understand what you're doing. If you're trying to patch up a corrupted disk, it would be better to make a physical copy of the disk in question, and mount that copy /FOR, and then have at it with OPIND - tht way, if things go bad, you haven't lot any ground.

  Let me know if you find any bugs or have any problems.,,

  

Saturday, May 31, 2025

MSCP and DUP talking to RQDX3

  I have a few BA23 systems here. Among others, one is an 11/73, and the other is a MicroVAX I (I have a taste for minimalism). They each have RQDX3 cards in them to access MFM disks. 

  MFM disks...as the bosun said in GC Edmondsons's "The Ship That Sailed The Time Stream", regarding batteries, "They ain't diamonds" - meaning, they aren't forever. I've gone through a lot of RD54s, RD53s, RD32s and RD31s. The ones I have left that still work howl like banshees, running on their square dry bearings.

  So they needed to be replaced, before I was left with what is usually my favorite thing...nothing. Enter David Gesswein's MFM disk emulators. These are great products. Quiet and dependable. I bought six of them and figured, I'd have the RD53/54s replaced in a day. One pair went into my PRO380 and worked great as two RD53s. The only wrinkle there is that you have to extend the power off/shutdown timing in their parameter settings, and power the PRO on twice, since the PRO disk controller doesn't give the emulators time to start up before deciding there's no disk present. But, the second time, it works great....and really quiets down the PRO.

  The 11/73 and the MIcroVAX 1, different story. No fault of the emulator cards, though - I had a series of cascading failures. An RQDX3 failed in one of them, and two of my spares were also bad. A new drive cable I was using turned out to be bad. And, while plugging and unplugging the drive cables repeatedly, I managed to bend pins in two of the BA23's sockets. Those pins are soft as butter. As well. a couple of RD32s I was using to test with turned out to be bad. This made for a lot of linear combinaitons of parts that wouldn't work....and it got worse as the parts were swapped around between systems trying to test.

  While these struggles were going on, I was using VMS and XXDP to test the results of the  swapping around, looking for the faults. They each took a middlin' amount of time to test with. I wanted something that would give me a quick pass/fail sort of answer as to the health of the controler, cabling and hard drive or emulator.

  A few blog posts back. I detailed how to talk MSCP to an RQDX3 in a downloadable image, for loading software via ethernet. It was the work of a moment to hack that program around to where it just issued MSCP commands to the RQDX3 and disk, sufficient to see if anybody was home. I won't bore you again with the details of how to do that - see the previous blog post if you're interested.

  But, while trying to get the two systems running again, I became far more interested in working on this utility. With a little work, I realized I could make it into a useful tool for poking at MSCP controllers and disks, beyond just seeing if they were alive or dead. I added the ability to do several MSCP functions as well as testing for life. While doing that, I became curious about DUP. DUP stands for Diagnostic/Utility Protocol. It is mentioned in scant detail in the DEC doccos about MSCP. It is used to load and control diagnostic and utility programs in MSCP controllers - thus the name DUP. The doccos do spell out the format of messages used to request DUP functions - the format is essentiially the same as MSCP control message format - but none of them that I could find spelled out how to actually send these commands to  DUP.

  I finally puzzled out the answer. The command packet format is the same as MSCP (although with different opcodes and success status values) - but it turns out that the two words BEFORE the command packet determine which protocol is used.  For example, here's part of a a typical MSCP command packet.

                  31                              0
                  +-------------------------------+
                  |   command reference number    |  0
                  +---------------+---------------+
                  |   reserved    |  unit number  |  4
                  +---------------+-------+-------+
                  |   modifiers   | rsvd  | opcode|  8
                  +---------------+-------+-------+
                  |  unit flags   |    reserved   | 12
                  +---------------+---------------+
                  |           reserved            | 16
                  +-------------------------------+              

   

  What nothing in the usual sorts of doccos tells you is that the two words previous to it determine who gets it. The packet is actually two words longer, with the top two words referenced as a negative offset from the start of the command packet. I finally found this little bit of info in a diagram in the MSCP patent application. Here's how it looks on a command packet.

                  31                              0
                  +------+--------+---------------+
                  | Type | MT & CR|    pktlen     | -4
                  +---------------+----------_----+
                  |   command reference number    |  0
                  +---------------+---------------+
                  |  reserved     |  unit number  |  4
                  +---------------+-------+-------+
                  |   modifiers   | rsvd  | opcode|  8
                  +---------------+-------+-------+
                  |  unit flags   |    reserved   | 12
                  +---------------+---------------+
                  |           reserved            | 16
                  +-------------------------------+              

  "Pktlen" is a word, and "Type" and "MT&CR" are bytes.If the packet length and the protocol type fields (pktlen and Type)  are zero, then MSCP will handle the packet. If the packet length is correct for the opcode specified, as a DUP opcode, and the type field is 2, then DUP will handle it. By blind good luck, my previous MSCP programs worked just because by happy accident, the two words before the command packet just happened to be 0, so I got MSCP successfully.

  The credits and msgtyp bytes are used for more complicated schemes involving simultaneously active IOs. They're  always 0 for my usage.

 Anyway, enough prattle about figuring out how to invoke DUP. Let's talk about this utility. The utility works like the disk installing software in a previous blog post, via DECnet MOP download. No software or OS required on the target machine.

$ mcr ncp set node negato load file dua0:[mvax1]mscp.exe
$ mcr ncp sho node negato char
Node Volatile Characteristics as of 18-SEP-2021 10:01:36
Remote node =   10.103 (NEGATO)
Hardware address         = 08-00-2B-26-2F-84
Load file                = DUA0:[MVAX1]MSCP.EXE

  Boot the MIcroVAX via network, and it should load mscp.exe

>>>B XQA0
ATTEMPTING BOOTSTRAP




                                  MSCP X02A02
                            Control-G Consultants



  You'll be prompted for the disk number. Then you get a "ribbon" of commands.

Enter disk unit number:

0
Enter command (HELP HALT INIT AVAI ONLI STAT READ WRIT CLEA HACK GETD DIRE)
 
Help - prints out a page of not particularly helpful information.
HALT - Halts the processor. Handy if you get scared, or if the control panel is not right next to you.
INIT - Initializes the RQDX3. Needed before any other command (except HELP) is used. If you don't, then it will hang.
AVAI - takes the disk offline, which makes it available to be put online again.
ONLI - takes the disk online
STAT - shows the state of things
READ - reads a block. Gotta go ONLINE first. It will prompt for a block number
WRIT  - writes a block...works like READ
CLEA - clears out the block buffer. The buffer is saved between read and write, so you could
"cut and paste" a block to another block. This clears it back out to zero, erasing anything you  previously read.
HACK - DUP command - Possibly the most interesting DUP command. This will load a block of PDP11 code into the MSCP controller and execute it as a task there. The PDP11 code is in the program between "ZAP:" and the definition of "ZAPLEN". The program included in the utility just bloinks the write protect lights. More research will show if anything useful can be run this way. It's necessary to go ONLINE before using HACK command.
GETD - DUP command - Get DUP status
DIRE - DUP command = This executes a local command called DIRECT, which will return a list of programs present on the controller. Does nothing useful here, since RQDX3's have no built in programs. But, on other MSCP cards, who knows? As is, it serves as an example of how to execute an MSCP controller built in program.




  I should mention...this is a utility that speaks directly to the disk controller, using poorly documented and unsupported features....a disk could get hurt if things go wrong, so if you use it on a machine with good data on the disks, make sure you have a backup before ...experimenting. Don't come crying to me if you manage to erase a disk or blow the format off of it....

Saturday, November 30, 2024

RSXstation - QVSS VCB01 graphics on a PDP-11

   A while back, I got a couple of VCB01 cards in a lot of other MicroVAX cards I wanted. The VCB01 was used in the VAXstation I and VAXstation II to provide simple graphics, and mouse and keyboard. This was referred to as QVSS graphics - Qbus Video Sub System. It's a relatively simple card - plugs into a Q22 bus, and has 256Kb of memory for screen memory, and a scan map that determines what lines are mapped where on the screen. And, like I said, it also supports a mouse and a keyboard. It displays one plane of monochrome.  Not the most capable graphics card in the world, but, I got to wondering - could it work on a Micro-PDP11?. Micro PDP-11s have a Q22 bus - could the VCB01 provide graphics on a PDP-11? Graphics for RSX sounds interesting. A look at the VCB01 doccos didn't turn up anything that would prevent it from working.

  I have a BA23 box test system that has a PDP-11/73, 1024KB of memory, an RD32 and assorted other options in it. I stuck the VCB01 in the box, after all the other cards on the bus - apparently the VCB01 can act funny with bus grants, so it gets to be last,  where it can't screw up as much. I powered on the machine, and it went into its normal self test. Interrupting the self test lets me use the "M" command - display the hardware map. I saw all the usual things, CPU, memory, CSRs. I additionally now saw a new 256 KB area of memory at 16000000, and a set of 16 CSRs at 177200. Both of those are what's expected with a VCB01. So that's a good start - the hardware is visible to the system, and didn't look like it stepped on any of the other hardware already present.

 Commands are Help, Boot, List, Setup, Map and Test.

Type a command then press the RETURN key: M

15.206 MHz

Memory Map

Starting     Ending       Size in      CSR           CSR    Bus
Address    address      K Bytes    address      type    type

00000000 - 03777776     1024       17772100     Parity  Qbus
16000000 - 16777776     256                                         Qbus <------This is the 256K of VCB01                                                                                                             memory

I/O page Map

Starting     Ending
Address    address

17760440 - 17760456
17765000 - 17765776     CPU ROM or EEPROM
17772100                        Memory CSR
17772150 - 17772152
17772200 - 17772276     Supervisor I and D PDR/PAR's
17772300 - 17772376     Kernel I and D PDR/PAR's
17772516                        MMR3
17773000 - 17773776     CPU ROM
17774440 - 17774456
17774500 - 17774502
17776500 - 17776516
17777200 - 17777276      <----------------------------------These are the VCB01's 16 CSRs.
17777520 - 17777524     BCSR, PCR, BCR/BDR
17777546                        Clock CSR
17777560 - 17777566     Console SLU
17777572 - 17777576     MMR0,1,2
17777600 - 17777676     User I and D PDR/PAR's
17777744 - 17777752     MSER, CCR, MREG, Hit/Miss

17777766                        CPU Error
17777772                        PIRQ
17777776                        PSW

  I booted RSX11M+, and it completed successfully. Man, was I surprised! RMD showed that RSX only knew about the usual 1024KB of memory - that's good, it didn't detect and try to use the 256KB on the VCB01, so I wouldnt have to fight with RSX over using it for graphics. So far, so good....time to hook up a monitor, I reckoned. I had an old DEC VR100 taking up (a lot) of space, left over from my old VAXstation 100, that was specced to be compatible with the video output of the VCB01. I hauled it out and and dusted it off. It turned on and displayed...well, not a raster, but some brightness on the screen, so I went to work making a cable from the DB15 on the VCB01 to the three BNC connectors on the monitor - Video, Horizontal Sync and Vertical Sync.

  This took a while and a lot of experimentation. I hooked up an oscilloscope to the three outputs and saw that the video was present, but the sync signals were missing. Turns out that I really needed to program the 6845 CRT controller on the VCB01 before it would know what kind of sync to generate, and when.  This looked like a complicated slug of calculations, about a page's worth, to get 16 values. This stuff looked like Buck Rogers math, so I looked for an example somewhere to copy from (I remember when the motto of DECUS was "steal from your friends"). I tried the values in the  VAXstation 100 Architecture Manual, figuring, they'd be close. Some  sync signals now showed up on the osillloscope,  but no soap - nothing on the VR100 display.  Totally nothing, actually, now not even the former bright glow it had before I hooked up the cables from the VCB01. Now I'm thinking,  the VR100 is dead. No brightness on the screen. Was it damaged by the strange sync frequencies that were produced while I was trying to program the 16 values? That was apparently a problem thing, back in the day. I dunno. I'll have to dig into it and see what's wrong. Could just be a coincidence. Maybe an aged capacitor gave up the ghost right as I needed to use the monitor. Looks like I'l have to troubleshoot it like an old TV. But that's a project for another day. I pushed the deadly high voltage box of puzzles and surprises aside on the workbench, and looked for a substitute display. Josh Densch, a VAXstation 100 owner,  pointed out that a NEC Multisync monitor would work, so I got a cheap one from Ebay. Apparently they will sync up to most anything, without blowing up. 

  So I hooked it up and had another go. Success! I got some more or less  random patterns on the screen at power on, no doubt due to whatever random values were in the 256K of pixel RAM on the card. But the screen didn't look right, it was tearing and flashing and rolling -  the sync clearly was still an issue.

Apparently, the 6845 has to be set just right before you get a usable display. For whatever reason, the VAXstation 100 values I had weren't doing the business. I tried a bunch of settings for similar graphics cards that used 6845s on hobby gear (back in the day, the 6845 was a popular hobby microcomputer CRT controller) - still no luck. I started looking for the sources to the QVSS driver from the MicroVAX, to copy the initializaion of the 6845 from, but, nothing to be found. I posted a query on the Vintage Computer DEC forum, and user Bitly provided the initialization values that QVSS uses, which turned out to be in the DECWindows sources. Thanks again, Bitly!. I plugged in those values, and, success! A more orderly pattern appreaed on the screen, still looking wild but no tearing and rolling.  Here's what it looked like.



Why the VAXstation 100  Architecture values for its 6845 didn't work - another DEC history mystery.

  Now that the display seems stable, it's onward to accessing it while running RSX. But this is a PDP-11. A task can only address 64KB, as 8 8KB chunks, at a time, using 16 bit addressing. You can't directly access the 128K of pixel space from a simple task. But we can access anywhere in the Q22 address space, by changing the mapping of a tasks' APRs - an address page register. A task's 8 APRs map the 8KB chunks of task logical space to the 22 bit space of the Q22 bus. I could map an 8KB chunk of a task's address space to 8KB chunks of the 128K of pixel memory on the VCB01 starting at physical address 16000000.

    So I wrote the typical sort of task to test something like this - it's built as /PR privileged to give it access to the IO page, where the APRs live.  The 256K of pixel memory is effectively a  1024X768 pixel array.  Program setlin abstracts that as x,y values. When it comes time to write to the memory, it first converts the x,y coordinates to an index into the equivalent 98304 byte array, with the low 3 bits indicating which bit in the byte needs to be set. From there, we look up what value to enter in an APR to reach it. Then we switch to Kernel mode and put that value in KISAR6 (Kernel Instruction Space APR 6), to map the 8KB chunk that contains that byte. Why Kernel mode? Why KISAR6? It's what similar DEC utilties do. If you're interested, have a look at the code. I did a previous blog entry that does a poor job of describing mapping things via APR, have a look at that, or better yet, have a look at the RSX Task Builder manual to find out more. 

 

  In any case, now I can write programs that set bits by X,& coordinates on the screen (the upper left corner is 0,0. X increases to the left, and y increases going downward). Here's some examples.







  OK, they aren't great art, but I don't have any ready to go drawing software for RSX.


  Here are programs that zero out or set all the bits in the pixel memory. They write entire bytes instead of setting bits, in the interests of speeding things along.

  This one zeroes out the pixel memory.

clear.mac

  This program writes all ones to the pixel memory.

set.mac

  Here's a test program - it draws some boxes, and some lines. It addresses individual bits/pixels, has more logic in it than the above two. It draws the RSX11 banner and a grid. 

  setlin.mac


  These programs have to be assembled and linked...special, to find all the symbols and routines invovled. Here's the commands for setlin.mac as an example

mac setlin=[1,1]exemc.mlb/ml,[11,10]rsxmc/pa:1,[vcb01]setlin
hft setlin/pr/-cp=setlin,[3,54]rsxvec.stb/ss,[1,1]exelib.olb/lb

  The mac commands  assume that the source files are in directory [vcb01]. If they aren't...you know what to do. The taskbuild commands assume that you have removed ...TKB and installed HFT (the Hybrid Fast Taskjbuilder) in its place.

>rem ...tkb
>ins $hft

 HFT is not required for these programs to work...but, ya gotta use the fastest task builder you can find....if you're on an older version of RSX11M+, use TKB.


Here's the command files to assemble and link them

clear.cmd

set.cmd

setlin.cmd


  So, this is all middlin' interesting. One big problem, though, is that this is slower than Christmas. I mean S-L-O-W. You'd think it was coming in via 1200 baud modem.  For some reason, it takes forever to draw something. Part of it is the test programs were not written to be fast - to write a pixel, you have to call several subroutines and do a $swstk for each one. Also I was experimenting with passing all args on the stack, instead of in registers. Doing dozens of pushes and pops for every bit set doesn't help speed things up. Hey, these are proof of concept test programs, not production grade. Ideally, this should be implemented as a driver (I'll get around to doing that). Maybe there's something wrong with my test system. But I wonder, if the VCB01 is just intrinsically slow on an 11, and that's the reason that it was never supported on 11s. Or it's bugs in the programs. Dunno yet. I want to get it running faster, so I can do some  fun things,  like using the pixel memory as a disk, and get to watch the blocks fly in and out on the screen. Or maybe as a swap disk, work files or task memory, like the classic Alan Frisbie story. As the story has it, he  realized that an early memory mapped graphics display was being sold cheaper than just buying the memory it contained. He started running tasks out of that memory, and jokingly asked the manufacturer to add the ability to select what task to run next using the light pen.

  Anyway, let me know if you give any of this a try. I'd love to hear about other results.


Tuesday, April 16, 2024

RSX utility for converting Logical Block order virtual RX50 disks to Track, Sector order.

   Several posts back. I posted a utility, TSTOLBN, that converts RX50 disk images that are in the same layout as a physical RX50 diskette (I call that Track, Sector or TS  order - it  has the blocks in a track  interleaved every other block, and the track  starting sector  is skewed by two sectors/each track, plus the last track is at the first physical track on the disk) , into just a string of blocks, in numerical order - the format used by RSX and VMS virtual disks, and SIMH disks (I call that Logical Block order, LBN). 

  That does the business for all of my needs - I use RX50 images as files on P/OS, RSX, VMS and SIMH, and they all need LBN format. Additionally, if you have an LBN order virtual disk, you can read and write it directly ro a real RX50 diskette, and the MSCP/Pro Controller will take care of converting it to/from the physical Track Sector format on the disk for you. But I've been noticing of late that people are needing RX50 images that they can use in assorted external disk emulating gizmos - and they all required the same format as a physical RX50 uses - TS order.

  Several folks have written converters in C and Python to convert LBN to TS order. But I prefer to work in the DEC environment as much as possible, so I needed a tool to do this conversion, that runs purely in the RSX and P/OS environment, no Windows/Linux/Python/C compiler required.

  So I took a little time and, using the previous converter (TSTOLBN, Track Sector To LBN) as a base, created a utility called LBNTOTS (Logical Block To Track Sector).

  Really, it's almost the same program - just had to make a few changes to the interleave and sector translation arrays, and the funny first track/last track logic. And I cleaned it up a little in general. 

  Here's the source code...


lbntots.mac


To make...
 >mac lbntots=lbntots
 >tkb
 TKB>lbntots=lbntots
 TKB>/
 Enter Options:
 TASK=...LTT                   ;stands for LBN To TS
 LIBR=FCSRES:RO       ;this is optional - saves memory on a busy system
 //
>

 To use...
 >run lbntots
 LTT>outfile=infile

 or install it and use direct from the command line

 >ins lbntots
 >LTT outfile=infile

 Outfile extension defaults to .dsk, infile extension to .dsk


Monday, January 22, 2024

Install prorgams via ethernet without OS - update to PDP11 version

  So my 11/73 system, in a BA23, has recently developed a memory problem and won't boot. The ROM diags show...

Expected data   = 052525
Bad data            = 052524
Address             = 02740032

 Looks like one bad bit on a chip. I replaced the card with a spare card, but it's too small and now RSX can't boot, I want to run some memory diags on the failed card, hoping that they will be able to give me some more clues as to which chip has carked it.

  My XXDP RX50 only had disk diags on it, so I needed to add QBUS memory diags, VSMAC0 and VMJAB0 (sometimes listed as CVMSAC0 and CVMJAB0).

  I used SIMH and an RL02 XXDP disk image to create a new XXDP RX50 disk image, comtaining the memory diags and the oft used ZRCHB0, the MFM disk formatter. Next I needed to copy the RX50 image to a physical floppy.

  I have a set of tools for this - the client/server disk copying tools I wrote to load VMS and RSX on systems without OSes. They should work fine on an RX50, since they are controlled by an RQDX3. 

  I had a look at them, and relaized that the VAX server tool, LOCALWRITE, had been upgraded a while back, and the PDP11 client tool, REMWRT, was no longer compatible with it. LOCALWRITE and REMOTEWRITE had been updated to allow entering what unit number to write to, and what file to download (per suggestions and help from Hans-Ulrich Hölscher), as well as some changes to the communiction protocol used between them. (When copying to a PDP11, the VAX LOCALWRITE server is used, since I haven't written LCLWRT yet, a PDP11 version of the server task).

  So I prodced a new version of REMWRT with the needed changes. They aren't interesting enough to describe. Here's the new version of REMWRT.MAC

remwrt.mac


  Please see earlier blog post for the instructions about how to assemble, link, load and use it.

 So, I used LOCALWRITE and REMWRT to copy the XXDP RX50 image to a real RX50 on the system in question. Copy worked fine, disk boots OK. Next step - take out the spare memory card and reinsert the bad one, and boot XDP and run the diags. Here's hoping for some useful info.... 


Wednesday, September 20, 2023

RSX11D V4 boot problem update

   A few posts back I posted about finding RSX11D V4, on a deceased DEC engineer's RK05 pack.. 

  That post presented it, but with a boot problem that required a manual step or two to get it to boot. The boot problem occurred both in SIMH and on real hardware.

  Tony Lawrence read the post, and figured out the problem (along with some others). In less than 24 hours. He said I could share his analysis, in a shortened form (his work was incredibly detailed). Thanks, Tony! Heres a note from him, summarizing the problem.

"The boot loader abuses a hardware-dependent "feature" of an old RK11 disk controller and reloads its word count while the operation is still in progress, so to keep the disk controller going (with what it was doing, because the only thing to stop it would be an error or the WC reaching 0): until it reaches the end of memory.  More modern controllers (and certainly, simh) can't be used with such a "trick",as like I said previously, they are numb to the register write while the operation is on-going, and in case of simh, the operation just stops when it reaches the word count of 65534 (because the write is not time-simulated, it's a one-shot operation, internally, of basically one read off of the disk image -- so the new WC would not have ever been noticed)."

  He included a disasasembly of the code in question, and pointed out that in the process of doing all this, the boot sector loads the system image on top of the boot sector, which isn't a problem since the code that overlays the boot sector, from the system image, is the same.

  In another paragraph, he pointed out...

"I can't know why the developers chose to use this boot hack with sizing the memory using RK11 -- because that's basically what they were doing.  At the boot time, the file structure of the disk is obviously unknown, but the first 245. blocks following the initial Disk Address (DA), do load the operating system.  Since they kept reloading the WC, it'd cause the controller to keep on going, loading up all the following sectors (with basically unstructured garbage) until the bus timeout -- address does not exist -- converted to the NXM error by the controller.  Should they load fewer than 128K because of the NXM condition (e.g. 96K phys mem), the end of the image wouldn't be read in, and the system would crash (as the tail of the image file contains something which looks like the STD -- the System Task Directory).  If the NXM occurred past the 128K, it's all good and everything can actually continue! So it was not considered as an error at all, but an attempt to load as much as possible from that initial DA and to make sure the memory is not tight.  There could be a problem, though, with such a logic, if the OS image was located closer to the end of the drive, then it could have triggered an OVR (overrun) controller error before the end of memory reached, and the boot would fail (would loop to address 0 to start over again).  Anyways, it was a very bad example of how things should NOT be done! LOL"

  He even included a patch to remove the manual steps that I had been using to get the image to boot.

"All in all, if you open the disk image (the .dsk file) with a binary editor, go to locations 146 and 6421146, and enter the following to replace the next 7 words:

  Tony also pointed out that if you do a SYSGEN on this system, you'll have to apply the patches again, pointing at the new RSX.SAV file. I'm working on an automated way to take care of that - stay tuned for another update when I get it done.

xxx146: 105737  ; TSTB @#177404  ;  Complete? 
xxx150: 177404  ;
xxx152: 100375  ; BPL 146                   ;  Loop if not
xxx154: 005737  ; TST @#177404     ;  Error?
xxx156: 177404  ;
xxx160: 100707  ; BMI 0                        ;  Loop back to boot if so
xxx162: 000240  ; NOP

Then your system will boot right away!  (You can actually skip patching the boot sector, locations 146+, and only patch locations 6421146+ -- note this is an offset in octal)."

 For anyone that has an interest in RSX11D V4, I include below the PDP11.INI and RSX11DV4PAT.DSK, with the above desribed patch.

rsx11dv4pat.dsk

pdp11.ini

  Using them, here's what the boot looks like now

C:\simh40\PDP11\rsx11d\rsx11dv4>pdp11

PDP-11 simulator V4.0-0 Current        git commit id: ab3e07a4
Disabling XQ

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>

  Of some interest, but not related to the boot problem, he pointed out a few curious things in the file structure of the disk. One was that there are files that weren't completely deleted - their checksums weren't deleted as they should be. As well, there are a number of files with really crazy looking update dates - here's a couple of examples.

RUN.TSK;1           (111,2420)      9./9.         C  01-APR-74 22:38  [1,5]    [RWED,RWED,RWE,R] 
32-SEP-73 00:01(9.)

INI.TSK;1           (112,2421)      17./17.       C  01-APR-74 22:38  [1,5]    [RWED,RWED,RWE,R] 
32-SEP-73 00:00(9.)

 I'm guessing these are results of Files-11 bugs from long ago.




Monday, August 21, 2023

Installing software on Microvax and MicroPDP11 systems - update

   Recently, Hans-Ulrich Hölscher did some experimenting with the programs I wrote that allow copying a disk image from any VMS or RSX system to a MicroVAX I or PDP11, that has no software already loaded, via ethernet (see several blog posts, with VAXstation I" and "install" in their titles).

  I was surprised when he reported a several things I hadn't realized about those utilities. I had assumed that they wouldn't run on SIMH systems, or on MicroVAX IIs, due to differences in their internal architecture from the MicroVAX Is and real PDP11s I wrote and tested them on. Ulli pointed out that they actually worked on SIMH instances of MicroVAX Is, and as well on SIMH images of MicroVAX IIs, and, very likely, real instances of MicroVAX IIs.

  As well, he reported that DELQA ethenret cards work as well as DEQNAs.

  I checked it out and his reports were correct. I reckon...1 - that the architectural features I used to make this work with MIcroVAX/VAXstation 1s were also present on the MicroVAX/VAXstation II, and...2 - SIMH MicroVAX I and II emulators also include all of those features. Bravo, SIMH developers!

  OK, so he reported that they worked, and indeed produced a good disk copy, but they emitted a zillion error messages when run with an emulated system as the target. A little study showed what that problem was - I had used timing loops extensively in the downloaded code, and SIMH and real MicroVAX IIs run a whole heckuva lot faster than the real MIcroVAX I hardware does - so things were timing out and retrying a lot more than they needed to.

  Another dive into the MicroVAX architecture documents produced a solution - there is an Interval Timer included in the MIcroVAX architecture. If enabled, it will produce an interrupt every .01 seconds. This will allow me to produce a delay of fixed time, regardless of how fast the machine or simualtor it is running on.

  The clock interrupt is controlled by the ICCS (Interval Clock Consoltr/Status) register, internal register #^X18. When bit 6 is set in it, it will produce an interrupt via the vector at SCB offset ^XC0 every 1/100 of a second. When bit 6 is clear, the clock interrupts are turned off.

  So, setup the vector for the clock interrupt.

        mfpr    #^X11,r7        ;move scb addr to r7
        moval   tick,^XC0(r7)   ;point vector C0 at routine "tick".

  Here's the interrupt routine. Not much to it, nicht wahr?

tick:   incl    clock
        rei

  Then, whenver I wanted to delay for some fixed amount of time, regardless of processor speed, I enable the clock interrupt, clear the clock variable, and wait until the variable "clock" reached the number of 1/100ths of a second I needed.
 
 A macro is used to invoke it.

;+
; Wait for specified number of .01 seconds ticks
;-
        .macro  waitm   beat
        pushl   beat
        calls   #1,waitm
        .endm   waitm

  Here's the routine the macro invokes..

;+
; Wait for a specified number of "ticks"
;-
        .entry  waitm,^m<r2>
        movl    4(ap),r2        ;# of ticks needed to r2
        clrl    clock           ;start fresh
        mtpr    #64,#^X18       ;Enable timer interrupts 
1$:     cmpl    r2,clock        ;had enough?
        bgequ   1$              ;please sir, I want some more
        mtpr    #0,#^X18        ;turn off the interupts when done
        ret

  On the plus side, it was simple and easy to write. On the negative, it will totally not be of any use if I ever start using multiple streams of execution. As is, It has to be used with caution if used in an interrupt routine, since that has the potential to step on the use of it in the non-interrrupt code. For now I elect to just be mindful of that when coding. Sketchy as hell, but, in this no-OS environment, what isn't?

  As well as taking care of the timing loop issues, these new versions address a deficiency that Ulli pointed out - the disk unit targeted had to be assembled into the program. He pointed out that being able to enter what unit to target would be a lot more flexible, and less prone to writing on the wrong disk by mistake. In support of that, he figured out how to get input from the console, and provided examples to demonstrate how to specify the unit number to target at run time. Thanks again, Ulli!. I also added the ability to specify what file to load at run time as well.

  Here's new versions of remotewrite.mar,localwrite.mar, localread.mar, remoteread.mar and sendcheck.mar. Note that the packet format changed, so that the older versions of these programs won't work with the newver versions - new remotewrite won't work with old localwrite, and so forth. New versions of the PDP11 programs are coming soon.

      *** New versions loaded 1-SEP-2023 ***