mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-01-29 13:11:11 +00:00
PRU1 code split into multiple images 1. test functions 2. UNIBUS operation PRU1 bus latch interface Write byte/bits access not with MACROS (random optimizer influence), now with *_helper() procedures. Same timing, more determinism, much code saving. Nono more ASM code to write PRU0 XFER area. demo: menu to test UNIBUS signals directly rework "Arbitration" logic: now 3-fold Rework of UNIBUs arbtiration: NONE/CLIENT/MASTER - no Arbitrator (SACK penidng for 11/34 Konsole) (NONE) - phyiscal PDP_11 CPU is Arbitrator (CLIENT) - UniBone implements Arbitrator (MASTER) - Same PRU code loop handles all arbitration types PRU buslatch timing slower, for some problematic PCBs More aggressive bus latch selftest (mixed patterns, running on PRU now) Refinement of ready-to-run scripts - Adapted to changed "demo" menu - new name scheme <OS>_<boot- drive>_<PDP-11CPU> indicates - which OS is run - which disk emulation is used and what is the boot device - what is the (minimum) PDP-11 to run that Merged in Joshs DMA timing for 11/84 UNIBUS master cycles waits 350 us before MSYN, instead 150. Merged in Joshs DMA request queue multiple devices canrequest INTR and DMAs concurrently, will be put on the bus sequentially Merged in Joshs MSCP driver - Build RT-11v5.5 for MSCP - added boot loader "du.lst" MSCP run scrips 2.11BSD on MSCP on PDP-11/44 RT11 on MSCP Fix: image file sizing Disk image file exptend automatically if block beyond current file end is written
1145 lines
42 KiB
C++
1145 lines
42 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.
|
|
|
|
|
|
21-may-2019 JH added UNIBUS signals
|
|
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 "pru.hpp"
|
|
#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_wire_info_t buslatches_wire_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 <- U25.18 <- U25.02 <- U27.13 <- U27.15 <- A16" },//
|
|
{ 4, 1, 1, 0, "A17",
|
|
"P8.46 <- J17.2 DATIN_1 <- U25.17 <- U25.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_wire_info_t *buslatches_get_wire_info(const char *unibus_name, unsigned is_input) {
|
|
unsigned i;
|
|
buslatches_wire_info_t *si;
|
|
|
|
for (i = 0; (si = &buslatches_wire_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_wire_path(unsigned reg, unsigned mismatch_bitmask) {
|
|
unsigned bit;
|
|
unsigned bitmask;
|
|
unsigned i;
|
|
buslatches_wire_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_wire_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_wire_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
|
|
// activate AFTER RPU code started and reset bus latches values
|
|
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
|
|
void buslatches_register() {
|
|
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 < BUSLATCHES_COUNT; 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;
|
|
|
|
}
|
|
|
|
// UNIBUS lines all H / only BR4567, NPR_OUT auf LOW
|
|
// PRU1 does it
|
|
void buslatches_pru_reset() {
|
|
assert(pru->prucode_id == pru_c::PRUCODE_TEST);
|
|
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. Other bits are cleared (PRU logic)
|
|
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 < BUSLATCHES_COUNT);
|
|
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_wire_path(reg_sel, setval ^ chkval);
|
|
return;
|
|
}
|
|
count++;
|
|
}
|
|
printf("\n%u tests successful.\n", count);
|
|
}
|
|
|
|
// shuffles entries in mailbox.exerciser work list
|
|
static void buslatches_exerciser_random_order() {
|
|
for (unsigned i = 0; i < 2 * BUSLATCHES_COUNT; i++) {
|
|
unsigned reg_sel1 = rand() % BUSLATCHES_COUNT;
|
|
unsigned reg_sel2 = rand() % BUSLATCHES_COUNT;
|
|
uint8_t tmp;
|
|
// swap addr and testval
|
|
tmp = mailbox->buslatch_exerciser.addr[reg_sel1];
|
|
mailbox->buslatch_exerciser.addr[reg_sel1] = mailbox->buslatch_exerciser.addr[reg_sel2];
|
|
mailbox->buslatch_exerciser.addr[reg_sel2] = tmp;
|
|
tmp = mailbox->buslatch_exerciser.writeval[reg_sel1];
|
|
mailbox->buslatch_exerciser.writeval[reg_sel1] =
|
|
mailbox->buslatch_exerciser.writeval[reg_sel2];
|
|
mailbox->buslatch_exerciser.writeval[reg_sel2] = tmp;
|
|
}
|
|
}
|
|
|
|
void buslatches_test_simple_pattern_multi(unsigned pattern) {
|
|
unsigned pass_no; // global test number counter
|
|
uint64_t total_errors, total_tests;
|
|
unsigned reg_sel; // register address
|
|
unsigned testval[BUSLATCHES_COUNT]; // 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, stop with ^C.\n");
|
|
break;
|
|
case 3:
|
|
printf("Highspeed \"moving zeros\" in register latches, stop with ^C.\n");
|
|
break;
|
|
case 4:
|
|
printf("Highspeed toggle 0x00 - 0xff in register latches, stop with ^C.\n");
|
|
break;
|
|
case 5:
|
|
printf("Highspeed random values in register latches, stop with ^C.\n");
|
|
break;
|
|
default:
|
|
printf("Error: unknown test pattern %u.\n", pattern);
|
|
}
|
|
|
|
pass_no = 0;
|
|
total_errors = 0;
|
|
total_tests = 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. Output: testval[reg_addr] */
|
|
switch (pattern) {
|
|
case 2: // moving ones, linear addressing
|
|
for (reg_sel = 0; reg_sel < BUSLATCHES_COUNT; reg_sel++) {
|
|
unsigned bitidx = pass_no % 8; // circle all 8 bits per register
|
|
unsigned regidx = (pass_no / 8) % BUSLATCHES_COUNT; // circle all registers
|
|
// set only one bit
|
|
if (reg_sel == regidx)
|
|
testval[reg_sel] = 1 << bitidx;
|
|
else
|
|
testval[reg_sel] = 0;
|
|
}
|
|
break;
|
|
case 3: // moving zeros, linear addressing
|
|
for (reg_sel = 0; reg_sel < BUSLATCHES_COUNT; reg_sel++) {
|
|
// clear only one bit
|
|
unsigned bitidx = pass_no % 8; // circle all 8 bits per register
|
|
unsigned regidx = (pass_no / 8) % BUSLATCHES_COUNT; // circle all registers
|
|
if (reg_sel == regidx)
|
|
testval[reg_sel] = ~(1 << bitidx);
|
|
else
|
|
testval[reg_sel] = 0xff;
|
|
}
|
|
break;
|
|
case 4: // toggle all regs simultaneously 0x00, 0xff, 0xff, ...
|
|
// linear addressing
|
|
for (reg_sel = 0; reg_sel < BUSLATCHES_COUNT; reg_sel++) {
|
|
if (pass_no & 1)
|
|
testval[reg_sel] = 0xff;
|
|
else
|
|
testval[reg_sel] = 0x00;
|
|
}
|
|
break;
|
|
case 5:
|
|
// random values, random addressing
|
|
for (reg_sel = 0; reg_sel < BUSLATCHES_COUNT; reg_sel++)
|
|
testval[reg_sel] = rand() & 0xff; // slow?
|
|
break;
|
|
default:
|
|
printf("Error: unknown test pattern %u.\n", pattern);
|
|
}
|
|
|
|
// mask out unimplemented bits
|
|
for (reg_sel = 0; reg_sel < BUSLATCHES_COUNT; reg_sel++)
|
|
testval[reg_sel] &= buslatches.bidi_bitmask[reg_sel];
|
|
|
|
// Setup mailbox for PRU buslatch exerciser
|
|
// it tests always 8 accesses
|
|
for (reg_sel = 0; reg_sel < BUSLATCHES_COUNT; reg_sel++) {
|
|
mailbox->buslatch_exerciser.addr[reg_sel] = reg_sel;
|
|
mailbox->buslatch_exerciser.writeval[reg_sel] = testval[reg_sel];
|
|
mailbox->buslatch_exerciser.readval[reg_sel] = 0xff; // invalid at the moment
|
|
}
|
|
// shuffle worklist to create random access order
|
|
buslatches_exerciser_random_order();
|
|
|
|
// alternatingly use byte or bit access procedures
|
|
// unindented synchronoized with moving one/moving zero or other peridioc tests
|
|
mailbox->buslatch_exerciser.pattern = (pass_no
|
|
% MAILBOX_BUSLATCH_EXERCISER_PATTERN_COUNT);
|
|
|
|
mailbox_execute(ARM2PRU_BUSLATCH_EXERCISER, ARM2PRU_NONE);
|
|
|
|
// check: mailbox readvalues == write values ?
|
|
for (unsigned i = 0; i < BUSLATCHES_COUNT; i++) {
|
|
reg_sel = mailbox->buslatch_exerciser.addr[i];
|
|
unsigned writeval = mailbox->buslatch_exerciser.writeval[i];
|
|
unsigned readval = mailbox->buslatch_exerciser.readval[i];
|
|
unsigned bitmask = buslatches.bidi_bitmask[reg_sel];
|
|
total_tests++;
|
|
if (buslatches.read_inverted[reg_sel])
|
|
readval = ~readval; // input latches invert
|
|
readval &= bitmask;
|
|
if (readval != writeval) {
|
|
total_errors++;
|
|
printf(
|
|
"Error buslatches_test_simple_pattern_multi(pattern=%d), pass %u, pattern = %d:\n",
|
|
pattern, pass_no, (unsigned) mailbox->buslatch_exerciser.pattern);
|
|
printf(" register %u: wrote 0x%x, read back 0x%x, error bit mask 0x%02x\n",
|
|
reg_sel, writeval, readval, writeval ^ readval);
|
|
if (i == 0)
|
|
printf(" No prev addr/val history\n");
|
|
else {
|
|
// prinout previous test data. for access pattern see "pattern" and sourcecode
|
|
printf(" Prev addr/val history:");
|
|
for (unsigned j = 0; j < i; j++)
|
|
printf(" %u/0x%02x", mailbox->buslatch_exerciser.addr[j],
|
|
mailbox->buslatch_exerciser.writeval[j]);
|
|
printf(".\n");
|
|
}
|
|
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_wire_path(reg_sel, writeval ^ readval);
|
|
printf("%llu of %llu tests failed, error rate = %0.5f%% = %gppm)\n\n",
|
|
total_errors, total_tests, 100.0 * total_errors / total_tests,
|
|
1000000.0 * total_errors / total_tests);
|
|
}
|
|
}
|
|
|
|
pass_no++;
|
|
}
|
|
|
|
if (total_errors == 0)
|
|
printf("\n%llu tests successful.\n", total_tests);
|
|
else
|
|
printf("\n%llu of %llu tests failed, error rate = %0.5f%% = %gppm)\n", total_errors,
|
|
total_tests, 100.0 * total_errors / total_tests,
|
|
1000000.0 * total_errors / total_tests);
|
|
}
|
|
|
|
/* 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");
|
|
}
|
|
|
|
/**** GPIO access to UNIBUS sigbals ****/
|
|
unibus_signals_c *unibus_signals; // singleton
|
|
|
|
unibus_signal_info_c::unibus_signal_info_c(enum unibus_signal_info_c::id_enum id, string name,
|
|
unsigned bitwidth) {
|
|
this->id = id;
|
|
this->name = name;
|
|
this->bitwidth = bitwidth;
|
|
}
|
|
|
|
unibus_signals_c::unibus_signals_c() {
|
|
// fill dictionary
|
|
// order like in DEC manual
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_address, "ADDR", 18));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_data, "DATA", 16));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_control, "C1,C0", 2));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_msyn, "MSYN", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_ssyn, "SSYN", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_pa, "PA", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_pb, "PB", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_intr, "INTR", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_br4, "BR4", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_br5, "BR5", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_br6, "BR6", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_br7, "BR7", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_bg4, "BG4", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_bg5, "BG5", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_bg6, "BG6", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_bg7, "BG7", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_npr, "NPR", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_npg, "NPG", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_sack, "SACK", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_bbsy, "BBSY", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_init, "INIT", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_aclo, "ACLO", 1));
|
|
signals.push_back(unibus_signal_info_c(unibus_signal_info_c::ub_dclo, "DCLO", 1));
|
|
}
|
|
|
|
unsigned unibus_signals_c::max_name_len() {
|
|
return 5; // see above
|
|
}
|
|
|
|
unsigned unibus_signals_c::size() {
|
|
return signals.size();
|
|
}
|
|
|
|
void unibus_signals_c::set_val(enum unibus_signal_info_c::id_enum id, unsigned value) {
|
|
switch (id) {
|
|
case unibus_signal_info_c::ub_address:
|
|
buslatches_setval(2, 0xff, value); // ADDR0:7
|
|
buslatches_setval(3, 0xff, value >> 8); // ADDR8:15
|
|
buslatches_setval(4, 0x03, value >> 12); // ADDR16,17
|
|
break;
|
|
case unibus_signal_info_c::ub_data:
|
|
buslatches_setval(5, 0xff, value); // DATA0:7
|
|
buslatches_setval(6, 0xff, value >> 8); // DATA8:15
|
|
break;
|
|
case unibus_signal_info_c::ub_control:
|
|
buslatches_setval(4, 0x0C, value << 2); // C1 = 0x8, C0 = 0x4
|
|
break;
|
|
case unibus_signal_info_c::ub_msyn:
|
|
buslatches_setval(4, 0x10, value << 4); // MSYN = 0x10
|
|
break;
|
|
case unibus_signal_info_c::ub_ssyn:
|
|
buslatches_setval(4, 0x20, value << 5); // ssyn=0x20
|
|
break;
|
|
case unibus_signal_info_c::ub_pa:
|
|
buslatches_setval(7, 0x02, value << 1);
|
|
break;
|
|
case unibus_signal_info_c::ub_pb:
|
|
buslatches_setval(7, 0x04, value << 2);
|
|
break;
|
|
case unibus_signal_info_c::ub_intr:
|
|
buslatches_setval(7, 0x01, value);
|
|
break;
|
|
case unibus_signal_info_c::ub_br4:
|
|
buslatches_setval(1, 0x01, value);
|
|
break;
|
|
case unibus_signal_info_c::ub_br5:
|
|
buslatches_setval(1, 0x02, value << 1);
|
|
break;
|
|
case unibus_signal_info_c::ub_br6:
|
|
buslatches_setval(1, 0x04, value << 2);
|
|
break;
|
|
case unibus_signal_info_c::ub_br7:
|
|
buslatches_setval(1, 0x08, value << 3);
|
|
break;
|
|
case unibus_signal_info_c::ub_bg4:
|
|
buslatches_setval(0, 0x01, !value);
|
|
break;
|
|
case unibus_signal_info_c::ub_bg5:
|
|
buslatches_setval(0, 0x02, (!value) << 1);
|
|
break;
|
|
case unibus_signal_info_c::ub_bg6:
|
|
buslatches_setval(0, 0x04, (!value) << 2);
|
|
break;
|
|
case unibus_signal_info_c::ub_bg7:
|
|
buslatches_setval(0, 0x08, (!value) << 3);
|
|
break;
|
|
case unibus_signal_info_c::ub_npr:
|
|
buslatches_setval(1, 0x10, value << 4);
|
|
break;
|
|
case unibus_signal_info_c::ub_npg:
|
|
buslatches_setval(0, 0x10, (!value) << 4);
|
|
break;
|
|
case unibus_signal_info_c::ub_sack:
|
|
buslatches_setval(1, 0x20, value << 5);
|
|
break;
|
|
case unibus_signal_info_c::ub_bbsy:
|
|
buslatches_setval(1, 0x40, value << 6);
|
|
break;
|
|
case unibus_signal_info_c::ub_init:
|
|
buslatches_setval(7, 0x08, value << 3);
|
|
break;
|
|
case unibus_signal_info_c::ub_aclo:
|
|
buslatches_setval(7, 0x10, value << 4);
|
|
break;
|
|
case unibus_signal_info_c::ub_dclo:
|
|
buslatches_setval(7, 0x20, value << 5);
|
|
break;
|
|
}
|
|
}
|
|
|
|
unsigned unibus_signals_c::get_val(enum unibus_signal_info_c::id_enum id) {
|
|
unsigned result = 0;
|
|
switch (id) {
|
|
case unibus_signal_info_c::ub_address:
|
|
result = buslatches_getval(2); // ADDR0:7
|
|
result |= buslatches_getval(3) << 8; // ADDR8:15
|
|
result |= (buslatches_getval(4) & 0x03) << 16; // ADDR8:15
|
|
break;
|
|
case unibus_signal_info_c::ub_data:
|
|
result = buslatches_getval(5); // DATA0:7
|
|
result |= buslatches_getval(6) << 8; // DATA8:15
|
|
break;
|
|
case unibus_signal_info_c::ub_control:
|
|
result = (buslatches_getval(4) & 0x0c) >> 2; // C1 = 0x8, C0 = 0x4
|
|
break;
|
|
case unibus_signal_info_c::ub_msyn:
|
|
result = (buslatches_getval(4) & 0x10) >> 4; // MSYN = 0x10
|
|
break;
|
|
case unibus_signal_info_c::ub_ssyn:
|
|
result = (buslatches_getval(4) & 0x20) >> 5; // ssyn=0x20
|
|
break;
|
|
case unibus_signal_info_c::ub_pa:
|
|
result = (buslatches_getval(7) & 0x02) >> 1;
|
|
break;
|
|
case unibus_signal_info_c::ub_pb:
|
|
result = (buslatches_getval(7) & 0x04) >> 2;
|
|
break;
|
|
case unibus_signal_info_c::ub_intr:
|
|
result = (buslatches_getval(7) & 0x01);
|
|
break;
|
|
case unibus_signal_info_c::ub_br4:
|
|
result = (buslatches_getval(1) & 0x01);
|
|
break;
|
|
case unibus_signal_info_c::ub_br5:
|
|
result = (buslatches_getval(1) & 0x02) >> 1;
|
|
break;
|
|
case unibus_signal_info_c::ub_br6:
|
|
result = (buslatches_getval(1) & 0x04) >> 2;
|
|
break;
|
|
case unibus_signal_info_c::ub_br7:
|
|
result = (buslatches_getval(1) & 0x08) >> 3;
|
|
break;
|
|
case unibus_signal_info_c::ub_bg4:
|
|
result = !(buslatches_getval(0) & 0x01);
|
|
break;
|
|
case unibus_signal_info_c::ub_bg5:
|
|
result = !(buslatches_getval(0) & 0x02) >> 1;
|
|
break;
|
|
case unibus_signal_info_c::ub_bg6:
|
|
result = !(buslatches_getval(0) & 0x04) >> 2;
|
|
break;
|
|
case unibus_signal_info_c::ub_bg7:
|
|
result = !(buslatches_getval(0) & 0x08) >> 3;
|
|
break;
|
|
case unibus_signal_info_c::ub_npr:
|
|
result = (buslatches_getval(1) & 0x10) >> 4;
|
|
break;
|
|
case unibus_signal_info_c::ub_npg:
|
|
result = !(buslatches_getval(0) & 0x10) >> 4;
|
|
break;
|
|
case unibus_signal_info_c::ub_sack:
|
|
result = (buslatches_getval(1) & 0x20) >> 5;
|
|
break;
|
|
case unibus_signal_info_c::ub_bbsy:
|
|
result = (buslatches_getval(1) & 0x40) >> 6;
|
|
break;
|
|
case unibus_signal_info_c::ub_init:
|
|
result = (buslatches_getval(7) & 0x08) >> 3;
|
|
break;
|
|
case unibus_signal_info_c::ub_aclo:
|
|
result = (buslatches_getval(7) & 0x10) >> 4;
|
|
break;
|
|
case unibus_signal_info_c::ub_dclo:
|
|
result = (buslatches_getval(7) & 0x20) >> 5;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|