Success! After considering some possible options, I decided that it was unlikely the LS logic had gone bad even though there were potentially 8 bad memory chips. Those transceiver and D latches are practically indestructible in my experience. I instead decided to trace the board to identify which chips in the two columns of memory were associated with the bad bits. I made the attached diagram of the memory, buffers and latches. The Rosetta stone was the Ethernet controller, where I could trace a labelled address/data line to a memory chip. It turns out the outer memory column is D8 to D15 (top to bottom) and the inner column is D0 to D7 (top to bottom). I then desoldered and replaced one memory chip to confirm the expected bit was responsive. To avoid desoldering in the future, I inserted chip sockets hoping that would not alter the bus characteristics. With all 8 chips replaced, the card passed the boot-up check and successfully passed the maintenance disk check.
It also passed by memory program check. But as I started to expand my memory check beyond the first 512 words, I encountered problems with the PARs unrelated to the hardware and I really started to question how to properly write a macro 11 program to reach memory at a specific physical location. All my testing suggests that if the program directly changes PAR values without informing the OS, any change in task, for instance, caused by an interrupt or system call, risks the OS restoring the PARs to the values it knows, leaving your program reaching the wrong memory space when back in context. For instance, I started writing my program in the following manner:
Reset and program memory register on DECNET card
Set PAR and PDR values
Set base virtual address corresponding to the APR
Set loop counter
Write memory
Read memory and increment base virtual address
Compare read and write values, branch on mismatch
Decrement counter and loop to write next memory address
I found this works when the loop counter was about 1000 (512.) or less. When I tried 3000, it triggered a trap with the register set display showing it aborted about 1700. No matter which APR I tried, I could not get past this value to reach the remainder of the virtual address window and the value itself was not constant, but near 1700. I had previously confirmed that a call to system macro would change my PAR. I then rewrote my loop to disable interrupts, figuring an ISR or the restoration was changing my PAR. Although I could get away with a 1000 loop, anything longer would get caught in an interrupt. The code then became:
Reset and program memory register on DECNET card
Set base virtual address corresponding to the APR
Set loop counter
Disable interrupts
Set PAR and PDR values
Write memory
Read memory and increment base virtual address
Re-enable interrupts
Compare read and write values, branch on mismatch
Decrement counter and loop to set PAR/PDR again and write next memory address
This worked and I was able to loop through the full 8KB of virtual address space. But in disabling all interrupts, including the clock, I lost my blinking cursor. The system remained stable, but doubts linger about possibly overwriting memory. If I disabled/enabled interrupts, but did not include setting the PAR/PDR in the loop, it would trap again. One thing that seems to be clear is that if you don't inform the OS/memory management unit that you are reserving a PAR, it is going to restore it to the value it understands to be correct upon any task change. We encountered something similar in another VCF thread on PRO video with RT-11. Again, we are disabling and enabling interrupts with direct PAR access. Nowhere in the macro programming training manuals do they discuss directly setting PARs. They instead describe a group of CRAW, CRRG, and other macros to formally request a memory block, create a region, create a virtual window, and map the window to the region through an APR. But these macros let the memory management unit select the physical memory and of course set the PAR. But we want to specify a specific region of physical memory. How do you inform the OS/memory management unit that you want to assign a specific part of physical memory to a region and window so that it will set the proper PAR and not mess with it when interrupts and other things occur? The POS Driver manual talks about a $STPAR call to add option card memory to the system and how to install a driver into the system, but I haven't found a way to specify a block of physical memory without directly setting a PAR. Should I be running in kernel/system mode? Would that let my PARs stick?