mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-28 08:30:21 +00:00
967 lines
24 KiB
C++
967 lines
24 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator PiSCSI
|
|
// for Raspberry Pi
|
|
//
|
|
// Powered by XM6 TypeG Technology.
|
|
// Copyright (C) 2016-2020 GIMONS
|
|
//
|
|
// [ GPIO-SCSI bus ]
|
|
//
|
|
// Raspberry Pi 4:
|
|
// https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
|
|
// Raspberry Pi Zero:
|
|
// https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <spdlog/spdlog.h>
|
|
#include "hal/gpiobus_raspberry.h"
|
|
#include "hal/gpiobus.h"
|
|
#include "hal/systimer.h"
|
|
#include <map>
|
|
#include <cstring>
|
|
#ifdef __linux__
|
|
#include <sys/epoll.h>
|
|
#endif
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/time.h>
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// imported from bcm_host.c
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
uint32_t GPIOBUS_Raspberry::get_dt_ranges(const char *filename, uint32_t offset)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
uint32_t address = ~0;
|
|
if (FILE *fp = fopen(filename, "rb"); fp) {
|
|
fseek(fp, offset, SEEK_SET);
|
|
if (array<uint8_t, 4> buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) {
|
|
address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0;
|
|
}
|
|
fclose(fp);
|
|
}
|
|
return address;
|
|
}
|
|
|
|
uint32_t GPIOBUS_Raspberry::bcm_host_get_peripheral_address()
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
#ifdef __linux__
|
|
uint32_t address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
|
|
if (address == 0) {
|
|
address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
|
|
}
|
|
address = (address == (uint32_t)~0) ? 0x20000000 : address;
|
|
return address;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::Init(mode_e mode)
|
|
{
|
|
GPIOBUS::Init(mode);
|
|
|
|
#if defined(__x86_64__) || defined(__X86__)
|
|
(void)baseaddr;
|
|
level = new uint32_t();
|
|
return true;
|
|
#else
|
|
int i;
|
|
#ifdef USE_SEL_EVENT_ENABLE
|
|
epoll_event ev = {};
|
|
#endif
|
|
|
|
// Get the base address
|
|
baseaddr = (uint32_t)bcm_host_get_peripheral_address();
|
|
|
|
// Open /dev/mem
|
|
int fd = open("/dev/mem", O_RDWR | O_SYNC);
|
|
if (fd == -1) {
|
|
spdlog::error("Error: Unable to open /dev/mem. Are you running as root?");
|
|
return false;
|
|
}
|
|
|
|
// Map peripheral region memory
|
|
void *map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
|
|
if (map == MAP_FAILED) {
|
|
spdlog::error("Error: Unable to map memory: "+ string(strerror(errno)));
|
|
close(fd);
|
|
return false;
|
|
}
|
|
|
|
// Determine the type of raspberry pi from the base address
|
|
if (baseaddr == 0xfe000000) {
|
|
rpitype = 4;
|
|
} else if (baseaddr == 0x3f000000) {
|
|
rpitype = 2;
|
|
} else {
|
|
rpitype = 1;
|
|
}
|
|
|
|
// GPIO
|
|
gpio = (uint32_t *)map;
|
|
gpio += GPIO_OFFSET / sizeof(uint32_t);
|
|
level = &gpio[GPIO_LEV_0];
|
|
|
|
// PADS
|
|
pads = (uint32_t *)map;
|
|
pads += PADS_OFFSET / sizeof(uint32_t);
|
|
|
|
// System timer
|
|
SysTimer::Init();
|
|
|
|
// Interrupt controller
|
|
irpctl = (uint32_t *)map;
|
|
irpctl += IRPT_OFFSET / sizeof(uint32_t);
|
|
|
|
// Quad-A7 control
|
|
qa7regs = (uint32_t *)map;
|
|
qa7regs += QA7_OFFSET / sizeof(uint32_t);
|
|
|
|
// Map GIC memory
|
|
if (rpitype == 4) {
|
|
map = mmap(NULL, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ARM_GICD_BASE);
|
|
if (map == MAP_FAILED) {
|
|
close(fd);
|
|
return false;
|
|
}
|
|
gicd = (uint32_t *)map;
|
|
gicc = (uint32_t *)map;
|
|
gicc += (ARM_GICC_BASE - ARM_GICD_BASE) / sizeof(uint32_t);
|
|
} else {
|
|
gicd = NULL;
|
|
gicc = NULL;
|
|
}
|
|
close(fd);
|
|
|
|
// Set Drive Strength to 16mA
|
|
DrvConfig(7);
|
|
|
|
// Set pull up/pull down
|
|
#if SIGNAL_CONTROL_MODE == 0
|
|
int pullmode = GPIO_PULLNONE;
|
|
#elif SIGNAL_CONTROL_MODE == 1
|
|
int pullmode = GPIO_PULLUP;
|
|
#else
|
|
int pullmode = GPIO_PULLDOWN;
|
|
#endif
|
|
|
|
// Initialize all signals
|
|
for (i = 0; SignalTable[i] >= 0; i++) {
|
|
int j = SignalTable[i];
|
|
PinSetSignal(j, OFF);
|
|
PinConfig(j, GPIO_INPUT);
|
|
PullConfig(j, pullmode);
|
|
}
|
|
|
|
// Set control signals
|
|
PinSetSignal(PIN_ACT, OFF);
|
|
PinSetSignal(PIN_TAD, OFF);
|
|
PinSetSignal(PIN_IND, OFF);
|
|
PinSetSignal(PIN_DTD, OFF);
|
|
PinConfig(PIN_ACT, GPIO_OUTPUT);
|
|
PinConfig(PIN_TAD, GPIO_OUTPUT);
|
|
PinConfig(PIN_IND, GPIO_OUTPUT);
|
|
PinConfig(PIN_DTD, GPIO_OUTPUT);
|
|
|
|
// Set the ENABLE signal
|
|
// This is used to show that the application is running
|
|
PinSetSignal(PIN_ENB, ENB_OFF);
|
|
PinConfig(PIN_ENB, GPIO_OUTPUT);
|
|
|
|
// GPIO Function Select (GPFSEL) registers backup
|
|
gpfsel[0] = gpio[GPIO_FSEL_0];
|
|
gpfsel[1] = gpio[GPIO_FSEL_1];
|
|
gpfsel[2] = gpio[GPIO_FSEL_2];
|
|
gpfsel[3] = gpio[GPIO_FSEL_3];
|
|
|
|
// Initialize SEL signal interrupt
|
|
#ifdef USE_SEL_EVENT_ENABLE
|
|
// GPIO chip open
|
|
fd = open("/dev/gpiochip0", 0);
|
|
if (fd == -1) {
|
|
spdlog::error("Unable to open /dev/gpiochip0. If PiSCSI is running, please shut it down first.");
|
|
return false;
|
|
}
|
|
|
|
// Event request setting
|
|
strcpy(selevreq.consumer_label, "PiSCSI");
|
|
selevreq.lineoffset = PIN_SEL;
|
|
selevreq.handleflags = GPIOHANDLE_REQUEST_INPUT;
|
|
#if SIGNAL_CONTROL_MODE < 2
|
|
selevreq.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE;
|
|
#else
|
|
selevreq.eventflags = GPIOEVENT_REQUEST_RISING_EDGE;
|
|
#endif // SIGNAL_CONTROL_MODE
|
|
|
|
// Get event request
|
|
if (ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &selevreq) == -1) {
|
|
spdlog::error("Unable to register event request. If PiSCSI is running, please shut it down first.");
|
|
close(fd);
|
|
return false;
|
|
}
|
|
|
|
// Close GPIO chip file handle
|
|
close(fd);
|
|
|
|
// epoll initialization
|
|
epfd = epoll_create(1);
|
|
ev.events = EPOLLIN | EPOLLPRI;
|
|
ev.data.fd = selevreq.fd;
|
|
epoll_ctl(epfd, EPOLL_CTL_ADD, selevreq.fd, &ev);
|
|
#else
|
|
// Edge detection setting
|
|
#if SIGNAL_CONTROL_MODE == 2
|
|
gpio[GPIO_AREN_0] = 1 << PIN_SEL;
|
|
#else
|
|
gpio[GPIO_AFEN_0] = 1 << PIN_SEL;
|
|
#endif // SIGNAL_CONTROL_MODE
|
|
|
|
// Clear event - GPIO Pin Event Detect Status
|
|
gpio[GPIO_EDS_0] = 1 << PIN_SEL;
|
|
|
|
// Register interrupt handler
|
|
setIrqFuncAddress(IrqHandler);
|
|
|
|
// GPIO interrupt setting
|
|
if (rpitype == 4) {
|
|
// GIC Invalid
|
|
gicd[GICD_CTLR] = 0;
|
|
|
|
// Route all interupts to core 0
|
|
for (i = 0; i < 8; i++) {
|
|
gicd[GICD_ICENABLER0 + i] = 0xffffffff;
|
|
gicd[GICD_ICPENDR0 + i] = 0xffffffff;
|
|
gicd[GICD_ICACTIVER0 + i] = 0xffffffff;
|
|
}
|
|
for (i = 0; i < 64; i++) {
|
|
gicd[GICD_IPRIORITYR0 + i] = 0xa0a0a0a0;
|
|
gicd[GICD_ITARGETSR0 + i] = 0x01010101;
|
|
}
|
|
|
|
// Set all interrupts as level triggers
|
|
for (i = 0; i < 16; i++) {
|
|
gicd[GICD_ICFGR0 + i] = 0;
|
|
}
|
|
|
|
// GIC Invalid
|
|
gicd[GICD_CTLR] = 1;
|
|
|
|
// Enable CPU interface for core 0
|
|
gicc[GICC_PMR] = 0xf0;
|
|
gicc[GICC_CTLR] = 1;
|
|
|
|
// Enable interrupts
|
|
gicd[GICD_ISENABLER0 + (GIC_GPIO_IRQ / 32)] = 1 << (GIC_GPIO_IRQ % 32);
|
|
} else {
|
|
// Enable interrupts
|
|
irpctl[IRPT_ENB_IRQ_2] = (1 << (GPIO_IRQ % 32));
|
|
}
|
|
#endif // USE_SEL_EVENT_ENABLE
|
|
|
|
// Create work table
|
|
MakeTable();
|
|
|
|
// Finally, enable ENABLE
|
|
// Show the user that this app is running
|
|
SetControl(PIN_ENB, ENB_ON);
|
|
|
|
return true;
|
|
#endif // ifdef __x86_64__ || __X86__
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::Cleanup()
|
|
{
|
|
#if defined(__x86_64__) || defined(__X86__)
|
|
return;
|
|
#else
|
|
// Release SEL signal interrupt
|
|
#ifdef USE_SEL_EVENT_ENABLE
|
|
close(selevreq.fd);
|
|
#endif // USE_SEL_EVENT_ENABLE
|
|
|
|
// Set control signals
|
|
PinSetSignal(PIN_ENB, OFF);
|
|
PinSetSignal(PIN_ACT, OFF);
|
|
PinSetSignal(PIN_TAD, OFF);
|
|
PinSetSignal(PIN_IND, OFF);
|
|
PinSetSignal(PIN_DTD, OFF);
|
|
PinConfig(PIN_ACT, GPIO_INPUT);
|
|
PinConfig(PIN_TAD, GPIO_INPUT);
|
|
PinConfig(PIN_IND, GPIO_INPUT);
|
|
PinConfig(PIN_DTD, GPIO_INPUT);
|
|
|
|
// Initialize all signals
|
|
for (int i = 0; SignalTable[i] >= 0; i++) {
|
|
int pin = SignalTable[i];
|
|
PinSetSignal(pin, OFF);
|
|
PinConfig(pin, GPIO_INPUT);
|
|
PullConfig(pin, GPIO_PULLNONE);
|
|
}
|
|
|
|
// Set drive strength back to 8mA
|
|
DrvConfig(3);
|
|
#endif // ifdef __x86_64__ || __X86__
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::Reset()
|
|
{
|
|
#if defined(__x86_64__) || defined(__X86__)
|
|
return;
|
|
#else
|
|
int i;
|
|
int j;
|
|
|
|
// Turn off active signal
|
|
SetControl(PIN_ACT, ACT_OFF);
|
|
|
|
// Set all signals to off
|
|
for (i = 0;; i++) {
|
|
j = SignalTable[i];
|
|
if (j < 0) {
|
|
break;
|
|
}
|
|
|
|
SetSignal(j, OFF);
|
|
}
|
|
|
|
if (actmode == mode_e::TARGET) {
|
|
// Target mode
|
|
|
|
// Set target signal to input
|
|
SetControl(PIN_TAD, TAD_IN);
|
|
SetMode(PIN_BSY, IN);
|
|
SetMode(PIN_MSG, IN);
|
|
SetMode(PIN_CD, IN);
|
|
SetMode(PIN_REQ, IN);
|
|
SetMode(PIN_IO, IN);
|
|
|
|
// Set the initiator signal to input
|
|
SetControl(PIN_IND, IND_IN);
|
|
SetMode(PIN_SEL, IN);
|
|
SetMode(PIN_ATN, IN);
|
|
SetMode(PIN_ACK, IN);
|
|
SetMode(PIN_RST, IN);
|
|
|
|
// Set data bus signals to input
|
|
SetControl(PIN_DTD, DTD_IN);
|
|
SetMode(PIN_DT0, IN);
|
|
SetMode(PIN_DT1, IN);
|
|
SetMode(PIN_DT2, IN);
|
|
SetMode(PIN_DT3, IN);
|
|
SetMode(PIN_DT4, IN);
|
|
SetMode(PIN_DT5, IN);
|
|
SetMode(PIN_DT6, IN);
|
|
SetMode(PIN_DT7, IN);
|
|
SetMode(PIN_DP, IN);
|
|
} else {
|
|
// Initiator mode
|
|
|
|
// Set target signal to input
|
|
SetControl(PIN_TAD, TAD_IN);
|
|
SetMode(PIN_BSY, IN);
|
|
SetMode(PIN_MSG, IN);
|
|
SetMode(PIN_CD, IN);
|
|
SetMode(PIN_REQ, IN);
|
|
SetMode(PIN_IO, IN);
|
|
|
|
// Set the initiator signal to output
|
|
SetControl(PIN_IND, IND_OUT);
|
|
SetMode(PIN_SEL, OUT);
|
|
SetMode(PIN_ATN, OUT);
|
|
SetMode(PIN_ACK, OUT);
|
|
SetMode(PIN_RST, OUT);
|
|
|
|
// Set the data bus signals to output
|
|
SetControl(PIN_DTD, DTD_OUT);
|
|
SetMode(PIN_DT0, OUT);
|
|
SetMode(PIN_DT1, OUT);
|
|
SetMode(PIN_DT2, OUT);
|
|
SetMode(PIN_DT3, OUT);
|
|
SetMode(PIN_DT4, OUT);
|
|
SetMode(PIN_DT5, OUT);
|
|
SetMode(PIN_DT6, OUT);
|
|
SetMode(PIN_DT7, OUT);
|
|
SetMode(PIN_DP, OUT);
|
|
}
|
|
|
|
// Initialize all signals
|
|
signals = 0;
|
|
#endif // ifdef __x86_64__ || __X86__
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetENB(bool ast)
|
|
{
|
|
PinSetSignal(PIN_ENB, ast ? ENB_ON : ENB_OFF);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetBSY() const
|
|
{
|
|
return GetSignal(PIN_BSY);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetBSY(bool ast)
|
|
{
|
|
// Set BSY signal
|
|
SetSignal(PIN_BSY, ast);
|
|
|
|
if (ast) {
|
|
// Turn on ACTIVE signal
|
|
SetControl(PIN_ACT, ACT_ON);
|
|
|
|
// Set Target signal to output
|
|
SetControl(PIN_TAD, TAD_OUT);
|
|
|
|
SetMode(PIN_BSY, OUT);
|
|
SetMode(PIN_MSG, OUT);
|
|
SetMode(PIN_CD, OUT);
|
|
SetMode(PIN_REQ, OUT);
|
|
SetMode(PIN_IO, OUT);
|
|
} else {
|
|
// Turn off the ACTIVE signal
|
|
SetControl(PIN_ACT, ACT_OFF);
|
|
|
|
// Set the target signal to input
|
|
SetControl(PIN_TAD, TAD_IN);
|
|
|
|
SetMode(PIN_BSY, IN);
|
|
SetMode(PIN_MSG, IN);
|
|
SetMode(PIN_CD, IN);
|
|
SetMode(PIN_REQ, IN);
|
|
SetMode(PIN_IO, IN);
|
|
}
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetSEL() const
|
|
{
|
|
return GetSignal(PIN_SEL);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetSEL(bool ast)
|
|
{
|
|
if (actmode == mode_e::INITIATOR && ast) {
|
|
// Turn on ACTIVE signal
|
|
SetControl(PIN_ACT, ACT_ON);
|
|
}
|
|
|
|
// Set SEL signal
|
|
SetSignal(PIN_SEL, ast);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetATN() const
|
|
{
|
|
return GetSignal(PIN_ATN);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetATN(bool ast)
|
|
{
|
|
SetSignal(PIN_ATN, ast);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetACK() const
|
|
{
|
|
return GetSignal(PIN_ACK);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetACK(bool ast)
|
|
{
|
|
SetSignal(PIN_ACK, ast);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetACT() const
|
|
{
|
|
return GetSignal(PIN_ACT);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetACT(bool ast)
|
|
{
|
|
SetSignal(PIN_ACT, ast);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetRST() const
|
|
{
|
|
return GetSignal(PIN_RST);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetRST(bool ast)
|
|
{
|
|
SetSignal(PIN_RST, ast);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetMSG() const
|
|
{
|
|
return GetSignal(PIN_MSG);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetMSG(bool ast)
|
|
{
|
|
SetSignal(PIN_MSG, ast);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetCD() const
|
|
{
|
|
return GetSignal(PIN_CD);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetCD(bool ast)
|
|
{
|
|
SetSignal(PIN_CD, ast);
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetIO()
|
|
{
|
|
bool ast = GetSignal(PIN_IO);
|
|
|
|
if (actmode == mode_e::INITIATOR) {
|
|
// Change the data input/output direction by IO signal
|
|
if (ast) {
|
|
SetControl(PIN_DTD, DTD_IN);
|
|
SetMode(PIN_DT0, IN);
|
|
SetMode(PIN_DT1, IN);
|
|
SetMode(PIN_DT2, IN);
|
|
SetMode(PIN_DT3, IN);
|
|
SetMode(PIN_DT4, IN);
|
|
SetMode(PIN_DT5, IN);
|
|
SetMode(PIN_DT6, IN);
|
|
SetMode(PIN_DT7, IN);
|
|
SetMode(PIN_DP, IN);
|
|
} else {
|
|
SetControl(PIN_DTD, DTD_OUT);
|
|
SetMode(PIN_DT0, OUT);
|
|
SetMode(PIN_DT1, OUT);
|
|
SetMode(PIN_DT2, OUT);
|
|
SetMode(PIN_DT3, OUT);
|
|
SetMode(PIN_DT4, OUT);
|
|
SetMode(PIN_DT5, OUT);
|
|
SetMode(PIN_DT6, OUT);
|
|
SetMode(PIN_DT7, OUT);
|
|
SetMode(PIN_DP, OUT);
|
|
}
|
|
}
|
|
|
|
return ast;
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetIO(bool ast)
|
|
{
|
|
SetSignal(PIN_IO, ast);
|
|
|
|
if (actmode == mode_e::TARGET) {
|
|
// Change the data input/output direction by IO signal
|
|
if (ast) {
|
|
SetControl(PIN_DTD, DTD_OUT);
|
|
SetDAT(0);
|
|
SetMode(PIN_DT0, OUT);
|
|
SetMode(PIN_DT1, OUT);
|
|
SetMode(PIN_DT2, OUT);
|
|
SetMode(PIN_DT3, OUT);
|
|
SetMode(PIN_DT4, OUT);
|
|
SetMode(PIN_DT5, OUT);
|
|
SetMode(PIN_DT6, OUT);
|
|
SetMode(PIN_DT7, OUT);
|
|
SetMode(PIN_DP, OUT);
|
|
} else {
|
|
SetControl(PIN_DTD, DTD_IN);
|
|
SetMode(PIN_DT0, IN);
|
|
SetMode(PIN_DT1, IN);
|
|
SetMode(PIN_DT2, IN);
|
|
SetMode(PIN_DT3, IN);
|
|
SetMode(PIN_DT4, IN);
|
|
SetMode(PIN_DT5, IN);
|
|
SetMode(PIN_DT6, IN);
|
|
SetMode(PIN_DT7, IN);
|
|
SetMode(PIN_DP, IN);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GPIOBUS_Raspberry::GetREQ() const
|
|
{
|
|
return GetSignal(PIN_REQ);
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetREQ(bool ast)
|
|
{
|
|
SetSignal(PIN_REQ, ast);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Get data signals
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
uint8_t GPIOBUS_Raspberry::GetDAT()
|
|
{
|
|
uint32_t data = Acquire();
|
|
data = ((data >> (PIN_DT0 - 0)) & (1 << 0)) | ((data >> (PIN_DT1 - 1)) & (1 << 1)) |
|
|
((data >> (PIN_DT2 - 2)) & (1 << 2)) | ((data >> (PIN_DT3 - 3)) & (1 << 3)) |
|
|
((data >> (PIN_DT4 - 4)) & (1 << 4)) | ((data >> (PIN_DT5 - 5)) & (1 << 5)) |
|
|
((data >> (PIN_DT6 - 6)) & (1 << 6)) | ((data >> (PIN_DT7 - 7)) & (1 << 7));
|
|
|
|
return (uint8_t)data;
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::SetDAT(uint8_t dat)
|
|
{
|
|
// Write to ports
|
|
#if SIGNAL_CONTROL_MODE == 0
|
|
uint32_t fsel = gpfsel[0];
|
|
fsel &= tblDatMsk[0][dat];
|
|
fsel |= tblDatSet[0][dat];
|
|
gpfsel[0] = fsel;
|
|
gpio[GPIO_FSEL_0] = fsel;
|
|
|
|
fsel = gpfsel[1];
|
|
fsel &= tblDatMsk[1][dat];
|
|
fsel |= tblDatSet[1][dat];
|
|
gpfsel[1] = fsel;
|
|
gpio[GPIO_FSEL_1] = fsel;
|
|
|
|
fsel = gpfsel[2];
|
|
fsel &= tblDatMsk[2][dat];
|
|
fsel |= tblDatSet[2][dat];
|
|
gpfsel[2] = fsel;
|
|
gpio[GPIO_FSEL_2] = fsel;
|
|
#else
|
|
gpio[GPIO_CLR_0] = tblDatMsk[dat];
|
|
gpio[GPIO_SET_0] = tblDatSet[dat];
|
|
#endif
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Signal table
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
const array<int, 19> GPIOBUS_Raspberry::SignalTable = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6,
|
|
PIN_DT7, PIN_DP, PIN_SEL, PIN_ATN, PIN_RST, PIN_ACK, PIN_BSY,
|
|
PIN_MSG, PIN_CD, PIN_IO, PIN_REQ, -1};
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Create work table
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::MakeTable(void)
|
|
{
|
|
const array<int, 9> pintbl = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP};
|
|
|
|
array<bool, 256> tblParity;
|
|
|
|
// Create parity table
|
|
for (uint32_t i = 0; i < 0x100; i++) {
|
|
uint32_t bits = i;
|
|
uint32_t parity = 0;
|
|
for (int j = 0; j < 8; j++) {
|
|
parity ^= bits & 1;
|
|
bits >>= 1;
|
|
}
|
|
parity = ~parity;
|
|
tblParity[i] = parity & 1;
|
|
}
|
|
|
|
#if SIGNAL_CONTROL_MODE == 0
|
|
// Mask and setting data generation
|
|
for (auto &tbl : tblDatMsk) {
|
|
tbl.fill(-1);
|
|
}
|
|
for (auto &tbl : tblDatSet) {
|
|
tbl.fill(0);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < 0x100; i++) {
|
|
// Bit string for inspection
|
|
uint32_t bits = i;
|
|
|
|
// Get parity
|
|
if (tblParity[i]) {
|
|
bits |= (1 << 8);
|
|
}
|
|
|
|
// Bit check
|
|
for (int j = 0; j < 9; j++) {
|
|
// Index and shift amount calculation
|
|
int index = pintbl[j] / 10;
|
|
int shift = (pintbl[j] % 10) * 3;
|
|
|
|
// Mask data
|
|
tblDatMsk[index][i] &= ~(0x7 << shift);
|
|
|
|
// Setting data
|
|
if (bits & 1) {
|
|
tblDatSet[index][i] |= (1 << shift);
|
|
}
|
|
|
|
bits >>= 1;
|
|
}
|
|
}
|
|
#else
|
|
for (uint32_t i = 0; i < 0x100; i++) {
|
|
// Bit string for inspection
|
|
uint32_t bits = i;
|
|
|
|
// Get parity
|
|
if (tblParity[i]) {
|
|
bits |= (1 << 8);
|
|
}
|
|
|
|
#if SIGNAL_CONTROL_MODE == 1
|
|
// Negative logic is inverted
|
|
bits = ~bits;
|
|
#endif
|
|
|
|
// Create GPIO register information
|
|
uint32_t gpclr = 0;
|
|
uint32_t gpset = 0;
|
|
for (int j = 0; j < 9; j++) {
|
|
if (bits & 1) {
|
|
gpset |= (1 << pintbl[j]);
|
|
} else {
|
|
gpclr |= (1 << pintbl[j]);
|
|
}
|
|
bits >>= 1;
|
|
}
|
|
|
|
tblDatMsk[i] = gpclr;
|
|
tblDatSet[i] = gpset;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Control signal setting
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::SetControl(int pin, bool ast)
|
|
{
|
|
PinSetSignal(pin, ast);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Input/output mode setting
|
|
//
|
|
// Set direction fo pin (IN / OUT)
|
|
// Used with: TAD, BSY, MSG, CD, REQ, O, SEL, IND, ATN, ACK, RST, DT*
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::SetMode(int pin, int mode)
|
|
{
|
|
#if SIGNAL_CONTROL_MODE == 0
|
|
if (mode == OUT) {
|
|
return;
|
|
}
|
|
#endif // SIGNAL_CONTROL_MODE
|
|
|
|
int index = pin / 10;
|
|
int shift = (pin % 10) * 3;
|
|
uint32_t data = gpfsel[index];
|
|
data &= ~(0x7 << shift);
|
|
if (mode == OUT) {
|
|
data |= (1 << shift);
|
|
}
|
|
gpio[index] = data;
|
|
gpfsel[index] = data;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Get input signal value
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
bool GPIOBUS_Raspberry::GetSignal(int pin) const
|
|
{
|
|
return (signals >> pin) & 1;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Set output signal value
|
|
//
|
|
// Sets the output value. Used with:
|
|
// PIN_ENB, ACT, TAD, IND, DTD, BSY, SignalTable
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::SetSignal(int pin, bool ast)
|
|
{
|
|
#if SIGNAL_CONTROL_MODE == 0
|
|
int index = pin / 10;
|
|
int shift = (pin % 10) * 3;
|
|
uint32_t data = gpfsel[index];
|
|
if (ast) {
|
|
data |= (1 << shift);
|
|
} else {
|
|
data &= ~(0x7 << shift);
|
|
}
|
|
gpio[index] = data;
|
|
gpfsel[index] = data;
|
|
#elif SIGNAL_CONTROL_MODE == 1
|
|
if (ast) {
|
|
gpio[GPIO_CLR_0] = 0x1 << pin;
|
|
} else {
|
|
gpio[GPIO_SET_0] = 0x1 << pin;
|
|
}
|
|
#elif SIGNAL_CONTROL_MODE == 2
|
|
if (ast) {
|
|
gpio[GPIO_SET_0] = 0x1 << pin;
|
|
} else {
|
|
gpio[GPIO_CLR_0] = 0x1 << pin;
|
|
}
|
|
#endif // SIGNAL_CONTROL_MODE
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::DisableIRQ()
|
|
{
|
|
#ifdef __linux__
|
|
if (rpitype == 4) {
|
|
// RPI4 is disabled by GICC
|
|
giccpmr = gicc[GICC_PMR];
|
|
gicc[GICC_PMR] = 0;
|
|
} else if (rpitype == 2) {
|
|
// RPI2,3 disable core timer IRQ
|
|
tintcore = sched_getcpu() + QA7_CORE0_TINTC;
|
|
tintctl = qa7regs[tintcore];
|
|
qa7regs[tintcore] = 0;
|
|
} else {
|
|
// Stop system timer interrupt with interrupt controller
|
|
irptenb = irpctl[IRPT_ENB_IRQ_1];
|
|
irpctl[IRPT_DIS_IRQ_1] = irptenb & 0xf;
|
|
}
|
|
#else
|
|
(void)0;
|
|
#endif
|
|
}
|
|
|
|
void GPIOBUS_Raspberry::EnableIRQ()
|
|
{
|
|
if (rpitype == 4) {
|
|
// RPI4 enables interrupts via the GICC
|
|
gicc[GICC_PMR] = giccpmr;
|
|
} else if (rpitype == 2) {
|
|
// RPI2,3 re-enable core timer IRQ
|
|
qa7regs[tintcore] = tintctl;
|
|
} else {
|
|
// Restart the system timer interrupt with the interrupt controller
|
|
irpctl[IRPT_ENB_IRQ_1] = irptenb & 0xf;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Pin direction setting (input/output)
|
|
//
|
|
// Used in Init() for ACT, TAD, IND, DTD, ENB to set direction (GPIO_OUTPUT vs GPIO_INPUT)
|
|
// Also used on SignalTable
|
|
// Only used in Init and Cleanup. Reset uses SetMode
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::PinConfig(int pin, int mode)
|
|
{
|
|
// Check for invalid pin
|
|
if (pin < 0) {
|
|
return;
|
|
}
|
|
|
|
int index = pin / 10;
|
|
uint32_t mask = ~(0x7 << ((pin % 10) * 3));
|
|
gpio[index] = (gpio[index] & mask) | ((mode & 0x7) << ((pin % 10) * 3));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Pin pull-up/pull-down setting
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::PullConfig(int pin, int mode)
|
|
{
|
|
uint32_t pull;
|
|
|
|
// Check for invalid pin
|
|
if (pin < 0) {
|
|
return;
|
|
}
|
|
|
|
if (rpitype == 4) {
|
|
switch (mode) {
|
|
case GPIO_PULLNONE:
|
|
pull = 0;
|
|
break;
|
|
case GPIO_PULLUP:
|
|
pull = 1;
|
|
break;
|
|
case GPIO_PULLDOWN:
|
|
pull = 2;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
pin &= 0x1f;
|
|
int shift = (pin & 0xf) << 1;
|
|
uint32_t bits = gpio[GPIO_PUPPDN0 + (pin >> 4)];
|
|
bits &= ~(3 << shift);
|
|
bits |= (pull << shift);
|
|
gpio[GPIO_PUPPDN0 + (pin >> 4)] = bits;
|
|
} else {
|
|
pin &= 0x1f;
|
|
gpio[GPIO_PUD] = mode & 0x3;
|
|
SysTimer::SleepUsec(2);
|
|
gpio[GPIO_CLK_0] = 0x1 << pin;
|
|
SysTimer::SleepUsec(2);
|
|
gpio[GPIO_PUD] = 0;
|
|
gpio[GPIO_CLK_0] = 0;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Set output pin
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::PinSetSignal(int pin, bool ast)
|
|
{
|
|
// Check for invalid pin
|
|
if (pin < 0) {
|
|
return;
|
|
}
|
|
|
|
if (ast) {
|
|
gpio[GPIO_SET_0] = 0x1 << pin;
|
|
} else {
|
|
gpio[GPIO_CLR_0] = 0x1 << pin;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Set the signal drive strength
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS_Raspberry::DrvConfig(uint32_t drive)
|
|
{
|
|
uint32_t data = pads[PAD_0_27];
|
|
pads[PAD_0_27] = (0xFFFFFFF8 & data) | drive | 0x5a000000;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Bus signal acquisition
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
uint32_t GPIOBUS_Raspberry::Acquire()
|
|
{
|
|
signals = *level;
|
|
|
|
#if SIGNAL_CONTROL_MODE < 2
|
|
// Invert if negative logic (internal processing is unified to positive logic)
|
|
signals = ~signals;
|
|
#endif // SIGNAL_CONTROL_MODE
|
|
|
|
return signals;
|
|
}
|