1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-01-27 20:37:36 +00:00

Merge pull request #3 from livingcomputermuseum/master

Fixes for MSCP with new DMA/IRQ infrastructure
This commit is contained in:
Jörg Hoppe
2019-08-16 14:25:44 +02:00
committed by GitHub
11 changed files with 70 additions and 61 deletions

View File

@@ -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() {

View File

@@ -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

View File

@@ -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<dma_request_c *>(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

View File

@@ -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);

View File

@@ -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

View File

@@ -200,16 +200,17 @@ mscp_server::Poll(void)
//
std::queue<shared_ptr<Message>> messages;
int msgCount = 0;
while (!_abort_polling && _pollState != PollingState::InitRestart)
{
shared_ptr<Message> 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> message(messages.front());
messages.pop();
DEBUG("Processing message.");
//
// Handle the message. We dispatch on opcodes to the
// appropriate methods. These methods modify the message

3
10.02_devices/2_src/rk05.hpp Executable file → Normal file
View File

@@ -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

View File

@@ -4,7 +4,7 @@
Copyright Vulcan Inc. 2019 via Living Computers: Museum + Labs, Seattle, WA.
Contributed under the BSD 2-clause license.
*/
*/
#include <string.h>
#include <assert.h>
@@ -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)

View File

@@ -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_

View File

@@ -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<Message> cmdMessage(
@@ -591,7 +591,7 @@ uda_c::GetNextCommand(void)
DMAWrite(
descriptorAddress,
sizeof(Descriptor),
reinterpret_cast<uint8_t*>(cmdDescriptor.get()));
reinterpret_cast<uint8_t*>(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;
}
}

View File

@@ -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);