1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-05-03 06:29:28 +00:00
Files
livingcomputermuseum.UniBone/10.01_base/2_src/arm/unibusdevice.hpp
Joerg Hoppe 3d1d9d3cf6 ACLO/DCLO/INIT moved from PRU to ARM
INTR/DMA request params linked to device params on change
2019-08-19 13:12:42 +02:00

172 lines
6.5 KiB
C++

/* unibusdevice.hpp: abstract device with interface to unibusadapter
Copyright (c) 2018, 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.
12-nov-2018 JH entered beta phase
*/
#ifndef _UNIBUSDEVICE_HPP_
#define _UNIBUSDEVICE_HPP_
#include <stdint.h>
#include <pthread.h>
#include "device.hpp"
#include "iopageregister.h"
#include "priorityrequest.hpp"
// forwards
class unibusdevice_c;
typedef struct unibusdevice_register_struct {
// backlink
unibusdevice_c *device;
char name[40]; // for display
unsigned index; // # of register in device register list
uint32_t addr; // unibus address
// so addr = device_base_addr + 2 * index
/*** link into PRU shared area ***/
// only for access by unibusadapter
// Restauration of shared_register->value IS NOT ATOMIC against device logic threads.
// Devices must use only reg->active_dati_flipflops !
volatile iopageregister_t *shared_register;
uint8_t shared_register_handle;
/*** static setup information ***/
// "Active=true": PRU generates an event after DATI and/or DATO on that register
// (context switch to ARM: slow!)
// "Active=false": PRU handles register access with simple data value like a memory cell.
// (fast)
// "active_on_dato" is true for "command" registers, which
// start controller actions (like "CMD+GO" in RL11 and similar disk controllers
// "active_on_dati" is true, if read with DATI clears a bit,
// or if register is port to a value sequence.
// Status register should be not "active", as they are polled in loops
// But sometimes reading status clears an INTR flag.
// controllers "on_after_register_access" is called then after
// UNIBUS access to the register
bool active_on_dati; // call on_after_register_access() on DATI
bool active_on_dato; // call on_after_register_access() on DATO
uint16_t reset_value;
uint16_t writable_bits;
/*** dynamic state ***/
// if register is "active": flipflops behind address
// active registers have different latches for DATI and DATO cycles,
// and represent status/command information.
volatile uint16_t active_dati_flipflops; // latch acessed by DATI
volatile uint16_t active_dato_flipflops;
} unibusdevice_register_t;
class unibusdevice_c: public device_c {
public:
static unibusdevice_c *find_by_request_slot(uint8_t priority_slot) ;
private:
// setup address tables, also in shared memory
// start both threads
void install(void);
void uninstall(void);bool is_installed() {
return (handle > 0);
}
public:
uint8_t handle; // assigned by "unibus.adapter.register
// !!! slot, vector, level READONLY. If user should change,
// !! add logic to update dma_request_c and intr_request_c
// 0 = not "Plugged" in to UNIBUS
parameter_unsigned_c base_addr = parameter_unsigned_c(this, "base_addr", "addr", true, "",
"%06o", "controller base address in IO page", 18, 8);
parameter_unsigned_c priority_slot = parameter_unsigned_c(this, "slot", "sl", true, "",
"%d", "backplane slot #, interrupt priority within one level, 0 = next to CPU", 16,
10);
// dump devices without buffers toward CPU, smart buffering devices other end
parameter_unsigned_c intr_vector = parameter_unsigned_c(this, "intr_vector", "iv", true, "",
"%03o", "interrupt vector address", 9, 8);
parameter_unsigned_c intr_level = parameter_unsigned_c(this, "intr_level", "il", true, "",
"%o", "interrupt bus request level: 4,5,6,7", 3, 8);
// DEC defaults as defined by device type
uint32_t default_base_addr;
uint8_t default_priority_slot;
uint8_t default_intr_level;
uint16_t default_intr_vector;
// requests in use
std::vector<dma_request_c *> dma_requests;
std::vector<intr_request_c *> intr_requests;
void set_default_bus_params(uint32_t default_base_addr, unsigned default_priority_slot,
unsigned default_intr_vector, unsigned default_intr_level);
// controller register data as pointer to registers in shared PRU RAM
// UNIBUS addr of register[i] = base_addr + 2*i
// !! devices have always sequential register address range !!
unsigned register_count;
unibusdevice_register_t registers[MAX_REGISTERS_PER_DEVICE];
unsigned log_channelmask; // channelmask for DEBUG logging
// device is the log channel. one of logger::LC_*
unibusdevice_c();
virtual ~unibusdevice_c(); // class with virtual functions should have virtual destructors
bool on_param_changed(parameter_c *param) override;
// reset device
// virtual void init() override ;
// access the value of a register in shared UNIBUS PRU space
void set_register_dati_value(unibusdevice_register_t *device_reg, uint16_t value,
const char *debug_info);
uint16_t get_register_dato_value(unibusdevice_register_t *device_reg);
void reset_unibus_registers();
unibusdevice_register_t *register_by_name(string name);
unibusdevice_register_t *register_by_unibus_address(uint32_t addr);
// callback to be called on controller register DATI/DATO events.
// must ACK mailbox.event.signal. Asynchron!
// May not generate direct INTR or DMA.
// INTR/DMA as task to separate INTR/DMA scheduler
// -> orders INTR/DMA of different devices, wait for UNIBUS idle.
virtual void on_after_register_access(unibusdevice_register_t *device_reg,
uint8_t unibus_control) = 0;
// communication between on_after_register_access() and device_c::worker()
// see pthread_cond_wait()* examples
pthread_cond_t on_after_register_access_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t on_after_register_access_mutex = PTHREAD_MUTEX_INITIALIZER;
void log_register_event(const char *change_info, unibusdevice_register_t *changed_reg);
char *get_unibus_resource_info(void) ;
};
#endif