• Please review our updated Terms and Rules here

UQSSP

cbscpe

Experienced Member
Joined
Apr 11, 2017
Messages
369
Location
Switzerland
I'm still in the process of reading and understanding the RQDX3 source code posted by Al but think I now understood most of it and I'm currently in the process of translating the source code into code for the microcontroller I have selected for my own MSCP controller. However there was one thing I'm not familiar with at all because which relates to the micro VAX. Not very important as I don't think I will have to translate this part as well but still I'm curious what it is and how it works.

In the module UQSSP.MAC of the source code there is a function call "map.buffer" with the following comment

;
; this routine maps a virtual Q-bus address into a physical Q-bus address
; (this is only needed when the host is a microVAX I) -- we need the address
; of the current PKT to fetch the address of the map register table
;
; the UQSSP specification describes this in detail
;

does anyone know what this UQSSP specifications is and where it is described?

Peter
 

cbscpe

Experienced Member
Joined
Apr 11, 2017
Messages
369
Location
Switzerland
Yes, so far so good, but I would like to have the specifications themselves. In other words the bits and bytes and how they work together.
 

vaxorcist

Experienced Member
Joined
Apr 26, 2012
Messages
59
Location
Germany
I think you will need to implement this part only if you want to support the (rare) MicroVAX I:

=> ; (this is only needed when the host is a MicroVAX I)

