1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-01-30 13:27:34 +00:00
Files
livingcomputermuseum.UniBone/10.01_base/2_src/arm/gpios.cpp
Joerg Hoppe 2530d9cbb5 Initial
2019-04-05 11:30:26 +02:00

882 lines
33 KiB
C++

/* gpios.cpp: UniBone functions for Non-PRU GPIOs
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
*/
#define _GPIOS_CPP_
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include "mailbox.h"
#include "utils.hpp"
#include "logsource.hpp"
#include "logger.hpp"
#include "bitcalc.h"
#include "gpios.hpp"
// see spruh73n.pdf
// address range of GPIO related registers. [spruh73n] page 181
#define GPIO_SIZE 0x1000 // size of each GPIO register range
#define GPIO0_START_ADDR 0x44E07000
#define GPIO1_START_ADDR 0x4804C000
#define GPIO2_START_ADDR 0x481AC000
#define GPIO3_START_ADDR 0x481AE000 // offset in each GPIO register range
#define GPIO_OE_ADDROFFSET 0x134
#define GPIO_DATAIN_ADDROFFSET 0x138
#define GPIO_DATAOUT_ADDROFFSET 0x13c
#define GPIO_SETDATAOUT_ADDROFFSET 0x194
#define GPIO_CLEARDATAOUT_ADDROFFSET 0x190
gpios_c *gpios; // Singleton
buslatches_t buslatches;
gpios_c::gpios_c() {
log_label = "GPIOS";
}
/* fill the 4 gpio_banks with values and
* map addresses
*/
void gpios_c::bank_map_registers(unsigned bank_idx, unsigned unmapped_start_addr) {
int fd;
gpio_bank_t *bank;
assert(bank_idx < 4);
fd = open((char*) "/dev/mem", O_RDWR);
if (!fd)
FATAL("Can not open /dev/mem");
bank = &(banks[bank_idx]);
bank->gpios_in_use = 0;
bank->registerrange_addr_unmapped = unmapped_start_addr; // info only
INFO("GPIO%d registers at %X - %X (size = %X)", bank_idx, unmapped_start_addr,
unmapped_start_addr + GPIO_SIZE - 1, GPIO_SIZE);
bank->registerrange_start_addr = (uint8_t *) mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, unmapped_start_addr);
if (bank->registerrange_start_addr == MAP_FAILED)
FATAL("Unable to map GPIO%d", bank_idx);
bank->oe_addr = (uint32_t *) (bank->registerrange_start_addr + GPIO_OE_ADDROFFSET);
bank->datain_addr = (uint32_t *) (bank->registerrange_start_addr + GPIO_DATAIN_ADDROFFSET);
bank->dataout_addr =
(uint32_t *) (bank->registerrange_start_addr + GPIO_DATAOUT_ADDROFFSET);
bank->setdataout_addr = (uint32_t *) (bank->registerrange_start_addr
+ GPIO_SETDATAOUT_ADDROFFSET);
bank->clrdataout_addr = (uint32_t *) (bank->registerrange_start_addr
+ GPIO_CLEARDATAOUT_ADDROFFSET);
}
gpio_config_t *gpios_c::config(const char *name, int direction, unsigned bank_idx,
unsigned pin_in_bank) {
gpio_config_t *result = (gpio_config_t *) malloc(sizeof(gpio_config_t));
if (name)
strcpy(result->name, name);
else
strcpy(result->name, "");
if (strlen(result->name) > 0)
result->internal = 0;
else
result->internal = 1;
result->direction = direction;
assert(bank_idx < 4);
result->bank_idx = bank_idx;
result->bank = &(banks[bank_idx]);
result->bank->gpios_in_use++;
result->pin_in_bank = pin_in_bank;
result->linear_no = 32 * bank_idx + pin_in_bank;
result->pin_in_bank_mask = 1 << pin_in_bank;
return result;
}
// "export" a pin over the sys file system
// this is necessary for GPIO2&3, despite we operate memory mapped.
void gpios_c::export_pin(gpio_config_t *pin) {
char fname[256];
FILE *f;
struct stat statbuff;
sprintf(fname, "/sys/class/gpio/export");
f = fopen(fname, "w");
if (!f)
FATAL("Can not open %s", fname);
fprintf(f, "%d\n", pin->linear_no);
fclose(f);
// verify: now there should appear the control directory for the pin
sprintf(fname, "/sys/class/gpio/gpio%d", pin->linear_no);
if (stat(fname, &statbuff) != 0 || !S_ISDIR(statbuff.st_mode))
FATAL("Gpio control dir %s not generated", fname);
}
/* export the NON-PRU pins: */
void gpios_c::init() {
unsigned n;
gpio_config_t *gpio;
bank_map_registers(0, GPIO0_START_ADDR);
bank_map_registers(1, GPIO1_START_ADDR);
bank_map_registers(2, GPIO2_START_ADDR);
bank_map_registers(3, GPIO3_START_ADDR);
// fill pin database
n = 0;
pins[n++] = led[0] = config("LED0", DIR_OUTPUT, 1, 0);
pins[n++] = led[1] = config("LED1", DIR_OUTPUT, 1, 1);
pins[n++] = led[2] = config("LED2", DIR_OUTPUT, 1, 2);
pins[n++] = led[3] = config("LED3", DIR_OUTPUT, 1, 3);
pins[n++] = swtch[0] = config("SW0", DIR_INPUT, 1, 4);
pins[n++] = swtch[1] = config("SW1", DIR_INPUT, 1, 5);
pins[n++] = swtch[2] = config("SW2", DIR_INPUT, 1, 6);
pins[n++] = swtch[3] = config("SW3", DIR_INPUT, 1, 7);
pins[n++] = button = config("BUTTON", DIR_INPUT, 1, 12);
pins[n++] = reg_enable = config("REG_ENABLE", DIR_OUTPUT, 1, 14);
pins[n++] = bus_enable = config("BUS_ENABLE", DIR_OUTPUT, 1, 13);
pins[n++] = i2c_panel_reset = config("PANEL_RESET", DIR_OUTPUT, 1, 28);
// double functions on header: P9.41 set other pin function to tristate
pins[n++] = collision_p9_41 = config(NULL, DIR_INPUT, 3, 20);
pins[n++] = collision_p9_42 = config(NULL, DIR_INPUT, 3, 18);
pins[n] = NULL; // end mark
// program pins registers
// echo no > /sys/class/gpio/export_pin
for (n = 0; (gpio = pins[n]); n++)
export_pin(gpio);
// set pin directions
// a) echo in|out > /sys/class/gpio/gpio<no>/direction
// b) bitmask in pin->gpio_bank_oe_addr
for (n = 0; (gpio = pins[n]); n++) {
unsigned reg = *(gpio->bank->oe_addr);
// bit set in OE register: pin is input.
reg &= ~gpio->pin_in_bank_mask; // clear bit
if (gpio->direction == DIR_INPUT)
reg |= gpio->pin_in_bank_mask;
*(gpio->bank->oe_addr) = reg;
}
// init output register cache with values (after export_pin!)
for (n = 0; n < 4; n++)
// bus error, if no gpio registered from this bank
if (banks[n].gpios_in_use > 0)
banks[n].cur_dataout_val = *(banks[n].dataout_addr);
// set the 4 LEDs to OFF
for (n = 0; n < 4; n++)
GPIO_SETVAL(led[n], 1)
; // inverted drivers
}
/*
* Toggle in high speed, break with ^C
*/
void gpios_c::test_toggle(gpio_config_t *gpio) {
INFO("Highspeed toggle pin %s, stop with ^C.", gpio->name);
// Setup ^C catcher
SIGINTcatchnext();
// high speed loop
while (!SIGINTreceived) {
// run, baby, run!
// the access macros:
GPIO_SETVAL(gpio, 1)
;
GPIO_SETVAL(gpio, 0)
;
// fastest possible:
// *(gpio->bank->setdataout_addr) = gpio->pin_in_bank_mask;
//*(gpio->bank->clrdataout_addr) = gpio->pin_in_bank_mask;
}
}
/* visible loop back
* Switches control LEDs
* Button controls UNIBUS reg_enable
*/
void gpios_c::test_loopback(void) {
timeout_c timeout;
INFO("Manual loopback test, stop with ^C");
INFO("Switch control LEDs, button controls \"UNIBUS enable\".");
// Setup ^C catcher
SIGINTcatchnext();
// high speed loop
while (!SIGINTreceived) {
GPIO_SETVAL(led[0], GPIO_GETVAL(swtch[0]));
GPIO_SETVAL(led[1], GPIO_GETVAL(swtch[1]));
GPIO_SETVAL(led[2], GPIO_GETVAL(swtch[2]));
GPIO_SETVAL(led[3], GPIO_GETVAL(swtch[3]));
GPIO_SETVAL(bus_enable, GPIO_GETVAL(button));
timeout.wait_ms(10);
}
}
/* return a string with board signal path for an UNIBUS signal
* used as error info for loopback failures
*/
buslatches_signal_info_t buslatches_signal_info[] = { //
//
// Register 0 write (PRU -> 74LS377 -> DS8641)
{ 0, 0, 0, 1, "BG4_OUT",
"P9.31 -> J10.1 DATOUT_0 -> U05.03 -> U05.02 -> U08.14 -> U08.15 -> BG4_OUT" }, //
{ 0, 1, 0, 1, "BG5_OUT",
"P9.29 -> J10.2 DATOUT_1 -> U05.04 -> U05.05 -> U08.11 -> U08.12 -> BG5_OUT" }, //
{ 0, 2, 0, 1, "BG6_OUT",
"P9.30 -> J10.3 DATOUT_2 -> U05.07 -> U05.06 -> U08.02 -> U08.01 -> BG6_OUT" }, //
{ 0, 3, 0, 1, "BG7_OUT",
"P9.28 -> J10.4 DATOUT_3 -> U05.08 -> U05.09 -> U08.05 -> U08.04 -> BG7_OUT" }, //
{ 0, 4, 0, 1, "NPG_OUT",
"P9.42 -> J10.5 DATOUT_4 -> U05.13 -> U05.12 -> U07.14 -> U07.15 -> NPG_OUT" }, //
{ 0, 5, 0, 0, "n.c.",
"P9.27 -> J10.6 DATOUT_5 -> U05.14 -> U05.15 -> U07.11 -> U07.12 -> n.c." },//
{ 0, 6, 0, 0, "n.c.",
"P9.41 -> J10.7 DATOUT_6 -> U05.17 -> U05.16 -> U07.02 -> U07.01 -> n.c." },//
{ 0, 7, 0, 0, "n.c.",
"P9.25 -> J10.8 DATOUT_7 -> U05.18 -> U05.19 -> U07.05 -> U07.04 -> n.c." },//
//
// Register 0 read (PRU <- 74LVTH541 <- 74LS244)
{ 0, 0, 1, 0, "BG4",
"P8.45 <- J17.1 DATIN_0 <- U04.18 <- U04.02 <- U06.18 <- U06.02 <- BG4_IN" },//
{ 0, 1, 1, 0, "BG5",
"P8.46 <- J17.2 DATIN_1 <- U04.17 <- U04.03 <- U06.16 <- U06.04 <- BG5_IN" },//
{ 0, 2, 1, 0, "BG6",
"P8.43 <- J17.3 DATIN_2 <- U04.16 <- U04.04 <- U06.14 <- U06.06 <- BG6_IN" },//
{ 0, 3, 1, 0, "BG7",
"P8.44 <- J17.4 DATIN_3 <- U04.15 <- U04.05 <- U06.12 <- U06.08 <- BG7_IN" },//
{ 0, 4, 1, 0, "NPG",
"P8.41 <- J17.5 DATIN_4 <- U04.14 <- U04.06 <- U06.09 <- U06.11 <- NPG_IN" },//
{ 0, 5, 1, 0, "LTC",
"P8.42 <- J17.6 DATIN_5 <- U04.13 <- U04.07 <- U06.07 <- U06.13 <- LTC" },//
{ 0, 6, 1, 0, "n.c.",
"P8.39 <- J17.7 DATIN_6 <- U04.12 <- U04.08 <- U06.05 <- U06.15 <- n.c." }, //
{ 0, 7, 1, 0, "n.c.",
"P8.40 <- J17.8 DATIN_7 <- U04.11 <- U04.09 <- U06.03 <- U06.13 <- n.c." }, //
//
// Register 1 write (PRU -> 74LS377 -> DS8641)
{ 1, 0, 0, 0, "BR4",
"P9.31 -> J10.1 DATOUT_0 -> U30.03 -> U30.02 -> U31.14 -> U31.15 -> BR4" }, //
{ 1, 1, 0, 0, "BR5",
"P9.29 -> J10.2 DATOUT_1 -> U30.04 -> U30.05 -> U31.11 -> U31.12 -> BR5" }, //
{ 1, 2, 0, 0, "BR6",
"P9.30 -> J10.3 DATOUT_2 -> U30.07 -> U30.06 -> U31.02 -> U31.01 -> BR6" }, //
{ 1, 3, 0, 0, "BR7",
"P9.28 -> J10.4 DATOUT_3 -> U30.08 -> U30.09 -> U31.05 -> U31.04 -> BR7" }, //
{ 1, 4, 0, 0, "NPR",
"P9.42 -> J10.5 DATOUT_4 -> U30.13 -> U30.12 -> U32.14 -> U32.15 -> NPR" }, //
{ 1, 5, 0, 0, "SACK",
"P9.27 -> J10.6 DATOUT_5 -> U30.14 -> U30.15 -> U32.11 -> U32.12 -> SACK" },//
{ 1, 6, 0, 0, "BBSY",
"P9.41 -> J10.7 DATOUT_6 -> U30.17 -> U30.16 -> U32.02 -> U32.01 -> BBSY" },//
{ 1, 7, 0, 0, "n.c.",
"P9.25 -> J10.8 DATOUT_7 -> U30.18 -> U30.19 -> U32.05 -> U32.04 -> n.c." },//
//
// Register 1 read (PRU <- 74LVTH541 <- DS8641)
{ 1, 0, 1, 0, "BR4",
"P8.45 <- J17.1 DATIN_0 <- U29.18 <- U29.02 <- U31.13 <- U31.15 <- BR4" },//
{ 1, 1, 1, 0, "BR5",
"P8.46 <- J17.2 DATIN_1 <- U29.17 <- U29.03 <- U31.10 <- U31.12 <- BR5" },//
{ 1, 2, 1, 0, "BR6",
"P8.43 <- J17.3 DATIN_2 <- U29.16 <- U29.04 <- U31.03 <- U31.01 <- BR6" },//
{ 1, 3, 1, 0, "BR7",
"P8.44 <- J17.4 DATIN_3 <- U29.15 <- U29.05 <- U31.06 <- U31.04 <- BR7" },//
{ 1, 4, 1, 0, "NPR",
"P8.41 <- J17.5 DATIN_4 <- U29.14 <- U29.06 <- U32.13 <- U32.15 <- NPR" },//
{ 1, 5, 1, 0, "SACK",
"P8.42 <- J17.6 DATIN_5 <- U29.13 <- U29.07 <- U32.10 <- U32.12 <- SACK" }, //
{ 1, 6, 1, 0, "BBSY",
"P8.39 <- J17.7 DATIN_6 <- U29.12 <- U29.08 <- U32.03 <- U32.01 <- BBSY" }, //
{ 1, 7, 1, 0, "n.c.",
"P8.40 <- J17.8 DATIN_7 <- U29.11 <- U29.09 <- U32.06 <- U32.04 <- n.c." }, //
//
// Register 2 write (PRU -> 74LS377 -> DS8641)
{ 2, 0, 0, 0, "A00",
"P9.31 -> J10.1 DATOUT_0 -> U10.03 -> U10.02 -> U11.14 -> U11.15 -> A00" }, //
{ 2, 1, 0, 0, "A01",
"P9.29 -> J10.2 DATOUT_1 -> U10.04 -> U10.05 -> U11.11 -> U11.12 -> A01" }, //
{ 2, 2, 0, 0, "A02",
"P9.30 -> J10.3 DATOUT_2 -> U10.07 -> U10.06 -> U11.02 -> U11.01 -> A02" }, //
{ 2, 3, 0, 0, "A03",
"P9.28 -> J10.4 DATOUT_3 -> U10.08 -> U10.09 -> U11.05 -> U11.04 -> A03" }, //
{ 2, 4, 0, 0, "A04",
"P9.42 -> J10.5 DATOUT_4 -> U10.13 -> U10.12 -> U12.14 -> U12.15 -> A04" }, //
{ 2, 5, 0, 0, "A05",
"P9.27 -> J10.6 DATOUT_5 -> U10.14 -> U10.15 -> U12.11 -> U12.12 -> A05" }, //
{ 2, 6, 0, 0, "A06",
"P9.41 -> J10.7 DATOUT_6 -> U10.17 -> U10.16 -> U12.02 -> U12.01 -> A06" }, //
{ 2, 7, 0, 0, "A07",
"P9.25 -> J10.8 DATOUT_7 -> U10.18 -> U10.19 -> U12.05 -> U12.04 -> A07" }, //
//
// Register 2 read (PRU <- 74LVTH541 <- DS8641)
{ 2, 0, 1, 0, "A00",
"P8.45 <- J17.1 DATIN_0 <- U09.18 <- U09.02 <- U11.13 <- U11.15 <- A00" },//
{ 2, 1, 1, 0, "A01",
"P8.46 <- J17.2 DATIN_1 <- U09.17 <- U09.03 <- U11.10 <- U11.12 <- A01" },//
{ 2, 2, 1, 0, "A02",
"P8.43 <- J17.3 DATIN_2 <- U09.16 <- U09.04 <- U11.03 <- U11.01 <- A02" },//
{ 2, 3, 1, 0, "A03",
"P8.44 <- J17.4 DATIN_3 <- U09.15 <- U09.05 <- U11.06 <- U11.04 <- A03" },//
{ 2, 4, 1, 0, "A04",
"P8.41 <- J17.5 DATIN_4 <- U09.14 <- U09.06 <- U12.13 <- U12.15 <- A04" },//
{ 2, 5, 1, 0, "A05",
"P8.42 <- J17.6 DATIN_5 <- U09.13 <- U09.07 <- U12.10 <- U12.12 <- A05" },//
{ 2, 6, 1, 0, "A06",
"P8.39 <- J17.7 DATIN_6 <- U09.12 <- U09.08 <- U12.03 <- U12.01 <- A06" },//
{ 2, 7, 1, 0, "A07",
"P8.40 <- J17.8 DATIN_7 <- U09.11 <- U09.09 <- U12.06 <- U12.04 <- A07" },//
//
// Register 3 write (PRU -> 74LS377 -> DS8641)
{ 3, 0, 0, 0, "A08",
"P9.31 -> J10.1 DATOUT_0 -> U14.03 -> U14.02 -> U15.14 -> U15.15 -> A08" }, //
{ 3, 1, 0, 0, "A09",
"P9.29 -> J10.2 DATOUT_1 -> U14.04 -> U14.05 -> U15.11 -> U15.12 -> A09" }, //
{ 3, 2, 0, 0, "A10",
"P9.30 -> J10.3 DATOUT_2 -> U14.07 -> U14.06 -> U15.02 -> U15.01 -> A10" }, //
{ 3, 3, 0, 0, "A11",
"P9.28 -> J10.4 DATOUT_3 -> U14.08 -> U14.09 -> U15.05 -> U15.04 -> A11" }, //
{ 3, 4, 0, 0, "A12",
"P9.42 -> J10.5 DATOUT_4 -> U14.13 -> U14.12 -> U16.14 -> U16.15 -> A12" }, //
{ 3, 5, 0, 0, "A13",
"P9.27 -> J10.6 DATOUT_5 -> U14.14 -> U14.15 -> U16.11 -> U16.12 -> A13" }, //
{ 3, 6, 0, 0, "A14",
"P9.41 -> J10.7 DATOUT_6 -> U14.17 -> U14.16 -> U16.02 -> U16.01 -> A14" }, //
{ 3, 7, 0, 0, "A15",
"P9.25 -> J10.8 DATOUT_7 -> U14.18 -> U14.19 -> U16.05 -> U16.04 -> A15" }, //
//
// Register 3 read (PRU <- 74LVTH541 <- DS8641)
{ 3, 0, 1, 0, "A08",
"P8.45 <- J17.1 DATIN_0 <- U13.18 <- U13.02 <- U15.13 <- U15.15 <- A08" },//
{ 3, 1, 1, 0, "A09",
"P8.46 <- J17.2 DATIN_1 <- U13.17 <- U13.03 <- U15.10 <- U15.12 <- A09" },//
{ 3, 2, 1, 0, "A10",
"P8.43 <- J17.3 DATIN_2 <- U13.16 <- U13.04 <- U15.03 <- U15.01 <- A10" },//
{ 3, 3, 1, 0, "A11",
"P8.44 <- J17.4 DATIN_3 <- U13.15 <- U13.05 <- U15.06 <- U15.04 <- A11" },//
{ 3, 4, 1, 0, "A12",
"P8.41 <- J17.5 DATIN_4 <- U13.14 <- U13.06 <- U16.13 <- U16.15 <- A12" },//
{ 3, 5, 1, 0, "A13",
"P8.42 <- J17.6 DATIN_5 <- U13.13 <- U13.07 <- U16.10 <- U16.12 <- A13" },//
{ 3, 6, 1, 0, "A14",
"P8.39 <- J17.7 DATIN_6 <- U13.12 <- U13.08 <- U16.03 <- U16.01 <- A14" },//
{ 3, 7, 1, 0, "A15",
"P8.40 <- J17.8 DATIN_7 <- U13.11 <- U13.09 <- U16.06 <- U16.04 <- A15" },//
//
// Register 4 write (PRU -> 74LS377 -> DS8641)
{ 4, 0, 0, 0, "A16",
"P9.31 -> J10.1 DATOUT_0 -> U26.03 -> U26.02 -> U27.14 -> U27.15 -> A16" }, //
{ 4, 1, 0, 0, "A17",
"P9.29 -> J10.2 DATOUT_1 -> U26.04 -> U26.05 -> U27.11 -> U27.12 -> A17" }, //
{ 4, 2, 0, 0, "C0",
"P9.30 -> J10.3 DATOUT_2 -> U26.07 -> U26.06 -> U27.02 -> U27.01 -> C0" },//
{ 4, 3, 0, 0, "C1",
"P9.28 -> J10.4 DATOUT_3 -> U26.08 -> U26.09 -> U27.05 -> U27.04 -> C1" },//
{ 4, 4, 0, 0, "MSYN",
"P9.42 -> J10.5 DATOUT_4 -> U26.13 -> U26.12 -> U28.14 -> U28.15 -> MSYN" },//
{ 4, 5, 0, 0, "SSYN",
"P9.27 -> J10.6 DATOUT_5 -> U26.14 -> U26.15 -> U28.11 -> U28.12 -> SSYN" },//
{ 4, 6, 0, 0, "n.c.",
"P9.41 -> J10.7 DATOUT_6 -> U26.17 -> U26.16 -> U28.02 -> U28.01 -> n.c." },//
{ 4, 7, 0, 0, "n.c.",
"P9.25 -> J10.8 DATOUT_7 -> U26.18 -> U26.19 -> U28.05 -> U28.04 -> n.c." },//
//
// Register 4 read (PRU <- 74LVTH541 <- DS8641)
{ 4, 0, 1, 0, "A16",
"P8.45 <- J17.1 DATIN_0 <- U13.18 <- U13.02 <- U27.13 <- U27.15 <- A16" },//
{ 4, 1, 1, 0, "A17",
"P8.46 <- J17.2 DATIN_1 <- U13.17 <- U13.03 <- U27.10 <- U27.12 <- A17" },//
{ 4, 2, 1, 0, "C0",
"P8.43 <- J17.3 DATIN_2 <- U13.16 <- U13.04 <- U27.03 <- U27.01 <- C0" },//
{ 4, 3, 1, 0, "C1",
"P8.44 <- J17.4 DATIN_3 <- U13.15 <- U13.05 <- U27.06 <- U27.04 <- C1" },//
{ 4, 4, 1, 0, "MSYN",
"P8.41 <- J17.5 DATIN_4 <- U25.14 <- U25.06 <- U28.13 <- U28.15 <- MSYN" }, //
{ 4, 5, 1, 0, "SSYN",
"P8.42 <- J17.6 DATIN_5 <- U25.13 <- U25.07 <- U28.10 <- U28.12 <- SSYN" }, //
{ 4, 6, 1, 0, "n.c.",
"P8.39 <- J17.7 DATIN_6 <- U25.12 <- U25.08 <- U28.03 <- U28.01 <- n.c." }, //
{ 4, 7, 1, 0, "n.c.",
"P8.40 <- J17.8 DATIN_7 <- U25.11 <- U25.09 <- U28.06 <- U28.04 <- n.c." }, //
//
// Register 5 write (PRU -> 74LS377 -> DS8641)
{ 5, 0, 0, 0, "D00",
"P9.31 -> J10.1 DATOUT_0 -> U18.03 -> U18.02 -> U19.14 -> U19.15 -> D00" }, //
{ 5, 1, 0, 0, "D01",
"P9.29 -> J10.2 DATOUT_1 -> U18.04 -> U18.05 -> U19.11 -> U19.12 -> D01" }, //
{ 5, 2, 0, 0, "D02",
"P9.30 -> J10.3 DATOUT_2 -> U18.07 -> U18.06 -> U19.02 -> U19.01 -> D02" }, //
{ 5, 3, 0, 0, "D03",
"P9.28 -> J10.4 DATOUT_3 -> U18.08 -> U18.09 -> U19.05 -> U19.04 -> D03" }, //
{ 5, 4, 0, 0, "D04",
"P9.42 -> J10.5 DATOUT_4 -> U18.13 -> U18.12 -> U20.14 -> U20.15 -> D04" }, //
{ 5, 5, 0, 0, "D05",
"P9.27 -> J10.6 DATOUT_5 -> U18.14 -> U18.15 -> U20.11 -> U20.12 -> D05" }, //
{ 5, 6, 0, 0, "D06",
"P9.41 -> J10.7 DATOUT_6 -> U18.17 -> U18.16 -> U20.02 -> U20.01 -> D06" }, //
{ 5, 7, 0, 0, "D07",
"P9.25 -> J10.8 DATOUT_7 -> U18.18 -> U18.19 -> U20.05 -> U20.04 -> D07" }, //
//
// Register 5 read (PRU <- 74LVTH541 <- DS8641)
{ 5, 0, 1, 0, "D00",
"P8.45 <- J17.1 DATIN_0 <- U17.18 <- U17.02 <- U19.13 <- U19.15 <- D00" },//
{ 5, 1, 1, 0, "D01",
"P8.46 <- J17.2 DATIN_1 <- U17.17 <- U17.03 <- U19.10 <- U19.12 <- D01" },//
{ 5, 2, 1, 0, "D02",
"P8.43 <- J17.3 DATIN_2 <- U17.16 <- U17.04 <- U19.03 <- U19.01 <- D02" },//
{ 5, 3, 1, 0, "D03",
"P8.44 <- J17.4 DATIN_3 <- U17.15 <- U17.05 <- U19.06 <- U19.04 <- D03" },//
{ 5, 4, 1, 0, "D04",
"P8.41 <- J17.5 DATIN_4 <- U17.14 <- U17.06 <- U20.13 <- U20.15 <- D04" },//
{ 5, 5, 1, 0, "D05",
"P8.42 <- J17.6 DATIN_5 <- U17.13 <- U17.07 <- U20.10 <- U20.12 <- D05" },//
{ 5, 6, 1, 0, "D06",
"P8.39 <- J17.7 DATIN_6 <- U17.12 <- U17.08 <- U20.03 <- U20.01 <- D06" },//
{ 5, 7, 1, 0, "D07",
"P8.40 <- J17.8 DATIN_7 <- U17.11 <- U17.09 <- U20.06 <- U20.04 <- D07" },//
//
// Register 6 write (PRU -> 74LS377 -> DS8641)
{ 6, 0, 0, 0, "D08",
"P9.31 -> J10.1 DATOUT_0 -> U22.03 -> U22.02 -> U23.14 -> U23.15 -> D08" }, //
{ 6, 1, 0, 0, "D09",
"P9.29 -> J10.2 DATOUT_1 -> U22.04 -> U22.05 -> U23.11 -> U23.12 -> D09" }, //
{ 6, 2, 0, 0, "D10",
"P9.30 -> J10.3 DATOUT_2 -> U22.07 -> U22.06 -> U23.02 -> U23.01 -> D10" }, //
{ 6, 3, 0, 0, "D11",
"P9.28 -> J10.4 DATOUT_3 -> U22.08 -> U22.09 -> U23.05 -> U23.04 -> D11" }, //
{ 6, 4, 0, 0, "D12",
"P9.42 -> J10.5 DATOUT_4 -> U22.13 -> U22.12 -> U24.14 -> U24.15 -> D12" }, //
{ 6, 5, 0, 0, "D13",
"P9.27 -> J10.6 DATOUT_5 -> U22.14 -> U22.15 -> U24.11 -> U24.12 -> D13" }, //
{ 6, 6, 0, 0, "D14",
"P9.41 -> J10.7 DATOUT_6 -> U22.17 -> U22.16 -> U24.02 -> U24.01 -> D14" }, //
{ 6, 7, 0, 0, "D15",
"P9.25 -> J10.8 DATOUT_7 -> U22.18 -> U22.19 -> U24.05 -> U24.04 -> D15" }, //
//
// Register 6 read (PRU <- 74LVTH541 <- DS8641)
{ 6, 0, 1, 0, "D08",
"P8.45 <- J17.1 DATIN_0 <- U21.18 <- U21.02 <- U23.13 <- U23.15 <- D08" },//
{ 6, 1, 1, 0, "D09",
"P8.46 <- J17.2 DATIN_1 <- U21.17 <- U21.03 <- U23.10 <- U23.12 <- D09" },//
{ 6, 2, 1, 0, "D10",
"P8.43 <- J17.3 DATIN_2 <- U21.16 <- U21.04 <- U23.03 <- U23.01 <- D10" },//
{ 6, 3, 1, 0, "D11",
"P8.44 <- J17.4 DATIN_3 <- U21.15 <- U21.05 <- U23.06 <- U23.04 <- D11" },//
{ 6, 4, 1, 0, "D12",
"P8.41 <- J17.5 DATIN_4 <- U21.14 <- U21.06 <- U24.13 <- U24.15 <- D12" },//
{ 6, 5, 1, 0, "D13",
"P8.42 <- J17.6 DATIN_5 <- U21.13 <- U21.07 <- U24.10 <- U24.12 <- D13" },//
{ 6, 6, 1, 0, "D14",
"P8.39 <- J17.7 DATIN_6 <- U21.12 <- U21.08 <- U24.03 <- U24.01 <- D14" },//
{ 6, 7, 1, 0, "D15",
"P8.40 <- J17.8 DATIN_7 <- U21.11 <- U21.09 <- U24.06 <- U24.04 <- D15" },//
//
// Register 7 write (PRU -> 74LS377 -> DS8641)
{ 7, 0, 0, 0, "INTR",
"P9.31 -> J10.1 DATOUT_0 -> U34.03 -> U34.02 -> U35.14 -> U35.15 -> INTR" },//
{ 7, 1, 0, 0, "PA",
"P9.29 -> J10.2 DATOUT_1 -> U34.04 -> U34.05 -> U35.11 -> U35.12 -> PA" },//
{ 7, 2, 0, 0, "PB",
"P9.30 -> J10.3 DATOUT_2 -> U34.07 -> U34.06 -> U35.02 -> U35.01 -> PB" },//
{ 7, 3, 0, 0, "INIT",
"P9.28 -> J10.4 DATOUT_3 -> U34.08 -> U34.09 -> U35.05 -> U35.04 -> INIT" },//
{ 7, 4, 0, 0, "ACLO",
"P9.42 -> J10.5 DATOUT_4 -> U34.13 -> U34.12 -> U36.14 -> U36.15 -> ACLO" },//
{ 7, 5, 0, 0, "DCLO",
"P9.27 -> J10.6 DATOUT_5 -> U34.14 -> U34.15 -> U36.11 -> U36.12 -> DCLO" },//
{ 7, 6, 0, 0, "n.c.",
"P9.41 -> J10.7 DATOUT_6 -> U34.17 -> U34.16 -> U36.02 -> U36.01 -> n.c." },//
{ 7, 7, 0, 0, "n.c.",
"P9.25 -> J10.8 DATOUT_7 -> U34.18 -> U34.19 -> U36.05 -> U36.04 -> n.c." },//
//
// Register 7 read (PRU <- 74LVTH541 <- DS8641)
{ 7, 0, 1, 0, "INTR",
"P8.45 <- J17.1 DATIN_0 <- U33.18 <- U33.02 <- U35.13 <- U35.15 <- INTR" }, //
{ 7, 1, 1, 0, "PA",
"P8.46 <- J17.2 DATIN_1 <- U33.17 <- U33.03 <- U35.10 <- U35.12 <- PA" },//
{ 7, 2, 1, 0, "PB",
"P8.43 <- J17.3 DATIN_2 <- U33.16 <- U33.04 <- U35.03 <- U35.01 <- PB" },//
{ 7, 3, 1, 0, "INIT",
"P8.44 <- J17.4 DATIN_3 <- U33.15 <- U33.05 <- U35.06 <- U35.04 <- INIT" }, //
{ 7, 4, 1, 0, "ACLO",
"P8.41 <- J17.5 DATIN_4 <- U33.14 <- U33.06 <- U36.13 <- U36.15 <- ACLO" }, //
{ 7, 5, 1, 0, "DCLO",
"P8.42 <- J17.6 DATIN_5 <- U33.13 <- U33.07 <- U36.10 <- U36.12 <- DCLO" }, //
{ 7, 6, 1, 0, "n.c.",
"P8.39 <- J17.7 DATIN_6 <- U33.12 <- U33.08 <- U36.03 <- U36.01 <- n.c." }, //
{ 7, 7, 1, 0, "n.c.",
"P8.40 <- J17.8 DATIN_7 <- U33.11 <- U33.09 <- U36.06 <- U36.04 <- n.c." }, //
{ 0, 0, 0, 0, NULL, NULL } // End mark
};
// search a register bit by UNIBUS signal name and direction
buslatches_signal_info_t *buslatches_get_signal_info(const char *unibus_name,
unsigned is_input) {
unsigned i;
buslatches_signal_info_t *si;
for (i = 0; (si = &buslatches_signal_info[i]) && si->path; i++)
if (si->is_input == is_input && !strcasecmp(si->unibus_name, unibus_name))
return si;
return NULL; // not found
}
// print info for a loop back mismatch bitmask
static void buslatches_print_signal_path(unsigned reg, unsigned mismatch_bitmask) {
unsigned bit;
unsigned bitmask;
unsigned i;
buslatches_signal_info_t *si;
for (bit = 0; bit < 8; bit++) {
bitmask = 1 << bit;
if (mismatch_bitmask & bitmask) {
// search for write path
printf("Signal path for bus latch %u, bit %u (mask 0x%02x):\n", reg, bit,
(1 << bit));
for (i = 0; (si = &buslatches_signal_info[i]) && si->path; i++)
if (si->reg_sel == reg && !si->is_input && si->bit_nr == bit)
printf(" Write: %s\n", si->path);
for (i = 0; (si = &buslatches_signal_info[i]) && si->path; i++)
if (si->reg_sel == reg && si->is_input && si->bit_nr == bit)
printf(" Read : %s\n", si->path);
}
}
}
// enable=1: activate UNIBUS drivers
// can be called BEFORE buslatches_init()
void buslatches_output_enable(bool enable) {
enable = !!enable;
GPIO_SETVAL(gpios->bus_enable, enable);
buslatches.cur_output_enable = enable;
}
// register signals to standard
// all outputs to standard:
// init state
// UNIBUS lines all H / only BR4567, NPR_OUT auf LOW
void buslatches_init() {
unsigned i;
// chips are all 8bit width, but not all input/outputs are
// connected to bidirektional terminated UNIBUs lines.
// see PCB schematic!
buslatches.bidi_bitwidth[0] = 5; // BG4567, NPG
// LTC on .6 ignored, is input only
buslatches.bidi_bitwidth[1] = 7; // BR4..BR7,NPR,SACK,BBSY
buslatches.bidi_bitwidth[2] = 8; // addresses 0..7 ;
buslatches.bidi_bitwidth[3] = 8; // addresses 8..15
buslatches.bidi_bitwidth[4] = 6; // A16,17,C0,C1, MSYN,SSYN
buslatches.bidi_bitwidth[5] = 8; // data 0..7
buslatches.bidi_bitwidth[6] = 8; // data 8..15
buslatches.bidi_bitwidth[7] = 6; // INTR,PA,PB,INIT,ACLO,DCLO
for (i = 0; i < 8; i++) {
buslatches.read_inverted[i] = false;
buslatches.bidi_bitmask[i] = BitmaskFromLen32[buslatches.bidi_bitwidth[i]];
}
// BG4567, NPG are read back non inverted from UNIBUS
buslatches.read_inverted[0] = true;
// PRU1 does it
mailbox_execute(ARM2PRU_BUSLATCH_INIT, ARM2PRU_NONE);
}
// read the REG_DATIN[0..7] pins
// highly optimized, to reduce access to memory mapped gpio registers
unsigned buslatches_getval(unsigned reg_sel) {
// PRU1 does it
mailbox->buslatch.addr = reg_sel;
while (mailbox->buslatch.addr != reg_sel)
; // cache !
mailbox_execute(ARM2PRU_BUSLATCH_GET, ARM2PRU_NONE);
return mailbox->buslatch.val; // PRU1 has put the result here
}
// write the REG_DATOUT[0..7] pins into one latch
// only bits "bitmask" are written
void buslatches_setval(unsigned reg_sel, unsigned bitmask, unsigned val) {
mailbox->buslatch.addr = reg_sel;
mailbox->buslatch.bitmask = bitmask & 0xff;
mailbox->buslatch.val = val;
mailbox_execute(ARM2PRU_BUSLATCH_SET, ARM2PRU_NONE);
}
// some pattern tests on a register latch
// register is set, drives UNIBUS lines, and is
// immediately read back and compared.
// pattern:
// 1: count upwards
// 2: moving one
// 3: moving zero
// 4: toggle between 0x00 and 0xff
// 5: random values
// read back and compare values
// stop with ^C
void buslatches_test_simple_pattern(unsigned pattern, unsigned reg_sel) {
unsigned idx, setval = 0, chkval;
unsigned bitwidth, bitmask;
unsigned count;
assert(reg_sel < 8);
bitwidth = buslatches.bidi_bitwidth[reg_sel];
bitmask = buslatches.bidi_bitmask[reg_sel];
switch (pattern) {
case 1:
printf("Highspeed count register latch %d, stop with ^C.\n", reg_sel);
break;
case 2:
printf("Highspeed \"moving ones\" in register latch %d, stop with ^C.\n", reg_sel);
break;
case 3:
printf("Highspeed \"moving zeros\" in register latch %d, stop with ^C.\n", reg_sel);
break;
case 4:
printf("Highspeed toggle 0x00 - 0xff in register latch %d, stop with ^C.\n", reg_sel);
break;
case 5:
printf("Highspeed random values in register latch %d, stop with ^C.\n", reg_sel);
break;
}
// Setup ^C catcher
SIGINTcatchnext();
// high speed loop
idx = 0;
count = 0;
while (!SIGINTreceived) {
/* 1. generate pattern */
switch (pattern) {
case 1: // count upwards
setval = idx;
idx = (idx + 1) & bitmask; // period = bitwidth
break;
case 2: // moving ones
setval = (1 << idx);
idx = (idx + 1) % bitwidth; // period = bitwidth
break;
case 3: // moving zeros
setval = ~(1 << idx);
idx = (idx + 1) % bitwidth; // period = bitwidth
break;
case 4: // toggle 0x00 0xff
setval = idx & 1 ? 0x00 : 0xff; // period = 2
idx = !idx;
break;
case 5:
setval = rand() & 0xff; // slow?
break;
}
/* 2. write pattern into output latches. */
setval &= bitmask; // do not test unconnected lines
buslatches_setval(reg_sel, 0xff, setval);
/* 3. read back pattern in output latches over UNIBUS into input muxes */
chkval = buslatches_getval(reg_sel);
if (buslatches.read_inverted[reg_sel])
chkval = ~chkval; // input latches invert
chkval &= bitmask;
if (chkval != setval) {
printf("pass %u test_register_simple_pattern(%d, %d): wrote 0x%x, read 0x%x\n",
count, pattern, reg_sel, setval, chkval);
if (reg_sel == 0) {
printf("Testing BR*,NPR with BG*,NPG feedback.\n");
printf("Are there 5*3 jumpers in the \"||\"\n");
printf(" \"--\" position?\n");
}
buslatches_print_signal_path(reg_sel, setval ^ chkval);
return;
}
count++;
}
printf("\n%u tests successful.\n", count);
}
void buslatches_test_simple_pattern_multi(unsigned reg_first, unsigned reg_last,
unsigned pattern) {
unsigned reg_count = reg_last - reg_first + 1;
unsigned testno; // global test number counter
unsigned i;
unsigned testval[8]; // test data for all latches
switch (pattern) {
// case 1:
// printf("Highspeed count register latch %d, stop with ^C.\n", reg_sel);
// break;
case 2:
printf("Highspeed \"moving ones\" in register latches %d-%d, stop with ^C.\n",
reg_first, reg_last);
break;
case 3:
printf("Highspeed \"moving zeros\" in register latches %d-%d, stop with ^C.\n",
reg_first, reg_last);
break;
case 4:
printf("Highspeed toggle 0x00 - 0xff in register latches %d-%d, stop with ^C.\n",
reg_first, reg_last);
break;
case 5:
printf("Highspeed random values in register latches %d-%d, stop with ^C.\n", reg_first,
reg_last);
break;
default:
printf("Error: unknown test pattern %u.\n", pattern);
}
testno = 0;
// Setup ^C catcher
SIGINTcatchnext();
// high speed loop
while (!SIGINTreceived) {
// 1 cycle = 8 bits of 8 registers
// some tests are no-op because of reduced bitwidth
/* 1. generate pattern */
for (i = reg_first; i <= reg_last; i++) {
switch (pattern) {
case 2: { // moving ones
unsigned bitidx = testno % 8; // circle all 8 bits per register
unsigned regidx = reg_first + ((testno / 8) % reg_count); // circle all registers
// set only one bit
if (i == regidx)
testval[i] = 1 << bitidx;
else
testval[i] = 0;
break;
}
case 3: { // moving zeros
// clear only one bit
unsigned bitidx = testno % 8; // circle all 8 bits per register
unsigned regidx = reg_first + ((testno / 8) % reg_count); // circle all registers
if (i == regidx)
testval[i] = ~(1 << bitidx);
else
testval[i] = 0xff;
break;
}
case 4: // toggle all regs simultaneously 0x00, 0xff, 0xff, ...
if (testno & 1)
testval[i] = 0xff;
else
testval[i] = 0x00;
break;
case 5:
testval[i] = rand() & 0xff; // slow?
break;
default:
printf("Error: unknown test pattern %u.\n", pattern);
}
// mask out unimplemented bits
testval[i] &= buslatches.bidi_bitmask[i];
}
/* 2. write pattern into output latches.
* Also write unused bits */
for (i = reg_first; i <= reg_last; i++)
buslatches_setval(i, 0xff, testval[i]);
/* 3. read back pattern in output latches over UNIBUS into input muxes */
for (i = reg_first; i <= reg_last; i++) {
unsigned bitmask = buslatches.bidi_bitmask[i];
unsigned chkval = buslatches_getval(i);
if (buslatches.read_inverted[i])
chkval = ~chkval; // input latches invert
chkval &= bitmask;
if (chkval != testval[i]) {
printf(
"Error buslatches_test_simple_pattern_multi(regs=%u-%u,pattern=%d), pass %u:\n",
reg_first, reg_last, pattern, testno);
printf(" register %u: wrote 0x%x, read back 0x%x\n", i, testval[i], chkval);
if (i == 0) {
printf("Testing BR*,NPR with BG*,NPG feedback.\n");
printf("Are there 5*3 jumpers in the \"||\"\n");
printf(" \"--\" position?\n");
}
buslatches_print_signal_path(i, testval[i] ^ chkval);
return;
}
}
testno++;
}
printf("\n%u tests successful.\n", testno);
}
/* stress test on highspeed timing
* PRU generates max speed reaed/write sequences on
// ADDR<0:7>, ADDR <8:15>, DATA<0:7> and <DATA8:15>
*/
void buslatches_test_timing(uint8_t addr_0_7, uint8_t addr_8_15, uint8_t data_0_7,
uint8_t data_8_15) {
timeout_c timeout;
printf("PRU generates max speed read/write sequences on 4 full 8bit\n");
printf("latches with these start patterns:\n");
printf(
"ADDR<0:7> = 0x%02x, ADDR<8:15> = 0x%02x, DATA<0:7> = 0x%02x, <DATA8:15> = 0x%02x.\n",
addr_0_7, addr_8_15, data_0_7, data_8_15);
printf("Read/write mismatches are signaled with PRU1.12 == 1.\n");
printf("Connect logic analyzer probes to: \n");
printf(" REG_SEL, REG_WRITE, REG_DATIN, REG_DATOUT, PRU1.12 .\n");
printf("End with ^C.\n");
mailbox->buslatch_test.addr_0_7 = addr_0_7;
mailbox->buslatch_test.addr_8_15 = addr_8_15;
mailbox->buslatch_test.data_0_7 = data_0_7;
mailbox->buslatch_test.data_8_15 = data_8_15;
// Setup ^C catcher
SIGINTcatchnext();
mailbox->arm2pru_req = ARM2PRU_BUSLATCH_TEST; // start PRU test loop
while (!SIGINTreceived) {
timeout.wait_ms(0);
}
// stop PRU loop by settting something != ARM2PRU_BUSLATCH_TEST
mailbox->arm2pru_req = ARM2PRU_BUSLATCH_INIT; //
timeout.wait_ms(1);
if (mailbox->arm2pru_req != ARM2PRU_NONE)
printf("Stopping PRU test loop failed!\n");
else
printf("PRU test loop stopped.\n");
}