1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-04-26 03:58:34 +00:00

Implemented AVAILABLE, ERASE, DETERMINE ACCESS PATHS commands. Tweaks to interrupt queueing (request_INTR now blocks until

the interrupt actually gets signaled on the unibus).  OpenVMS 7.3 now boots on the VAX.
This commit is contained in:
Josh Dersch
2019-05-06 19:28:20 +02:00
parent 8eff2a4e10
commit be3b6d57ed
6 changed files with 272 additions and 81 deletions

View File

@@ -92,7 +92,8 @@ irq_request_c::irq_request_c(
unsigned level,
unsigned vector) :
_level(level),
_vector(vector)
_vector(vector),
_isComplete(false)
{
}
@@ -174,13 +175,13 @@ void unibusadapter_c::worker_init_event() {
device->on_init_changed();
}
INFO("clearing due to INIT empty %d", _irqRequests.empty());
// Clear bus request queues
/*
pthread_mutex_lock(&_busWorker_mutex);
_dmaRequests.clear();
_irqRequests.clear();
while (!_dmaRequests.empty()) _dmaRequests.pop();
while (!_irqRequests.empty()) _irqRequests.pop();
pthread_mutex_unlock(&_busWorker_mutex);
*/
}
void unibusadapter_c::worker_power_event() {
@@ -194,13 +195,13 @@ void unibusadapter_c::worker_power_event() {
device->on_power_changed();
}
INFO("clearing due to power empty %d", _irqRequests.empty());
// Clear bus request queues
/*
pthread_mutex_lock(&_busWorker_mutex);
_dmaRequests.clear();
_irqRequests.clear();
pthread_mutex_unlock(&_busWorker_mutex);
*/
while (!_dmaRequests.empty()) _dmaRequests.pop();
while (!_irqRequests.empty()) _irqRequests.pop();
pthread_mutex_unlock(&_busWorker_mutex);
}
// process DATI/DATO access to active device registers
@@ -587,11 +588,11 @@ bool unibusadapter_c::request_DMA(
void unibusadapter_c::dma_worker()
{
//worker_init_realtime_priority(rt_device);
while(true)
{
dma_request_c* dmaReq = nullptr;
irq_request_c irqReq(0,0);
irq_request_c* irqReq = nullptr;
//
// Wait for the next request.
@@ -610,8 +611,7 @@ void unibusadapter_c::dma_worker()
//
if (!_irqRequests.empty())
{
irq_request_c const& req = _irqRequests.front();
irqReq = req;
irqReq = _irqRequests.front();
_irqRequests.pop();
}
else
@@ -622,16 +622,18 @@ void unibusadapter_c::dma_worker()
pthread_mutex_unlock(&_busWorker_mutex);
// Sanity check: Should be no active DMA requests on the PRU.
assert (!request_DMA_active(nullptr));
// Sanity check: Should be no active DMA or interrupt requests on the PRU.
assert (!request_DMA_active(nullptr) && !request_INTR_active(nullptr));
/*
// If there's an IRQ still active, wait for it to finish.
// TODO: find a way to avoid having to do this.
timeout_c timer;
while (request_INTR_active(nullptr))
{
INFO("intr active");
timer.wait_us(50);
}
} */
if (dmaReq)
{
@@ -670,7 +672,7 @@ void unibusadapter_c::dma_worker()
// Wait for the transfer to complete.
// TODO: we're polling the mailbox; is there a more efficient way to do this?
timeout_c timeout;
while (request_DMA_active(NULL))
while (request_DMA_active(nullptr))
{
timeout.wait_us(50);
}
@@ -691,8 +693,14 @@ void unibusadapter_c::dma_worker()
dmaReq->SetUnibusEndAddr(mailbox->dma.cur_addr);
dmaReq->SetSuccess(mailbox->dma.cur_status == DMA_STATE_READY);
assert(dmaReq->GetUnibusAddr() + dmaReq->GetWordCount() * 2 == mailbox->dma.cur_addr + 2);
if(dmaReq->GetUnibusAddr() + dmaReq->GetWordCount() * 2 != mailbox->dma.cur_addr + 2)
{
FATAL("PRU end addr 0x%x, expected 0x%x",
mailbox->dma.cur_addr + 2,
dmaReq->GetUnibusAddr() + dmaReq->GetWordCount() * 2);
}
//
// Signal that the request is complete.
//
@@ -704,7 +712,7 @@ void unibusadapter_c::dma_worker()
else
{
// Handle interrupt request
switch(irqReq.GetInterruptLevel())
switch(irqReq->GetInterruptLevel())
{
case 4:
mailbox->intr.priority_bit = ARBITRATION_PRIORITY_BIT_B4;
@@ -723,15 +731,30 @@ void unibusadapter_c::dma_worker()
break;
default:
ERROR("Request_INTR(): Illegal priority %u, aborting", irqReq.GetInterruptLevel());
ERROR("Request_INTR(): Illegal priority %u, aborting", irqReq->GetInterruptLevel());
return;
}
mailbox->intr.vector = irqReq.GetVector();
mailbox->intr.vector = irqReq->GetVector();
// start!
mailbox->arm2pru_req = ARM2PRU_INTR;
// PRU now changes state
// Signal that the request has been raised.
pthread_mutex_lock(&_busWorker_mutex);
irqReq->SetComplete();
pthread_cond_signal(&_requestFinished_cond);
pthread_mutex_unlock(&_busWorker_mutex);
// Wait for the transfer to complete.
// TODO: we're polling the mailbox; is there a more efficient way to
// do this? (as w/dma)
timeout_c timeout;
while(request_INTR_active(nullptr))
{
timeout.wait_us(50);
}
}
}
}
@@ -746,10 +769,20 @@ void unibusadapter_c::request_INTR(uint32_t level, uint32_t vector) {
vector);
pthread_mutex_lock(&_busWorker_mutex);
_irqRequests.push(request);
_irqRequests.push(&request);
pthread_cond_signal(&_busWakeup_cond);
pthread_mutex_unlock(&_busWorker_mutex);
//
// Wait for request to finish.
//
pthread_mutex_lock(&_busWorker_mutex);
while (!request.IsComplete())
{
pthread_cond_wait(&_requestFinished_cond, &_busWorker_mutex);
}
pthread_mutex_unlock(&_busWorker_mutex);
//
// And we're done.
//

View File

@@ -80,10 +80,14 @@ public:
uint32_t GetInterruptLevel() { return _level; }
uint32_t GetVector() { return _vector; }
bool IsComplete() { return _isComplete; }
void SetComplete() { _isComplete = true; }
private:
uint32_t _level;
uint32_t _vector;
bool _isComplete;
};
@@ -126,7 +130,7 @@ public:
private:
std::queue<dma_request_c*> _dmaRequests;
std::queue<irq_request_c> _irqRequests;
std::queue<irq_request_c*> _irqRequests;
pthread_t _busWorker_pthread;
pthread_cond_t _busWakeup_cond;
pthread_cond_t _requestFinished_cond;