10.02_devices/2_src/rx211.cpp
// Access to QBUS/UNIBUS register interface
// called with 100% CPU highest RT priority.
// QBUS/UNIBUS is stopped by SSYN/RPLY while this is running.
// No loops! no drive, console, file or other operations!
// QBUS/UNIBUS DATO cycles let dati_flipflops "flicker" outside of this proc:
//      do not read back dati_flipflops.
Access to QBUS/UNIBUS register interface
called with 100% CPU highest RT priority.
QBUS/UNIBUS is stopped by SSYN/RPLY while this is running.
No loops. no drive, console, file or other operations.
QBUS/UNIBUS DATO cycles let dati_flipflops "flicker" outside of this proc:
do not read back dati_flipflops.
Access to QBUS / UNIBUS register interface called with 100% CPU highest RT priority . QBUS / UNIBUS is stopped by SSYN / RPLY while this is running . No loops . no drive console file or other operations . QBUS / UNIBUS DATO cycles let dati_flipflops " flicker " outside of this proc : do not read back dati_flipflops .
void RX211_c::on_after_register_access(qunibusdevice_register_t *device_reg,
                                       uint8_t qunibus_control) {
    switch (device_reg->index) {
    case 0:  
        if (qunibus_control == QUNIBUS_CYCLE_DATO) {
            uint16_t w = busreg_RX2CS->active_dato_flipflops ;
            pthread_mutex_lock(&on_after_register_access_mutex);
            uCPU->signal_selected_drive_unitno = !!(w & BIT(4));
            function_select = uCPU->signal_function_code = (w >> 1) & 0x07;
            function_density = uCPU->signal_function_density = !!(w & BIT(8));
            interrupt_enable = !!(w & BIT(6));
            extended_address = (w >> 12) & 3;
            csr09_10 = (w >> 10) & 3;
            uCPU->rxdb = w & 0366; 
            if (w & BIT(14)) { 
                uCPU->init() ;
            } else if (uCPU->signal_done && (w & BIT(0))) { 
                if (function_select == RX11_CMD_EMPTY_BUFFER
                        || function_select == RX11_CMD_FILL_BUFFER
                        || function_select == RX11_CMD_READ_ERROR_CODE) {
                    done = false ; 
                    error_dma_nxm = false ;
                    if (function_select == RX11_CMD_READ_ERROR_CODE) {
                        dma_function_word_count = 4 ; 
                        state = state_wait_rx2ba ; 
                    } else
                        state = state_wait_rx2wc ;
                    update_status("on_after_register_access() -> update_status") ;  may trigger interrupt
                } else
                    uCPU->go() ;  execute uCPU.function_code
            } else
                 register status NOT updated via uCPU activity
                update_status("on_after_register_access() -> update_status") ;  may trigger interrupt
            pthread_mutex_unlock(&on_after_register_access_mutex);
        } else {
             CS reg is not "active_on_dati"
              set value in code with "set_register_dati_value(reg_CS, CS_read) ;"
        }
        break;
    case 1:   AFTER access to RXDB, multifunction
         read from data port to RXDB
        if (qunibus_control == QUNIBUS_CYCLE_DATI) {
             read moves next byte to rxdb
            uCPU->rxdb_after_read() ;
             has read current value of rxdb, now deliver next via
             on_uCPU_status_changed() to rxdb, calling
        } else if (qunibus_control == QUNIBUS_CYCLE_DATO) {
             write RXDB to data port
            uint16_t w  = get_register_dato_value(busreg_RX2DB);
            switch(state) {
            case state_base:
                uCPU->rxdb_after_write(w) ;  forward to uCPU, alls update_status()
                break ;
            case state_wait_rx2wc:
                dma_function_word_count = uCPU->extended_status[1] = rx2wc = w & 0xff ;  save word count
                 in worker() test against uCPU transfer size
                state = state_wait_rx2ba ;
				update_status("on_after_register_access() state_wait_rx2ba -> update_status") ;  may trigger interrupt
                break ;
            case state_wait_rx2ba:
                rx2ba = w ;  save bus address
                state = state_dma_busy ;
				update_status("on_after_register_access() state_dma_busy -> update_status") ;  may trigger interrupt
                 wake up worker()
                 do DMA! with dma_buffer and dma_cycle DATI/DATO
                pthread_cond_signal(&on_after_register_access_cond);
                break ;
            case state_dma_busy:
            default:
                assert(false);  Show me stray write to RX2DB
            }
        }
    default: ;  ignore write
    }
}
void RX211_c :: on_after_register_access ( qunibusdevice_register_t * device_reg , uint8_t qunibus_control ) { switch ( device_reg -> index ) { case 0 : if ( qunibus_control == QUNIBUS_CYCLE_DATO ) { uint16_t w = busreg_RX2CS -> active_dato_flipflops ; pthread_mutex_lock ( & on_after_register_access_mutex ) ; uCPU -> signal_selected_drive_unitno = ! ! ( w & BIT ( 4 ) ) ; function_select = uCPU -> signal_function_code = ( w >> 1 ) & 0x07 ; function_density = uCPU -> signal_function_density = ! ! ( w & BIT ( 8 ) ) ; interrupt_enable = ! ! ( w & BIT ( 6 ) ) ; extended_address = ( w >> 12 ) & 3 ; csr09_10 = ( w >> 10 ) & 3 ; uCPU -> rxdb = w & 0366 ; if ( w & BIT ( 14 ) ) { uCPU -> init ( ) ; } else if ( uCPU -> signal_done && ( w & BIT ( 0 ) ) ) { if ( function_select == RX11_CMD_EMPTY_BUFFER || function_select == RX11_CMD_FILL_BUFFER || function_select == RX11_CMD_READ_ERROR_CODE ) { done = false ; error_dma_nxm = false ; if ( function_select == RX11_CMD_READ_ERROR_CODE ) { dma_function_word_count = 4 ; state = state_wait_rx2ba ; } else state = state_wait_rx2wc ; update_status ( " " ) ; } else uCPU -> go ( ) ; } else update_status ( " " ) ; pthread_mutex_unlock ( & on_after_register_access_mutex ) ; } else { } break ; case 1 : if ( qunibus_control == QUNIBUS_CYCLE_DATI ) { uCPU -> rxdb_after_read ( ) ; } else if ( qunibus_control == QUNIBUS_CYCLE_DATO ) { uint16_t w = get_register_dato_value ( busreg_RX2DB ) ; switch ( state ) { case state_base : uCPU -> rxdb_after_write ( w ) ; break ; case state_wait_rx2wc : dma_function_word_count = uCPU -> extended_status [ 1 ] = rx2wc = w & 0xff ; state = state_wait_rx2ba ; update_status ( " " ) ; break ; case state_wait_rx2ba : rx2ba = w ; state = state_dma_busy ; update_status ( " " ) ; pthread_cond_signal ( & on_after_register_access_cond ) ; break ; case state_dma_busy : default : assert ( false ) ; } } default : ; } }
Access to QBUS/UNIBUS register interface
called with 100% CPU highest RT priority.
Access to QBUS / UNIBUS register interface called with 100% CPU highest RT priority .
// on drive select: // move  status of new drive to controller status register // on command: signal worker thread // RXCS //GPIO_SETVAL(gpios.led[0], 1); // inverted, led OFF // Not clear, which bits may be written when DONE=0 (busy) // "go" disabled // RX11 DX.MAC: sets INT enable while INIT active // INIT interrupts GO ? // But: Changes of Unit select" while CPU active??" // write only allowed if RX02 is not busy // if (! uCPU->signal_done) //    break; // ignore write // CS<4> = drive select, write only, forwad to uCPU // CS<1:3> is cmd, write only // CS<8> determines the desnity of the function to be executed // CS<6> is IE // CS<13:12> is bus address <17:16> // "future use", but must be read back // ZRXFB0, test13: write to lower byte of RXCS maps to RXDB? // only some bits map ? // visible on update_status() // INIT bit // GO bit // multistep Buffer DMA: RX211 operates uCPU via RXDB and does QUNIBUS DMA // first BA and WC are received via RXDB, then uCPU&DMA started in background worker(). // inhibit interrupts // very special: not touched and not transferred before BA // previous WC value should be returned by extended status // DO NOT TOUCH wc, only address to transfer // // may trigger interrupt // execute uCPU.function_code // register status NOT updated via uCPU activity // may trigger interrupt // CS reg is not "active_on_dati" //  set value in code with "set_register_dati_value(reg_CS, CS_read) ;" // AFTER access to RXDB, multifunction // read from data port to RXDB // read moves next byte to rxdb // has read current value of rxdb, now deliver next via // on_uCPU_status_changed() to rxdb, calling // write RXDB to data port // forward to uCPU, alls update_status() // save word count // in worker() test against uCPU transfer size // may trigger interrupt // save bus address // may trigger interrupt // wake up worker() // do DMA! with dma_buffer and dma_cycle DATI/DATO // Show me stray write to RX2DB // ignore write