mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-02-16 04:33:49 +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
342 lines
10 KiB
C++
342 lines
10 KiB
C++
/* application.cpp: UniBone "demo" application, global resources
|
|
|
|
Copyright (c) 2018, Joerg Hoppe, j_hoppe@t-online.de, www.retrocmp.com
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
- Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
- Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
- Neither the name of the copyright holder nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
12-nov-2018 JH entered beta phase
|
|
14-May-2018 JH created
|
|
|
|
*/
|
|
|
|
#define _MAIN_C_
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
//#include <string.h>
|
|
//#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
//#include <errno.h>
|
|
//#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <strings.h>
|
|
#include <string>
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
|
|
#include "logsource.hpp"
|
|
#include "logger.hpp"
|
|
|
|
#include "getopt2.hpp"
|
|
#include "inputline.h"
|
|
#include "pru.hpp"
|
|
#include "mailbox.h"
|
|
#include "gpios.hpp"
|
|
#include "memoryimage.hpp"
|
|
#include "iopageregister.h"
|
|
#include "panel.hpp"
|
|
#include "unibus.h"
|
|
#include "unibusadapter.hpp"
|
|
|
|
#include "logger.hpp"
|
|
#include "application.hpp" // own
|
|
|
|
application_c::application_c() {
|
|
log_label = "APP";
|
|
}
|
|
|
|
/*
|
|
* help()
|
|
*/
|
|
void application_c::help() {
|
|
cout << "\n";
|
|
cout << "NAME\n";
|
|
cout << "\n";
|
|
cout << version << "\n";
|
|
cout << copyright << "\n";
|
|
cout << "\n";
|
|
cout << "SYNOPSIS\n";
|
|
cout << "\n";
|
|
cout << "TEST SETUP\n";
|
|
cout << " - UniBone must be plugged into SPC slots C-F on DD11-CK backplane.\n";
|
|
cout << " - 2 passive M903 terminators plugged into backplane.\n";
|
|
cout << " - Short cut BR4,5,6,NPR IN/OUT with jumpers.\n";
|
|
cout << " - Install the \"PRU\" device tree overlay:\n";
|
|
cout << " - cp UniBone-00B0.dtbo /lib/firmware UniBone-00B0.dtbo\n";
|
|
cout << " - reboot\n";
|
|
cout << "\n";
|
|
// cout << "Command line options are processed strictly left-to-right. \n\n");
|
|
// getopt must be initialized to print the syntax
|
|
getopt_parser.help(cout, opt_linewidth, 10, PROGNAME);
|
|
cout << "\n";
|
|
cout << "EXAMPLES\n";
|
|
cout << "\n";
|
|
cout << "sudo ./" PROGNAME "\n";
|
|
cout << " Show interactive menus.\n";
|
|
cout << "\n";
|
|
|
|
exit(1);
|
|
}
|
|
|
|
// show error for one option
|
|
void application_c::commandline_error() {
|
|
cerr << "Error while parsing command line:\n";
|
|
cerr << " " << getopt_parser.curerrortext.c_str() << "\n";
|
|
exit(1);
|
|
}
|
|
|
|
// parameter wrong for currently parsed option
|
|
void application_c::commandline_option_error(char *errtext, ...) {
|
|
char buffer[1024];
|
|
va_list args;
|
|
cerr << "Error while parsing commandline option:\n";
|
|
if (errtext) {
|
|
va_start(args, errtext);
|
|
vsprintf(buffer, errtext, args);
|
|
cerr << buffer << "\nSyntax: ";
|
|
va_end(args);
|
|
} else
|
|
cerr << " " << getopt_parser.curerrortext << "\nSyntax: ";
|
|
getopt_parser.help_option(cerr, 96, 10);
|
|
exit(1);
|
|
}
|
|
|
|
/* check whether the given device parameter configuration
|
|
* my cause problems.
|
|
*/
|
|
|
|
/*
|
|
* read commandline parameters into global "param_" vars
|
|
* result: 0 = OK, 1 = error
|
|
*/
|
|
void application_c::parse_commandline(int argc, char **argv) {
|
|
int res;
|
|
|
|
// define commandline syntax
|
|
getopt_parser.init(/*ignore_case*/1);
|
|
|
|
// getopt_def(&getopt_parser, NULL, NULL, "hostname", NULL, NULL, "Connect to the Blinkenlight API server on <hostname>\n"
|
|
// "<hostname> may be numerical or ar DNS name",
|
|
// "127.0.0.1", "connect to the server running on the same machine.",
|
|
// "raspberrypi", "connected to a RaspberryPi with default name.");
|
|
|
|
// !!!1 Do not define any defaults... else these will be set very time!!!
|
|
|
|
getopt_parser.ignore_case = 1;
|
|
getopt_parser.define("?", "help", "", "", "", "Print help.", "", "", "", "");
|
|
getopt_parser.define("v", "verbose", "", "", "", "Print info about operation.", "", "", "",
|
|
"");
|
|
getopt_parser.define("dbg", "debug", "", "", "", "Print debug messages.\n"
|
|
// getopt_parser.define("dbg", "debug", "", "channelmask", "",
|
|
// "Print debug messages. Optional reduces to channels wit <channelmask>.\n"
|
|
"Outputfile is \"unibone.log\"", "", "", "", "");
|
|
getopt_parser.define("cf", "cmdfile", "cmdfilename", "", "",
|
|
"File from which commands are read.\n"
|
|
"Lines are processed as if typed in.", "testseq",
|
|
"read commands from file \"testseq\" and execute line by line", "", "");
|
|
|
|
getopt_parser.define("arb", "arbitration_mode", "mode", "", "",
|
|
"Setup configuration of UNIBUS test system.\n"
|
|
"arb 0: no Bus Arbitrator. No PDP-11 CPU is doing NPR/INTR/SACK arbitration\n"
|
|
" (HALTed, Not plugged in, or console processor active SACK)\n"
|
|
" Bus master memory access without handshake to CPU.\n"
|
|
"arb 1: UniBone is client to PDP-11 CPU Bus Arbitrator.\n"
|
|
" Bus master memory access with NPR/G/SACK handshake to CPU.\n", "", "",
|
|
"", "");
|
|
|
|
// test options
|
|
|
|
getopt_parser.define("t", "test", "iarg1,iarg2", "soptarg", "8 15",
|
|
"Tests the new c++ getop2.cpp\n"
|
|
"Multiline info, fix and optional args, short and long examples", "1,2",
|
|
"simple sets both mandatory int args", "1 2 hello",
|
|
"Sets integer args and option string arg");
|
|
// if (argc < 2)
|
|
// help(); // at least 1 required
|
|
logger->default_level = LL_WARNING;
|
|
res = getopt_parser.first(argc, argv);
|
|
while (res > 0) {
|
|
if (getopt_parser.isoption("help")) {
|
|
help();
|
|
} else if (getopt_parser.isoption("verbose")) {
|
|
logger->default_level = LL_INFO;
|
|
} else if (getopt_parser.isoption("debug")) {
|
|
logger->default_level = LL_DEBUG;
|
|
} else if (getopt_parser.isoption("cmdfile")) {
|
|
if (getopt_parser.arg_s("cmdfilename", opt_cmdfilename) < 0)
|
|
commandline_option_error(NULL);
|
|
} else if (getopt_parser.isoption("arbitration_mode")) {
|
|
unsigned mode;
|
|
WARNING("Option \"arbitration_mode\" was removed");
|
|
if (getopt_parser.arg_u("mode", &mode) < 0)
|
|
commandline_option_error(NULL);
|
|
} else if (getopt_parser.isoption("test")) {
|
|
int i1, i2;
|
|
string s;
|
|
if (getopt_parser.arg_i("iarg1", &i1) < 0)
|
|
commandline_option_error(NULL);
|
|
if (getopt_parser.arg_i("iarg2", &i2) < 0)
|
|
commandline_option_error(NULL);
|
|
cout << "iarg1=" << i1 << ", iarg2=" << i2;
|
|
if (getopt_parser.arg_s("soptarg", s))
|
|
cout << ", soptarg=" << s;
|
|
cout << "\n";
|
|
}
|
|
res = getopt_parser.next();
|
|
}
|
|
if (res == GETOPT_STATUS_MINARGCOUNT || res == GETOPT_STATUS_MAXARGCOUNT)
|
|
// known option, but wrong number of arguments
|
|
commandline_option_error(NULL);
|
|
else if (res < 0)
|
|
commandline_error();
|
|
}
|
|
|
|
// configure all hardware related subsystems:
|
|
// PUR, shard memory, GPIOs,
|
|
void application_c::hardware_startup(enum pru_c::prucode_enum prucode_id) {
|
|
|
|
INFO("Connecting to PRU.");
|
|
/* initialize the library, PRU and interrupt; launch our PRU program */
|
|
|
|
pru->start(prucode_id);
|
|
mailbox_connect();
|
|
|
|
INFO("Registering non-PRU pins.");
|
|
gpios->init();
|
|
INFO("Disable DS8641 drivers.");
|
|
buslatches_output_enable(0);
|
|
INFO("Leave SYSBOOT mode.");
|
|
GPIO_SETVAL(gpios->reg_enable, 1);
|
|
// input registers can now be read
|
|
|
|
INFO("Registering multiplex bus latches, initialized later by PRU code.");
|
|
// INFO("Setup bus multiplex latches.");
|
|
buslatches_register();
|
|
|
|
INFO("Initializing device register maps.");
|
|
iopageregisters_init();
|
|
}
|
|
|
|
// disable all hardware related subsystems:
|
|
void application_c::hardware_shutdown() {
|
|
pru->stop();
|
|
}
|
|
|
|
int application_c::run(int argc, char *argv[]) {
|
|
void error_clear(void);
|
|
|
|
opt_linewidth = 80;
|
|
/* Intializes random number generator */
|
|
{
|
|
time_t t;
|
|
srand((unsigned) time(&t));
|
|
}
|
|
|
|
// returns only if everything is OK
|
|
// Std options already executed
|
|
parse_commandline(argc, argv);
|
|
|
|
logger->reset_log_levels(); // logger.default_level maybe info or debug
|
|
logger->life_level = LL_INFO; // show message up to this level immediately on console
|
|
//logger->life_level = LL_DEBUG; // show message up to this level immediately on console
|
|
logger->default_filepath = "unibone.log.csv";
|
|
|
|
// Test messages: visible if -verbose, -debug set.
|
|
INFO("Printing verbose output.");
|
|
DEBUG("Printing DEBUG output. Log file = \"%s\"", logger->default_filepath.c_str());
|
|
|
|
/* prussdrv_init() will segfault if called with EUID != 0 */
|
|
if (geteuid()) {
|
|
FATAL("%s must be run as root to use prussdrv\n", argv[0]);
|
|
}
|
|
|
|
inputline_init();
|
|
if (!opt_cmdfilename.empty()) {
|
|
// read commands from file
|
|
if (!inputline_fopen((char*) opt_cmdfilename.c_str())) {
|
|
printf("%s\n",
|
|
fileErrorText("Could not open command file \"%s\"",
|
|
opt_cmdfilename.c_str()));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
cout << version << "\n";
|
|
|
|
// Multiplex latches are intialized by PRU code after each code download
|
|
INFO("Registering Non-PRU GPIO pins.");
|
|
gpios->init();
|
|
INFO("Disable DS8641 UNIBUS drivers.");
|
|
buslatches_output_enable(0);
|
|
INFO("Leave SYSBOOT mode.");
|
|
GPIO_SETVAL(gpios->reg_enable, 1);
|
|
// input registers can now be read
|
|
|
|
menu_main();
|
|
|
|
// hardware_shutdown();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Singleton
|
|
application_c *app;
|
|
|
|
/* construct all singletons in proper order
|
|
*/
|
|
static void factory() {
|
|
// logger first, all logsource_c connect to it.
|
|
logger = new logger_c();
|
|
|
|
pru = new pru_c();
|
|
gpios = new gpios_c();
|
|
unibus_signals = new unibus_signals_c() ;
|
|
ddrmem = new ddrmem_c();
|
|
|
|
// paneldriver before all devices who use lamps or buttons
|
|
paneldriver = new paneldriver_c();
|
|
|
|
membuffer = new memoryimage_c();
|
|
|
|
unibus = new unibus_c();
|
|
unibusadapter = new unibusadapter_c();
|
|
|
|
app = new application_c();
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
factory();
|
|
return app->run(argc, argv);
|
|
}
|
|
|