1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-01-29 21:21:25 +00:00
Files
livingcomputermuseum.UniBone/10.01_base/2_src/arm/priorityrequest.hpp
Josh Dersch 6f1b476716 Cleaned up signaling of DMA/INTR completion (using pthread_cond_wait).
Tweaked MSYN timeout value from 350ns to 400ns to compensate for timing changes
with latest PRU code -- MSCP works reliably on PDP-11/84 again.
2019-08-16 02:23:32 +02:00

184 lines
5.6 KiB
C++

/* priorityrequest.hpp: DMA or iNTR request of an device
Copyright (c) 2019 Joerg Hoppe
j_hoppe@t-online.de, www.retrocmp.com
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
jul-2019 JH start: multiple parallel arbitration levels
*/
/*
Handling priorities of Arbitration Requests:
1. Priority of arbitration levels
Ascending priority: INTR BR4,5,6,7, DMA NPR
=> 5 Priority Arbitration Levels encoded with index 0..4
2. Priority within one request level
Priority for Requests of same level given by backplane slot.
Backplane closests to CPU is granted first => highest priority
So priority of a request is given by two coordinates: level and slot.
Implementation:
all 5 levels are handled in parallel: priority_request_level_c [5])
In each level, a refernece array[slot] holds open requests.
For fast determination of lowest active slot, a bitarray
marks active slots.
*/
#ifndef _PRIORITYREQUEST_HPP_
#define _PRIORITYREQUEST_HPP_
#include <stdint.h>
#include <pthread.h>
#include "logsource.hpp"
// linear indexes for different UNIBUS arbitration levels
#define PRIORITY_LEVEL_INDEX_BR4 0
#define PRIORITY_LEVEL_INDEX_BR5 1
#define PRIORITY_LEVEL_INDEX_BR6 2
#define PRIORITY_LEVEL_INDEX_BR7 3
#define PRIORITY_LEVEL_INDEX_NPR 4
#define PRIORITY_LEVEL_COUNT 5
#define PRIORITY_SLOT_COUNT 32 // backplane slot numbers 0..31 may be used
class unibusdevice_c;
// (almost) abstract base class for dma and intr requests
class priority_request_c: public logsource_c {
friend class intr_request_c;
friend class dma_request_c;
friend class unibusadapter_c;
private:
unibusdevice_c *device; // this device owns the request
// maybe NULL, in request is not used for device meualtion
// (test console EXAM, DEPOSIT for example).
// internal priority index of a request level, see REQUEST_INDEX_*
uint8_t level_index; // is BR4567,NPR level - 4
uint8_t slot; // backplane slot which triggered request
public:
// better make state variables volatile, accessed by unibusadapter::worker
volatile bool executing_on_PRU; // true between schedule to PRU and compelte signal
volatile bool complete;
// PRU -> signal -> worker() -> request -> device. INTR/DMA
pthread_mutex_t complete_mutex;
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
void set_priority_slot(uint8_t slot);
uint8_t get_priority_slot(void) {
return slot;
}
};
class dma_request_c: public priority_request_c {
friend class unibusadapter_c;
public:
dma_request_c(unibusdevice_c *device);
~dma_request_c();
// const for all chunks
uint8_t unibus_control; // DATI,DATO
uint32_t unibus_start_addr;
uint32_t unibus_end_addr;
uint16_t* buffer;
uint32_t wordcount;
// DMA transaction are divided in to smaller DAT transfer "chunks"
uint32_t chunk_max_words; // max is PRU capacity PRU_MAX_DMA_WORDCOUNT (512)
uint32_t chunk_unibus_start_addr; // current chunk
uint32_t chunk_words; // size of current chunks
volatile bool success; // DMA can fail with bus timeout
// return ptr to chunk pos in buffer
uint16_t *chunk_buffer_start(void) {
return buffer + (chunk_unibus_start_addr - unibus_start_addr) / 2;
}
// words already transfered in previous chunks
uint32_t wordcount_completed_chunks(void) {
return (chunk_unibus_start_addr - unibus_start_addr) / 2;
}
};
struct unibusdevice_register_struct;
// forward
class intr_request_c: public priority_request_c {
friend class unibusadapter_c;
public:
enum interrupt_edge_enum {
INTERRUPT_EDGE_NONE, INTERRUPT_EDGE_RAISING, INTERRUPT_EDGE_FALLING
};
private:
uint16_t vector; // PDP-11 interrupt vector
// optionally register, with which a device signals presence of interrupt condition
struct unibusdevice_register_struct *interrupt_register;
uint16_t interrupt_register_value;
// static level of some device INTR signal.
// raising edge calculated with edge_detect()
bool signal_level;
public:
intr_request_c(unibusdevice_c *device);
~intr_request_c();
void set_level(uint8_t level);
void set_vector(uint16_t vector);
uint8_t get_level(void) {
return level_index + 4;
}
uint8_t get_vector(void) {
return vector;
}
// service for device logic: calculate change of static INTR condition
void edge_detect_reset() {
signal_level = 0;
}
// detect raising edge of interrupt level
enum interrupt_edge_enum edge_detect(bool new_signal_level) {
if (signal_level == new_signal_level)
return INTERRUPT_EDGE_NONE;
else {
// change: which edge?
signal_level = new_signal_level;
if (signal_level)
return INTERRUPT_EDGE_RAISING;
else
return INTERRUPT_EDGE_FALLING;
}
}
};
#endif