10.02_devices/2_src/uda.cpp
//
// on_after_register_access():
//  Handles register accesses for the IP and SA registers.
//
Handles register accesses for the IP and SA registers.
Handles register accesses for the IP and SA registers .
void
uda_c::on_after_register_access(
    qunibusdevice_register_t *device_reg,
    uint8_t unibus_control
)
{
    switch (device_reg->index)
    {
        case 0:  
            if (QUNIBUS_CYCLE_DATO == unibus_control)
            {
                DEBUG("Reset due to IP read"); 
                update_SA(0x0); 
                StateTransition(InitializationStep::Uninitialized);
            }
            else
            {
                if (_initStep == InitializationStep::Complete)
                {
                    DEBUG("Request to start polling.");
                    _server->InitPolling();
                }
            }
            break;
        case 1:  
            uint16_t value = SA_reg->active_dato_flipflops;
            switch (_initStep)
            {
                case InitializationStep::Uninitialized:
                    DEBUG("Write to SA in Uninitialized state.");
                case InitializationStep::Step1:
                     c rng lng is the number of slots (32 bits each)
                      in the command ring, expressed as a power of two.
                     r rng lng is as above, but for the response ring.
                     IE=1 means the host is requesting an interrupt
                     at the end of the completion of init steps 1-3.
                     int vector determines if interrupts will be generated
                     by the port.  If this field is non-zero, interupts will
                     be generated during normal operation and, if IE=1,
                     during initialization.
                    _step1Value = value;
                    _interruptVector = ((value & 0x7f) << 2);
                    intr_request.set_vector(_interruptVector);
                    _interruptEnable = !!(value & 0x80);
                    _responseRingLength = (1 << ((value & 0x700) >> 8));
                    _commandRingLength = (1 << ((value & 0x3800) >> 11));
                    DEBUG("Step1: 0x%x", value); 
                    DEBUG("resp ring 0x%x", _responseRingLength);
                    DEBUG("cmd ring 0x%x", _commandRingLength);
                    DEBUG("vector 0x%x", _interruptVector);
                    DEBUG("ie %d", _interruptEnable);
                     Move to step 2.
                    StateTransition(InitializationStep::Step2);
                    break;
                case InitializationStep::Step2:
                      15                          1 0 
                     +-----------------------------+-+ 
                     |        ringbase low         |P| 
                     |         (address)           |I|
                     +-----------------------------+-+ 
                     ringbase low is the low-order portion of word
                     [ringbase+0] of the communications area.  This is a
                     16-bit byte address whose low-order bit is zero implicitly.
                    _ringBase = value & 0xfffe;
                    _purgeInterruptEnable = !!(value & 0x1);
                    DEBUG("Step2: rb 0x%x pi %d", _ringBase, _purgeInterruptEnable);
                     Move to step 3 and interrupt as necessary.
                    StateTransition(InitializationStep::Step3);
                    break;
                case InitializationStep::Step3:
                     15                              0
                     +-+-----------------------------+ 
                     |P|        ringbase hi          |
                     |P|         (address)           | 
                     +-+-----------------------------+
                     PP = 1 means the host is requesting execution of
                     purge and poll tests, which we ignore because we can.
                     ringbase hi is the high-order portion of the address
                     [ringbase+0].
                    _ringBase |= ((value & 0x7fff) << 16);
                    DEBUG("Step3: ringbase 0x%x", _ringBase);
                     Move to step 4 and interrupt as necessary.
                    StateTransition(InitializationStep::Step4);
                    break;
                case InitializationStep::Step4:
                     15             8 7           1 0 
                     +---------------+-----------+-+-+ 
                     |    reserved   |    burst  |L|G| 
                     |               |           |F|O| 
                     +---------------+-----------+-+-+ 
                     Burst is one less than the max. number of longwords
                     the host is willing to allow per DMA transfer.
                     If zero, the port uses its default burst count.
                     LF=1 means that the host wants a "last fail" response
                     packet when initialization is complete.
                     GO=1 means that the controller should enter its functional
                     microcode as soon as initialization completes.
                     Note that if GO=0 when initialization completes, the port
                     will continue to read SA until the host forces SA bit 0 to
                     make the transition 0->1.
                     There is no explicit interrupt at the end of Step 4.
                     TODO: For now we ignore burst settings.
                     We also ignore Last Fail report requests since we aren't
                     supporting onboard diagnostics and there's nothing to
                     report.
                    DEBUG("Step4: 0x%x", value);
                    if (value & 0x1)
                    {
                         GO is set, move to the Complete state.  The worker will
                         start the controller running.
                        StateTransition(InitializationStep::Complete);
                         The VMS bootstrap expects SA to be zero IMMEDIATELY
                         after completion. 
                        update_SA(0x0);
                    }
                    else
                    {
                         GO unset, wait until it is.
                    }
                    break;
                case InitializationStep::Complete:
                     "When zeroed by the host during both initialization and normal
                      operation, it signals the port that the host has successfully
                      completed a bus adapter purge in response to a port-initiated
                      purge request.
                      We don't deal with bus adapter purges, yet.
                    break;
            }
            break;
    }
}
void uda_c :: on_after_register_access ( qunibusdevice_register_t * device_reg , uint8_t unibus_control ) { switch ( device_reg -> index ) { case 0 : if ( QUNIBUS_CYCLE_DATO == unibus_control ) { DEBUG ( " " ) ; update_SA ( 0x0 ) ; StateTransition ( InitializationStep :: Uninitialized ) ; } else { if ( _initStep == InitializationStep :: Complete ) { DEBUG ( " " ) ; _server -> InitPolling ( ) ; } } break ; case 1 : uint16_t value = SA_reg -> active_dato_flipflops ; switch ( _initStep ) { case InitializationStep :: Uninitialized : DEBUG ( " " ) ; case InitializationStep :: Step1 : _step1Value = value ; _interruptVector = ( ( value & 0x7f ) << 2 ) ; intr_request . set_vector ( _interruptVector ) ; _interruptEnable = ! ! ( value & 0x80 ) ; _responseRingLength = ( 1 << ( ( value & 0x700 ) >> 8 ) ) ; _commandRingLength = ( 1 << ( ( value & 0x3800 ) >> 11 ) ) ; DEBUG ( " " , value ) ; DEBUG ( " " , _responseRingLength ) ; DEBUG ( " " , _commandRingLength ) ; DEBUG ( " " , _interruptVector ) ; DEBUG ( " " , _interruptEnable ) ; StateTransition ( InitializationStep :: Step2 ) ; break ; case InitializationStep :: Step2 : _ringBase = value & 0xfffe ; _purgeInterruptEnable = ! ! ( value & 0x1 ) ; DEBUG ( " " , _ringBase , _purgeInterruptEnable ) ; StateTransition ( InitializationStep :: Step3 ) ; break ; case InitializationStep :: Step3 : _ringBase |= ( ( value & 0x7fff ) << 16 ) ; DEBUG ( " " , _ringBase ) ; StateTransition ( InitializationStep :: Step4 ) ; break ; case InitializationStep :: Step4 : DEBUG ( " " , value ) ; if ( value & 0x1 ) { StateTransition ( InitializationStep :: Complete ) ; update_SA ( 0x0 ) ; } else { } break ; case InitializationStep :: Complete : break ; } break ; } }
on_after_register_access():
Handles register accesses for the IP and SA registers.
on_after_register_access () : Handles register accesses for the IP and SA registers .
// IP - read / write // "When written with any value, it causes a hard initialization //  of the port and the device controller." // "When read while the port is operating, it causes the controller //  to initiate polling..." // SA - write only // Should not occur, we treat it like step1 here. // Host writes the following: // 15   13 11 10  8 7 6           0 // +-+-+-----+-----+-+-------------+ // |1|W|c rng|r rng|I| int vector  | // | |R| lng | lng |E|(address / 4)| // +-+-+-----+-----+-+-------------+ // WR = 1 tells the port to enter diagnostic wrap // mode (which we ignore). // // c rng lng is the number of slots (32 bits each) //  in the command ring, expressed as a power of two. // // r rng lng is as above, but for the response ring. //  // IE=1 means the host is requesting an interrupt // at the end of the completion of init steps 1-3. // // int vector determines if interrupts will be generated // by the port.  If this field is non-zero, interupts will // be generated during normal operation and, if IE=1, // during initialization. // Move to step 2. // Host writes the following: //  15                          1 0  // +-----------------------------+-+  // |        ringbase low         |P|  // |         (address)           |I| // +-----------------------------+-+  // ringbase low is the low-order portion of word // [ringbase+0] of the communications area.  This is a // 16-bit byte address whose low-order bit is zero implicitly. // // Move to step 3 and interrupt as necessary. // Host writes the following: // 15                              0 // +-+-----------------------------+  // |P|        ringbase hi          | // |P|         (address)           |  // +-+-----------------------------+ // PP = 1 means the host is requesting execution of // purge and poll tests, which we ignore because we can. // // ringbase hi is the high-order portion of the address // [ringbase+0]. // Move to step 4 and interrupt as necessary. // Host writes the following: // 15             8 7           1 0  // +---------------+-----------+-+-+  // |    reserved   |    burst  |L|G|  // |               |           |F|O|  // +---------------+-----------+-+-+  // Burst is one less than the max. number of longwords // the host is willing to allow per DMA transfer. // If zero, the port uses its default burst count. // // LF=1 means that the host wants a "last fail" response // packet when initialization is complete. // // GO=1 means that the controller should enter its functional // microcode as soon as initialization completes. //  // Note that if GO=0 when initialization completes, the port // will continue to read SA until the host forces SA bit 0 to // make the transition 0->1. // // There is no explicit interrupt at the end of Step 4. // // TODO: For now we ignore burst settings. // We also ignore Last Fail report requests since we aren't // supporting onboard diagnostics and there's nothing to // report. // // // GO is set, move to the Complete state.  The worker will // start the controller running. // // The VMS bootstrap expects SA to be zero IMMEDIATELY // after completion.  // GO unset, wait until it is. // "When zeroed by the host during both initialization and normal //  operation, it signals the port that the host has successfully //  completed a bus adapter purge in response to a port-initiated //  purge request. //  We don't deal with bus adapter purges, yet.