Optimize setting the data gpio bits (#1022)

Co-authored-by: Tony Kuker <akuker@gmail.com>
This commit is contained in:
akuker 2022-12-07 11:09:30 -06:00 committed by GitHub
parent 52c2aa474f
commit 09ba19a24f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 128 deletions

View File

@ -77,6 +77,8 @@ bool GPIOBUS_BananaM2p::Init(mode_e mode)
InitializeGpio();
MakeTable();
// SetupSelEvent needs to be called AFTER Initialize GPIO. This function
// reconfigures the SEL signal.
if (!SetupSelEvent()) {
@ -533,8 +535,8 @@ void GPIOBUS_BananaM2p::SetREQ(bool ast)
uint8_t GPIOBUS_BananaM2p::GetDAT()
{
GPIO_FUNCTION_TRACE
(void)Acquire();
// TODO: This is inefficient, but it works...
Acquire();
uint32_t data =
((GetSignal(BPI_PIN_DT0) ? 0x01 : 0x00) << 0) | ((GetSignal(BPI_PIN_DT1) ? 0x01 : 0x00) << 1) |
((GetSignal(BPI_PIN_DT2) ? 0x01 : 0x00) << 2) | ((GetSignal(BPI_PIN_DT3) ? 0x01 : 0x00) << 3) |
@ -549,27 +551,27 @@ void GPIOBUS_BananaM2p::SetDAT(uint8_t dat)
{
GPIO_FUNCTION_TRACE
SetMode(BPI_PIN_DT0, OUT);
SetMode(BPI_PIN_DT1, OUT);
SetMode(BPI_PIN_DT2, OUT);
SetMode(BPI_PIN_DT3, OUT);
SetMode(BPI_PIN_DT4, OUT);
SetMode(BPI_PIN_DT5, OUT);
SetMode(BPI_PIN_DT6, OUT);
SetMode(BPI_PIN_DT7, OUT);
SetMode(BPI_PIN_DP, OUT);
array<uint32_t, 12> gpio_reg_values = {0};
// TODO: This is inefficient, but it works...
PinSetSignal(BPI_PIN_DT0, (dat & (1 << 0)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
PinSetSignal(BPI_PIN_DT1, (dat & (1 << 1)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
PinSetSignal(BPI_PIN_DT2, (dat & (1 << 2)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
PinSetSignal(BPI_PIN_DT3, (dat & (1 << 3)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
PinSetSignal(BPI_PIN_DT4, (dat & (1 << 4)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
PinSetSignal(BPI_PIN_DT5, (dat & (1 << 5)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
PinSetSignal(BPI_PIN_DT6, (dat & (1 << 6)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
PinSetSignal(BPI_PIN_DT7, (dat & (1 << 7)) == 0); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
for (size_t gpio_num = 0; gpio_num < pintbl.size(); gpio_num++) {
bool value;
if (gpio_num < 8) {
// data bits
value = !(dat & (1 << gpio_num)); // NOSONAR: GCC 10 doesn't support shift operations on std::byte
} else {
// parity bit
value = (__builtin_parity(dat) == 1);
}
PinSetSignal(BPI_PIN_DP, __builtin_parity(dat) == 1);
if (value) {
uint32_t this_gpio = pintbl[gpio_num];
int bank = SunXI::GPIO_BANK(this_gpio);
int offset = SunXI::GPIO_NUM(this_gpio);
gpio_reg_values[bank] |= (1 << offset);
}
}
sunxi_set_all_gpios(gpio_data_masks, gpio_reg_values);
}
//---------------------------------------------------------------------------
@ -589,89 +591,12 @@ const array<int, 19> GPIOBUS_BananaM2p::SignalTable = {BPI_PIN_DT0, BPI_PIN_DT1,
//---------------------------------------------------------------------------
void GPIOBUS_BananaM2p::MakeTable(void)
{
const array<int, 9> pintbl = {BPI_PIN_DT0, BPI_PIN_DT1, BPI_PIN_DT2, BPI_PIN_DT3, BPI_PIN_DT4,
BPI_PIN_DT5, BPI_PIN_DT6, BPI_PIN_DT7, BPI_PIN_DP};
for (auto this_gpio : pintbl) {
int bank = SunXI::GPIO_BANK(this_gpio);
int offset = (SunXI::GPIO_NUM(this_gpio));
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;
gpio_data_masks[bank] |= (1 << offset);
}
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
}
bool GPIOBUS_BananaM2p::GetDP() const
@ -1058,6 +983,28 @@ void GPIOBUS_BananaM2p::sunxi_output_gpio(int pin, int value)
pio->DAT |= (1 << num);
}
void GPIOBUS_BananaM2p::sunxi_set_all_gpios(array<uint32_t, 12> &mask, array<uint32_t, 12> &value)
{
GPIO_FUNCTION_TRACE
for (size_t bank = 0; bank < mask.size(); bank++) {
if (mask[bank] == 0) {
continue;
}
volatile SunXI::sunxi_gpio_t *pio;
if (bank < 11) {
pio = &(pio_map->gpio_bank[bank]);
} else {
pio = &(r_pio_map->gpio_bank[bank - 11]);
}
uint32_t reg_val = pio->DAT;
reg_val &= ~mask[bank];
reg_val |= value[bank];
pio->DAT = reg_val;
}
}
int GPIOBUS_BananaM2p::sunxi_input_gpio(int pin) const
{
GPIO_FUNCTION_TRACE

View File

@ -124,7 +124,7 @@ class GPIOBUS_BananaM2p : public GPIOBUS
// Set SCSI I/O mode
int GetMode(int pin) override;
bool GetSignal(int pin) const override;
inline bool GetSignal(int pin) const override;
// Set SCSI output signal value
void SetSignal(int pin, bool ast) override;
@ -153,35 +153,12 @@ class GPIOBUS_BananaM2p : public GPIOBUS
bool SetupSelEvent();
#if !defined(__x86_64__) && !defined(__X86__)
uint32_t baseaddr = 0; // Base address
#endif
volatile uint32_t *gpio_map = nullptr;
// Timer control register
volatile uint32_t *tmr_ctrl;
#if !defined(__x86_64__) && !defined(__X86__)
volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register
#endif
volatile uint32_t *gicc = nullptr; // GIC CPU interface register
array<uint32_t, 4> gpfsel; // GPFSEL0-4 backup values
array<uint32_t, 12> signals = {0}; // All bus signals
#if SIGNAL_CONTROL_MODE == 0
array<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table
array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table
#else
array<uint32_t, 256> tblDatMsk = {}; // Data mask table
array<uint32_t, 256> tblDatSet = {}; // Table setting table
#endif
int sunxi_setup(void);
void sunxi_set_pullupdn(int gpio, int pud);
@ -206,13 +183,19 @@ class GPIOBUS_BananaM2p : public GPIOBUS
SBC_Version::sbc_version_type sbc_version;
SunXI::sunxi_gpio_reg_t saved_gpio_config;
static const array<int, 19> SignalTable;
void InitializeGpio();
std::vector<int> gpio_banks;
// Note: These MUST be in order from bit 0 to bit 7 with parity as the last item in the array
const array<int, 9> pintbl = {BPI_PIN_DT0, BPI_PIN_DT1, BPI_PIN_DT2, BPI_PIN_DT3, BPI_PIN_DT4,
BPI_PIN_DT5, BPI_PIN_DT6, BPI_PIN_DT7, BPI_PIN_DP};
void sunxi_set_all_gpios(array<uint32_t, 12> &mask, array<uint32_t, 12> &value);
array<uint32_t, 12> gpio_data_masks = {0};
#if defined(__x86_64__) || defined(__X86__) || defined(__aarch64__)
// The SEL_EVENT functions need to do something to prevent SonarCloud from
// claiming they should be const