This (to cover the rare MicroVAX I) would be really nice (I've got one ;-)), but is it really worth the effort?

Ulli
 

cruff

Experienced Member
Joined
Dec 12, 2012
Messages
345
Location
Colorado
Is this just Appendix D Buffer Descriptor Formats of Mass_Storage_Control_Protocol_Ver_2.4.0_Jun92.txt? I haven't looked closely at either the doc or the uqsspm.mac code, but a mapped buffer has bit 31 of the first 32-bit word set.
 

cruff

Experienced Member
Joined
Dec 12, 2012
Messages
345
Location
Colorado
My guess is that map.buffer is reading the Microvax's memory mapping page table entries and interpreting them to determine the correct address for the physical Qbus transfer.
 

Bitly

Experienced Member
Joined
Sep 1, 2016
Messages
86
Location
Westminster, Colorado
I think you will need to implement this part only if you want to support the (rare) MicroVAX I:

=> ; (this is only needed when the host is a MicroVAX I)

This (to cover the rare MicroVAX I) would be really nice (I've got one ;-)), but is it really worth the effort?

Ulli

My question (concern?) would be, does this source code pre-date the Microvax II, and does the Microvax II also require similiar manipulations? They wouldn't mention a computer that didn't exist in the comments......

Edit: You might find the information you need in the UDA50 programmers kit, referenced here:
http://ana-3.lcs.mit.edu/~jnc/cctalk/2004-February/1510.html

CW
 
Last edited:

gslick

Veteran Member
Joined
Dec 30, 2010
Messages
2,112
Location
Seattle, WA
My question (concern?) would be, does this source code pre-date the Microvax II, and does the Microvax II also require similiar manipulations? They wouldn't mention a computer that didn't exist in the comments......

The RQDX3 was developed at the same time as the MicroVAX II.
Digital Technical Journal, March 1986, is all about the MicroVAX II, and includes a section on the RQDX3 development project.

One of the differences between the original KA610 (KD32) MicroVAX I, and the KA630 MicroVAX II and all subsequent Q22 bus VAX is that the KA610 physical memory space is directly mapped in Q22 address space, while on the KA630 and later Q22 bus CPUs the CPU physical memory address space is mapped into the Q22 address space through Q22 bus map registers.

There are 8192 map registers, one for every 512-byte page of Q22 bus address space, forming a direct mapped translation table of Q22 bus addresses to CPU local memory physical addresses. Each 512-byte page of Q22 bus address space can be mapped to any 512-byte page in CPU local physical memory.

KA630-A Processor Specification, Rev. 3.4 Date: 26-Apr-85
Section 9.3 Mapping Registers

KA680 CPU Module Technical Manual, EK-KA680-TM-001
9.1 Q22–bus to Main Memory Address Translation

The Q22 bus map registers can be used as a scatter/gather translation mechanism so that transfer buffers that are not contiguous in CPU local memory physical address space can be be dynamically mapped as needed into a contiguous region in Q22 bus address space. When that is done, a controller such as the RQDX3 can use a contiguous Q22 address space DMA transfer buffer address provided by the driver and OS and not need to know or care how that is mapped into CPU local memory space.

VMS Device Support, AA-LA88A-TE
Chapter 12, UNIBUS and Q22 Bus Device Support
12.2.8 Considerations for MicroVAX I DMA Devices
 

gslick

Veteran Member
Joined
Dec 30, 2010
Messages
2,112
Location
Seattle, WA
Is this just Appendix D Buffer Descriptor Formats of Mass_Storage_Control_Protocol_Ver_2.4.0_Jun92.txt? I haven't looked closely at either the doc or the uqsspm.mac code, but a mapped buffer has bit 31 of the first 32-bit word set.

Unfortunately this also refers to the "Storage Systems Port Specification (SSP)" for further details, which no one here has yet been able to find.


Code:
           Digital Equipment Corporation        Confidential And Proprietary
           Mass Storage Control Protocol                       Version 2.4.0
           BUFFER DESCRIPTOR FORMATS                                Page D-2
                                                                11 June 1992

     9     There are two buffer descriptor formats used with the UNIBUS  and
    10     QBUS  in  order  to  accommodate  two different transfer methods:
    11     unmapped and mapped.

    12     The format for unmapped transfers is as follows:

    13                     31                             0
    14                     +-+-----+-----------------------+
    15                     |0| chan|buffer physical address|
    16                     +-+-----+-----------------------+
    17                     |           reserved            |
    18                     +-------------------------------+
    19                     |           reserved            |
    20                     +-------------------------------+

    21     The format for mapped transfers is as follows:

    22                     31                    9 8      0
    23                     +-+-----+-----------------------+
    24                     |1| map register index | offset |
    25                     +-+-----+-----------------------+
    26                     |mbz|    map register base      |
    27                     +-------------------------------+
    28                     |           reserved            |
    29                     +-------------------------------+

    30     The following interpretation shows  that  the  unmapped  transfer
    31     format  is  consistent with the generic buffer descriptor format.
    32     The  UNIBUS  and  QBUS  are  inherently   single   host   busses.
    33     Furthermore,  all  anticipated  controllers for these busses only
    34     support a single device class.  Therefore there  can  only  be  a
    35     single  connection  between the host and any controller.  Thus it
    36     is reasonable to assign a fixed connection  identifier  of  zero.
    37     Secondly,  since these busses are not used with any (bus visible)
    38     form of virtual memory, there is no use  for  the  concept  of  a
    39     logical  buffer  name.   Thus  it is reasonable to assign a fixed
    40     buffer name of zero, denoting the entire address space  available
    41     on  the  bus.   This  leaves  the offset field to denote the byte
    42     offset from address zero, or merely the starting address  of  the
    43     buffer.  In order to accommodate VAX-11/780 UBAs, it is necessary

     1     to include the UBA channel number so that controllers can request
     2     UBA  purges.   This  has  been  placed  with  the bus address for
     3     controller convenience.

     4     On the other hand the mapped transfer format, with the  exception
     5     of the fixed connection identifier of zero, deviates totally from
     6     the generic buffer descriptor format.  See  the  Storage  Systems
     7     Port   Specification   (SSP)   for  complete  details  on  mapped
     8     transfers.
 

cbscpe

Experienced Member
Joined
Apr 11, 2017
Messages
369
Location
Switzerland
It seems that this mapping is really only needed by the microVAX I which maps Q22 directly to memory. Reading through the posts and documents later microVAX with Q-Bus provided the translation via mapping register and therefore would present to the controller a contiguous buffer for data transfer.

For now I will not bother to write an equivalent to map.buffer. On the other side the function only consists of 71 PDP-11 assembler instructions. So it should be possible to reverse engineer its function. But before this happens there is still lot of work to be done for my MSCP controller.
 

gslick

Veteran Member
Joined
Dec 30, 2010
Messages
2,112
Location
Seattle, WA
One other source of information, which may or may not be helpful, is the SIMH MSCP emulation code. Looks like that is code that is common to both the PDP-11 and VAX emulator builds, but the mapped transfer handling code paths are only conditionally built into the VAX emulator builds.

https://github.com/simh/simh/blob/master/PDP11/pdp11_rq.c

relevant code snippets:

Code:
#define RQ_MAPXFER      (1u << 31)                      /* mapped xfer */


/* Map buffer address */

uint32 rq_map_ba (uint32 ba, uint32 ma)
{
#if defined (VM_VAX)                                    /* VAX version */
int32 idx;
uint32 rg;

idx = (VA_GETVPN(ba) << 2);                            /* map register index */
rg = ReadL (ma + idx);                                 /* map register */
if (rg & PTE_V)                                        /* valid? */
    return ((rg & RQ_M_PFN) << VA_N_OFF) | (ba & VA_M_OFF);
#endif
return 0;
}

/* Read byte buffer from memory */

int32 rq_readb (uint32 ba, int32 bc, uint32 ma, uint8 *buf)
{
#if defined (VM_VAX)                                    /* VAX version */
int32 lbc, t, tbc = 0;
uint32 pba;

if (ba & RQ_MAPXFER) {                                  /* mapped xfer? */
    while (tbc < bc) {
        if (!(pba = rq_map_ba (ba, ma)))                /* get physical ba */
            return (bc - tbc);
        lbc = 0x200 - (ba & VA_M_OFF);                  /* bc for this tx */
        if (lbc > (bc - tbc)) lbc = (bc - tbc);
        t = Map_ReadB (pba, lbc, buf);
        tbc += (lbc - t);                               /* bytes xfer'd so far */
        if (t) return (bc - tbc);                       /* incomplete xfer? */
        ba += lbc;
        buf += lbc;
        }
    return 0;
    }
#endif
return Map_ReadB (ba, bc, buf);                         /* unmapped xfer */
}

/* Read word buffer from memory */

int32 rq_readw (uint32 ba, int32 bc, uint32 ma, uint16 *buf)
{
#if defined (VM_VAX)                                    /* VAX version */
int32 lbc, t, tbc = 0;
uint32 pba;

if (ba & RQ_MAPXFER) {                                  /* mapped xfer? */
    while (tbc < bc) {
        if (!(pba = rq_map_ba (ba, ma)))                /* get physical ba */
            return (bc - tbc);
        lbc = 0x200 - (ba & VA_M_OFF);                  /* bc for this tx */
        if (lbc > (bc - tbc)) lbc = (bc - tbc);
        t = Map_ReadW (pba, lbc, buf);
        tbc += (lbc - t);                               /* bytes xfer'd so far */
        if (t) return (bc - tbc);                       /* incomplete xfer? */
        ba += lbc;
        buf += (lbc >> 1);
        }
    return 0;
    }
#endif
return Map_ReadW (ba, bc, buf);                         /* unmapped xfer */
}

/* Write word buffer to memory */

int32 rq_writew (uint32 ba, int32 bc, uint32 ma, uint16 *buf)
{
#if defined (VM_VAX)                                    /* VAX version */
int32 lbc, t, tbc = 0;
uint32 pba;

if (ba & RQ_MAPXFER) {                                  /* mapped xfer? */
    while (tbc < bc) {
        if (!(pba = rq_map_ba (ba, ma)))                /* get physical ba */
            return (bc - tbc);
        lbc = 0x200 - (ba & VA_M_OFF);                  /* bc for this tx */
        if (lbc > (bc - tbc)) lbc = (bc - tbc);
        t = Map_WriteW (pba, lbc, buf);
        tbc += (lbc - t);                               /* bytes xfer'd so far */
        if (t) return (bc - tbc);                       /* incomplete xfer? */
        ba += lbc;
        buf += (lbc >> 1);
        }
    return 0;
    }
#endif
return Map_WriteW (ba, bc, buf);                        /* unmapped xfer */
}
 
Top