diff --git a/10.01_base/2_src/arm/priorityrequest.cpp b/10.01_base/2_src/arm/priorityrequest.cpp index 309645f..d239ab8 100644 --- a/10.01_base/2_src/arm/priorityrequest.cpp +++ b/10.01_base/2_src/arm/priorityrequest.cpp @@ -37,7 +37,7 @@ priority_request_c::priority_request_c(unibusdevice_c *device) { this->executing_on_PRU = false; this->slot = 0xff; // uninitialized, asserts() if used complete_mutex = PTHREAD_MUTEX_INITIALIZER; - //complete_cond = PTHREAD_COND_INITIALIZER; // PRU signal notifies request on completeness + complete_cond = PTHREAD_COND_INITIALIZER; // PRU signal notifies request on completeness } priority_request_c::~priority_request_c() { diff --git a/10.01_base/2_src/arm/priorityrequest.hpp b/10.01_base/2_src/arm/priorityrequest.hpp index 41c86e5..c6c61e5 100644 --- a/10.01_base/2_src/arm/priorityrequest.hpp +++ b/10.01_base/2_src/arm/priorityrequest.hpp @@ -82,7 +82,7 @@ public: // PRU -> signal -> worker() -> request -> device. INTR/DMA pthread_mutex_t complete_mutex; - //pthread_cond_t complete_cond; // PRU signal notifies request on completeness + pthread_cond_t complete_cond; // PRU signal notifies request on completeness priority_request_c(unibusdevice_c *device); virtual ~priority_request_c(); // not used, but need dynamic_cast diff --git a/10.01_base/2_src/arm/unibusadapter.cpp b/10.01_base/2_src/arm/unibusadapter.cpp index d83333b..d8b3a9f 100644 --- a/10.01_base/2_src/arm/unibusadapter.cpp +++ b/10.01_base/2_src/arm/unibusadapter.cpp @@ -296,13 +296,14 @@ void unibusadapter_c::requests_cancel_scheduled(void) { if ((req = prl->slot_request[slot])) { dma_request_c *dmareq; req->executing_on_PRU = false; - req->complete = true; if ((dmareq = dynamic_cast(req))) dmareq->success = false; // device gets an DMA error, but will not understand prl->slot_request[slot] = NULL; - // signal to blockin DMA() or INTR() - pthread_mutex_unlock(&req->complete_mutex); - //pthread_cond_signal(&req->complete_cond); + // signal to blocking DMA() or INTR() + pthread_mutex_lock(&req->complete_mutex); + req->complete = true; + pthread_cond_signal(&req->complete_cond); + pthread_mutex_unlock(&req->complete_mutex); } } } @@ -489,12 +490,10 @@ void unibusadapter_c::request_active_complete(unsigned level_index) { prl->active = NULL; // signal to DMA() or INTR() - tmprq->complete = true; // close to signal - pthread_mutex_unlock(&tmprq->complete_mutex); - -// pthread_cond_signal(&tmprq->complete_cond); - -// pthread_cond_broadcast(&tmprq->complete_cond); + pthread_mutex_lock(&tmprq->complete_mutex); + tmprq->complete = true; + pthread_cond_signal(&tmprq->complete_cond); + pthread_mutex_unlock(&tmprq->complete_mutex); } // Request a DMA cycle from Arbitrator. @@ -522,9 +521,9 @@ void unibusadapter_c::DMA(dma_request_c& dma_request, bool blocking, uint8_t uni priority_request_level_c *prl = &request_levels[PRIORITY_LEVEL_INDEX_NPR]; assert(prl->slot_request[dma_request.slot] == NULL); // not scheduled or prev completed - pthread_mutex_lock(&dma_request.complete_mutex); // lock early, else PRU can signal cond before we lock // dma_request.level-index, priority_slot in constructor dma_request.complete = false; + dma_request.success = false; dma_request.executing_on_PRU = false; dma_request.unibus_control = unibus_control; dma_request.unibus_start_addr = unibus_addr; @@ -549,20 +548,13 @@ void unibusadapter_c::DMA(dma_request_c& dma_request, bool blocking, uint8_t uni // DEBUG("device DMA start: %s @ %06o, len=%d", unibus->control2text(unibus_control), unibus_addr, wordcount); if (blocking) { - // acquire locked mutex => wait for worker to release pthread_mutex_lock(&dma_request.complete_mutex); + // DMA() is blocking: Wait for request to finish. + while (!dma_request.complete) { + int res = pthread_cond_wait(&dma_request.complete_cond, &dma_request.complete_mutex); + assert(!res); + } pthread_mutex_unlock(&dma_request.complete_mutex); - - /* - // DMA() is blocking: Wait for request to finish. - // pthread_mutex_lock(&dma_request.mutex); - while (!dma_request.complete) { - // busy waiting OK - int res = pthread_cond_wait(&dma_request.complete_cond, &dma_request.complete_mutex); - assert(!res) ; - dma_request.dbg_complete_sig_received++ ; - } - */ } } @@ -685,6 +677,9 @@ void unibusadapter_c::cancel_INTR(intr_request_c& intr_request) { } // both empty, or both filled assert((prl->slot_request_mask == 0) == (prl->active == NULL)); + + pthread_mutex_lock(&intr_request.complete_mutex); + pthread_cond_signal(&intr_request.complete_cond); pthread_mutex_unlock(&intr_request.complete_mutex); pthread_mutex_unlock(&requests_mutex); // lock schedule table operations diff --git a/10.01_base/2_src/arm/unibusadapter.hpp b/10.01_base/2_src/arm/unibusadapter.hpp index 102d9ce..c4d8bbc 100644 --- a/10.01_base/2_src/arm/unibusadapter.hpp +++ b/10.01_base/2_src/arm/unibusadapter.hpp @@ -100,7 +100,7 @@ public: void INTR(intr_request_c& intr_request, unibusdevice_register_t *interrupt_register, uint16_t interrupt_register_value); void cancel_INTR(intr_request_c& intr_request) ; - + void print_shared_register_map(void); diff --git a/10.01_base/2_src/shared/tuning.h b/10.01_base/2_src/shared/tuning.h index d677d7f..6f6de3e 100644 --- a/10.01_base/2_src/shared/tuning.h +++ b/10.01_base/2_src/shared/tuning.h @@ -81,4 +81,4 @@ // Addtional delay on PDP11s with private memory interconnect (PMI) // and UNIBUS/PMI translation? // Experiments with "250" made still occasional errors. -#define UNIBUS_DMA_MASTER_PRE_MSYN_NS 350 +#define UNIBUS_DMA_MASTER_PRE_MSYN_NS 400 diff --git a/10.02_devices/2_src/mscp_server.cpp b/10.02_devices/2_src/mscp_server.cpp index cc4e17f..39582a2 100644 --- a/10.02_devices/2_src/mscp_server.cpp +++ b/10.02_devices/2_src/mscp_server.cpp @@ -200,16 +200,17 @@ mscp_server::Poll(void) // std::queue> messages; + int msgCount = 0; while (!_abort_polling && _pollState != PollingState::InitRestart) { shared_ptr message(_port->GetNextCommand()); - if (nullptr == message) { - DEBUG("End of command ring; %d messages to be executed."); + DEBUG("End of command ring; %d messages to be executed.", msgCount); break; } + msgCount++; messages.push(message); } @@ -221,8 +222,6 @@ mscp_server::Poll(void) shared_ptr message(messages.front()); messages.pop(); - DEBUG("Processing message."); - // // Handle the message. We dispatch on opcodes to the // appropriate methods. These methods modify the message diff --git a/10.02_devices/2_src/rk05.hpp b/10.02_devices/2_src/rk05.hpp old mode 100755 new mode 100644 index a5a0bcf..3d72d9b --- a/10.02_devices/2_src/rk05.hpp +++ b/10.02_devices/2_src/rk05.hpp @@ -56,12 +56,10 @@ private: volatile bool _scp; // Indicates the completion of a seek - uint64_t get_disk_byte_offset( uint32_t cylinder, uint32_t surface, uint32_t sector); - public: Geometry get_geometry(void); @@ -96,7 +94,6 @@ public: bool on_param_changed(parameter_c* param) override; void on_power_changed(void) override; - void on_init_changed(void) override; // background worker function diff --git a/10.02_devices/2_src/rk11.cpp b/10.02_devices/2_src/rk11.cpp index de41330..5d99707 100755 --- a/10.02_devices/2_src/rk11.cpp +++ b/10.02_devices/2_src/rk11.cpp @@ -4,7 +4,7 @@ Copyright Vulcan Inc. 2019 via Living Computers: Museum + Labs, Seattle, WA. Contributed under the BSD 2-clause license. - */ +*/ #include #include @@ -189,7 +189,6 @@ void rk11_c::dma_transfer(DMARequest &request) } } - // If an IBA DMA read from memory, we need to fill the request buffer // with the single word returned from memory by the DMA operation. if (request.iba && !request.write) diff --git a/10.02_devices/2_src/rk11.hpp b/10.02_devices/2_src/rk11.hpp index 1dea632..a98908b 100755 --- a/10.02_devices/2_src/rk11.hpp +++ b/10.02_devices/2_src/rk11.hpp @@ -4,7 +4,7 @@ Copyright Vulcan Inc. 2019 via Living Computers: Museum + Labs, Seattle, WA. Contributed under the BSD 2-clause license. - */ +*/ #ifndef _RK11_HPP_ #define _RK11_HPP_ diff --git a/10.02_devices/2_src/uda.cpp b/10.02_devices/2_src/uda.cpp index 2fbef44..d7a12d9 100644 --- a/10.02_devices/2_src/uda.cpp +++ b/10.02_devices/2_src/uda.cpp @@ -46,12 +46,12 @@ uda_c::uda_c() : type_name.value = "UDA50"; log_label = "uda"; - // base addr, intr-vector, intr level - set_default_bus_params(0772150, 20, 0154, 5) ; - dma_request.set_priority_slot(default_priority_slot) ; - intr_request.set_priority_slot(default_priority_slot) ; - intr_request.set_level(default_intr_level) ; - intr_request.set_vector(default_intr_vector) ; + // base addr, intr-vector, intr level + set_default_bus_params(0772150, 20, 0154, 5) ; + dma_request.set_priority_slot(default_priority_slot) ; + intr_request.set_priority_slot(default_priority_slot) ; + intr_request.set_level(default_intr_level) ; + intr_request.set_vector(default_intr_vector) ; // The UDA50 controller has two registers. register_count = 2; @@ -98,8 +98,8 @@ uda_c::~uda_c() } bool uda_c::on_param_changed(parameter_c *param) { - // no own parameter or "enable" logic - return storagecontroller_c::on_param_changed(param) ; // more actions (for enable) + // no own parameter or "enable" logic + return storagecontroller_c::on_param_changed(param) ; // more actions (for enable) } @@ -169,7 +169,7 @@ void uda_c::StateTransition( // void uda_c::worker(unsigned instance) { - UNUSED(instance) ; // only one + UNUSED(instance) ; // only one worker_init_realtime_priority(rt_device); @@ -224,8 +224,7 @@ void uda_c::worker(unsigned instance) // Update the SA read value for step 2: // S2 is set, unibus port type (0), SA bits 15-8 written // by the host in step 1. - update_SA(0x1000 | ((_step1Value >> 8) & 0xff)); - Interrupt(); + Interrupt(0x1000 | ((_step1Value >> 8) & 0xff)); break; case InitializationStep::Step3: @@ -234,8 +233,7 @@ void uda_c::worker(unsigned instance) DEBUG("Transition to Init state S3."); // Update the SA read value for step 3: // S3 set, plus SA bits 7-0 written by the host in step 1. - update_SA(0x2000 | (_step1Value & 0xff)); - Interrupt(); + Interrupt(0x2000 | (_step1Value & 0xff)); break; case InitializationStep::Step4: @@ -275,8 +273,7 @@ void uda_c::worker(unsigned instance) DEBUG("Transition to Init state S4, comm area initialized."); // Update the SA read value for step 4: // Bits 7-0 indicating our control microcode version. - update_SA(UDA50_ID); // UDA50 ID, makes RSTS happy - Interrupt(); + Interrupt(UDA50_ID); // UDA50 ID, makes RSTS happy break; case InitializationStep::Complete: @@ -304,7 +301,8 @@ uda_c::on_after_register_access( { // "When written with any value, it causes a hard initialization // of the port and the device controller." - DEBUG("Reset due to IP read"); + DEBUG("Reset due to IP read"); + update_SA(0x0); StateTransition(InitializationStep::Uninitialized); } else @@ -352,7 +350,9 @@ uda_c::on_after_register_access( // during initialization. _step1Value = value; - intr_vector.value = _interruptVector = ((value & 0x7f) << 2); + _interruptVector = ((value & 0x7f) << 2); + + intr_request.set_vector(_interruptVector); _interruptEnable = !!(value & 0x80); _responseRingLength = (1 << ((value & 0x700) >> 8)); _commandRingLength = (1 << ((value & 0x3800) >> 11)); @@ -531,7 +531,7 @@ uda_c::GetNextCommand(void) DMAReadWord( messageAddress - 4, success); - + assert(messageLength > 0 && messageLength < MAX_MESSAGE_LENGTH); std::unique_ptr cmdMessage( @@ -591,7 +591,7 @@ uda_c::GetNextCommand(void) DMAWrite( descriptorAddress, sizeof(Descriptor), - reinterpret_cast(cmdDescriptor.get())); + reinterpret_cast(cmdDescriptor.get())); // // Move to the next descriptor in the ring for next time. @@ -802,6 +802,24 @@ uda_c::GetControllerClassModel() return 0x0102; // Class 1 (mass storage), model 2 (UDA50) } +// +// Interrupt(): +// Invokes a Unibus interrupt if interrupts are enabled and the interrupt +// vector is non-zero. Updates SA to the specified value atomically. +// +void +uda_c::Interrupt(uint16_t sa_value) +{ + if ((_interruptEnable || _initStep == InitializationStep::Complete) && _interruptVector != 0) + { + unibusadapter->INTR(intr_request, SA_reg, sa_value); + } + else + { + update_SA(sa_value); + } +} + // // Interrupt(): // Invokes a Unibus interrupt if interrupts are enabled and the interrupt @@ -812,7 +830,7 @@ uda_c::Interrupt(void) { if ((_interruptEnable || _initStep == InitializationStep::Complete) && _interruptVector != 0) { - unibusadapter->INTR(intr_request, NULL, 0); // todo: link to interupt register + unibusadapter->INTR(intr_request, NULL, 0); } } @@ -989,6 +1007,6 @@ uda_c::DMARead( } else { - return nullptr; + return nullptr; } } diff --git a/10.02_devices/2_src/uda.hpp b/10.02_devices/2_src/uda.hpp index b7e861c..9c46b6a 100644 --- a/10.02_devices/2_src/uda.hpp +++ b/10.02_devices/2_src/uda.hpp @@ -76,9 +76,9 @@ public: void on_drive_status_changed(storagedrive_c *drive) override; - // As every storage controller UDA has one INTR and DMA - dma_request_c dma_request = dma_request_c(this) ; // operated by unibusadapter - intr_request_c intr_request = intr_request_c(this) ; + // As every storage controller UDA has one INTR and DMA + dma_request_c dma_request = dma_request_c(this) ; // operated by unibusadapter + intr_request_c intr_request = intr_request_c(this) ; public: @@ -103,6 +103,7 @@ public: private: // TODO: consolidate these private/public groups here void Reset(void); + void Interrupt(uint16_t sa_value); void Interrupt(void); uint32_t GetCommandDescriptorAddress(size_t index);