1
0
mirror of https://github.com/prirun/p50em.git synced 2026-02-26 16:23:28 +00:00

license dongle, boot options, amlc, tape, disk, change device filenames

added licensing dongle support
boot option supports filename, sense and data switches:
  -boot filename sswitch dswitch (for D. Boone)
-ds option (like VCP) as alternate way to set data switches (for D. Boone)
removed -v and -vv: they were old and didn't do anything
tries to read ring0.map and ring3.map if no -map option used
fixed bug with new connect for multiple AMLC controllers
default build is now for 32 amlc lines
fixed disk geometry for CMD; added geometry for Model 4935 (1.1G NEC)
fixed tape boot for variable record sizes (for D. Boone), but rev 19 loops
added EMULATOR_VERSION #define and version printf()
changed tape drive filenames from dev14u0-4 to mt0-4
changed disk drive filenames from dev26u0 to disk26u0
added license manager tracing
changed to automatically redirect stderr to error.log on startup
changed to create mtx tape drive files if they don't exist
tested write-protected tape drive files
changed invalid seek from a fatal error (emulator halt) to a disk error
disable Nagle algorithm for telnet connections (OSX buggy delay)
error setting terminfo flags for USB serial devices is no longer fatal
changed "pio to unimplemented device" from error to trace
This commit is contained in:
Jim
2008-01-06 00:00:00 -05:00
parent e16f8824c4
commit 1750f7f83b
3 changed files with 335 additions and 214 deletions

347
em.c
View File

@@ -1,3 +1,5 @@
#define EMULATOR_VERSION 102
/* Pr1me Computer emulator, Jim Wilcoxson (prirun@gmail.com), April 4, 2005
Copyright (C) 2005-2007, Jim Wilcoxson. All Rights Reserved.
@@ -53,7 +55,7 @@ SAM>
Usage: to load initial boot from tape, then prompt for disk pdev
$ time ./em -boot 1005 -tport 8000 -cpuid 5
Boot file is dev14u0 <--- note tape drive boot
Boot file is mt0 <--- note tape drive boot
Sense switches set to 1005 <--- these cause pdev prompt
[BOOT Rev. 20.2.3 Copyright (c) 1987, Prime Computer, Inc.]
@@ -103,8 +105,16 @@ OK:
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include "mxapi.h"
#include <sys/select.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <time.h>
#include <sys/file.h>
#include <glob.h>
/* In SR modes, Prime CPU registers are mapped to memory locations
0-'37, but only 0-7 are user accessible. In the post-P300
@@ -257,6 +267,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
T_PCL PCL instructions
T_FAULT Faults
T_PX Process exchange
T_LM License manager
*/
#define T_EAR 0x00000001
@@ -274,12 +285,27 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
#define T_TIO 0x00001000
#define T_TERM 0x00002000
#define T_RIO 0x00004000
#define T_GET 0x00002000
#define T_PUT 0x00001000
#define T_LM 0x00008000
#define T_PUT 0x00010000
#define T_GET 0x00020000
#define BITMASK16(b) (0x8000 >> ((b)-1))
#define BITMASK32(b) ((unsigned int)(0x80000000) >> ((b)-1))
/* license data structure. Part is read from file "license" file:
- field 1: license id
- field 2: license server Internet name
- field 3: license server port (TCP)
*/
struct {
int id;
char server[65];
int sport;
int sockfd;
struct hostent *rserver;
} license;
#ifdef NOTRACE
#define TRACE(flags, formatargs...)
#define TRACEA(formatargs...)
@@ -288,10 +314,10 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
#define TRACEA(formatargs...) fprintf(gvp->tracefile,formatargs)
#endif
/* traceprocs is an array of (operating system) procedure names we're
tracing, with flags and associated data
/* traceprocs is an array of (operating system) procedure names we're
tracing, with flags and associated data
numtraceprocs is the number of entries in traceprocs, 0=none */
numtraceprocs is the number of entries in traceprocs, 0=none */
#define MAXTRACEPROCS 2
static struct {
@@ -307,6 +333,7 @@ static struct {
switches are set to 014114. But DIAGS like this setting. :( */
static unsigned short sswitch = 014114; /* sense switches, set with -ss & -boot */
static unsigned short dswitch = 0; /* data (down) switches, set with -sd */
/* NOTE: the default cpuid is a P750: 1 MIPS, 8MB of memory
@@ -375,9 +402,10 @@ typedef struct {
references the same page as the cache entry pointed to by eap, then
the mapva call can be bypassed and the physical memory address
calculated using the cache. If the cache can't be used, either
because the entry is invalid or the access isn't allowed (only for
writes), mapva is called to do the mapping and (assuming it doesn't
fault) the eap cache entry is updated.
because the entry is invalid, points to a different virtual page,
or the access isn't allowed (only for writes), mapva is called to
do the mapping and (assuming it doesn't fault) the eap cache entry
is updated.
This special cache is invalidated whenever the STLB is changed,
whenever a ring change occurs, and whenever a process exchange
@@ -435,6 +463,12 @@ typedef struct {
ea_t vpn; /* corresponding virtual page address */
} brp_t;
/* the dispatch table for generic instructions:
- bits 1-2 are the class (0-3)
- bits 3-6 are always zero
- bits 7-16 are the opcode
the index into the table is bits 1-2_7-16, for a 12-bit index */
void *disp_gen[4096]; /* generic dispatch table */
/* "gv" is a static structure used to hold "hot" global variables. These
@@ -458,7 +492,7 @@ typedef struct {
unsigned int instpermsec; /* instructions executed per millisecond */
stlbe_t stlb[STLBENTS] /* the STLB: Segmentation Translation Lookaside Buffer */
stlbe_t stlb[STLBENTS]; /* the STLB: Segmentation Translation Lookaside Buffer */
iotlbe_t iotlb[IOTLBENTS]; /* the IOTLB: I/O Translation Lookaside Buffer */
@@ -523,13 +557,9 @@ static jmp_buf jmpbuf; /* for longjumps to the fetch loop */
"memlimit" is set with the -mem argument, taking an argument which is
the desired memory limit in MB. Setting a memory limit is useful to
speed up system boots and diagnostics during emulator testing.
*/
*/
#ifdef OSX
#define MAXMB 512
#else
#define MAXMB 32
#endif
#define MAXMB 512
#define MEMSIZE MAXMB/2*1024*1024
#define MEM physmem
@@ -598,7 +628,6 @@ static unsigned short physmem[MEMSIZE]; /* system's physical memory */
#define LASTFAULT 077
static ea_t tnoua_ea=0, tnou_ea=0, tsrc_ea=0;
static int verbose; /* -v (not used anymore) */
static int domemdump; /* -memdump arg */
static int tport; /* -tport option (incoming terminals) */
@@ -653,6 +682,75 @@ char *brp_name() {
#include "stopwatch.h"
/* reads and parses the license file and sets the license global
variable structure. The license file is not used in the hobby
version. This routine also sets up the socket and client
listening port, so that errors can be detected early.
*/
readlicense() {
struct sockaddr_in raddr;
int raddrlen;
FILE *licensefile;
char line[100];
license.id = 0;
license.server[0] = 0;
license.sport = 0;
license.sockfd = -1;
#ifndef HOBBY
if ((licensefile = fopen("license", "r")) == NULL) {
printf("No license file.\n");
exit(1);
}
if (fgets(line, sizeof(line), licensefile) == NULL
|| sscanf(line, "%x %s %d", &license.id, license.server, &license.sport) != 3) {
printf("Unable to read license file. Format is: id server port\n");
exit(1);
}
fclose(licensefile);
#if 0
/* setup a port on the client for responses */
if (license.lport > 0) {
bzero(&license.laddr,sizeof(license.laddr));
license.laddr.sin_family = AF_INET;
license.laddr.sin_addr.s_addr = INADDR_ANY;
license.laddr.sin_port = htons(license.lport);
if (bind(license.sockfd, (struct sockaddr *)&license.laddr, sizeof(license.laddr)) < 0) {
perror("License bind");
fatal("Unable to bind local license port. Check license file.");
exit(1);
}
} else {
printf("Local license port must be > zero\n");
exit(1);
}
#endif
/* lookup the license server's address.
XXX: this might need repeating periodically, like daily, in case
an IP address changes */
license.rserver = gethostbyname(license.server);
if (license.rserver == NULL) {
printf("Can't lookup IP address for license server %s. Check license file or DNS.\n", license.server);
exit(1);
}
bcopy((char *)license.rserver->h_addr, (char *)&raddr.sin_addr.s_addr, license.rserver->h_length);
printf("License id: %08x server %s [%s:%d]\n", license.id, license.server, inet_ntoa(raddr.sin_addr.s_addr), license.sport);
#endif
return;
}
/* returns an index to a symbol, based on an address and type
match; if the address isn't found exactly, the index returned
@@ -707,7 +805,7 @@ addsym(char *sym, unsigned short seg, unsigned short word, char type) {
}
readloadmap(char *filename) {
readloadmap(char *filename, int showerr) {
FILE *mapf;
char line[100];
int lc,ix;
@@ -716,10 +814,13 @@ readloadmap(char *filename) {
ea_t lastaddr;
TRACEA("Reading load map from %s... ", filename);
if ((mapf = fopen(filename, "r")) == NULL) {
perror("Map file open");
fatal("Error reading map file");
}
if ((mapf = fopen(filename, "r")) == NULL)
if (showerr) {
perror("Map file open");
fatal("Error reading map file");
} else
return;
lc = 0;
while (fgets(line, sizeof(line), mapf) != NULL) {
lc++;
@@ -828,11 +929,14 @@ static pa_t mapva(ea_t ea, ea_t rp, short intacc, unsigned short *access) {
stopwatch_push(&sw_mapva);
/* map virtual address if segmentation is enabled */
/* fault bit set on EA means an address trap, which should be
handled at a higher lever and never make it this far */
if (ea & 0x80000000)
fatal("mapva: fault bit set on EA");
/* map virtual address if segmentation is enabled */
if (crs[MODALS] & 4) {
#ifndef NOTRACE
gvp->mapvacalls++;
@@ -948,45 +1052,6 @@ static pa_t mapva(ea_t ea, ea_t rp, short intacc, unsigned short *access) {
fatal("Return from macheck");
}
#if 0
/* NOTE: this is ifdef'd out because it slowed things down (it was a
precursor to the brp cache, which worked much better */
/* Use fastmap only when intacc = RACC or WACC, ie, get/put, not PACC!):
(pa_t) pa = fastmap(ea, intacc, rp);
*/
static pa_t fastmap (ea_t ea, ea_t rp, short intacc) {
short seg, ring;
stlbe_t *stlbp;
unsigned short access;
if (crs[MODALS] & 4) {
seg = SEGNO32(ea);
stlbp = gvp->stlb+STLBIX(ea);
/* if the STLB segments match, and the segment is common to all or
the process id matches, then the STLB cache can be used for
this access */
if ((stlbp->seg == seg) && ((seg < 04000) || (stlbp->procid == crs[OWNERL]))) {
ring = ((rp | ea) >> 29) & 3; /* current ring | ea ring = access ring */
access = stlbp->access[ring];
if ((intacc & access) == intacc) {
if (stlbp->unmodified && intacc == WACC) {
stlbp->unmodified = 0;
*(stlbp->pmep) &= ~020000; /* reset unmodified bit in memory */
}
return (stlbp->ppa | (ea & 0x3FF));
}
}
return mapva(ea, rp, intacc, &access);
}
return ea;
}
#endif
/* for I/O, ea is either an 18-bit physical address (which is just
returned if not in mapped I/O mode), or a 2-bit segment number and
@@ -1659,7 +1724,7 @@ static int devpoll[64] = {0};
'04 = devasr: system console
'07 = devpnc: Primenet Node Controller aka PNC (Ringnet)
'14 = devmt: mag tape unit 0
'14 = devmt: mag tape controller (4 drives)
'20 = devcp: clock / VCP / SOC
'26 = devdisk: 1st disk controller
*/
@@ -1691,15 +1756,24 @@ static int (*devmap[64])(int, int, int) = {
#else
/* this is the "typical system" controller configuration */
/* this is the "typical system" controller configuration:
'04 = devasr: system console
'14 = devmt: mag tape controller (4 drives)
'20 = devcp: clock / VCP / SOC
'26 = devdisk: 1st disk controller (4/8 drives)
'27 = devdisk: 2nd disk controller (4/8 drives)
'54 = 1st amlc (terminal) controller (16 lines)
'53 = 2nd amlc (terminal) controller (16 lines)
*/
static int (*devmap[64])(int, int, int) = {
/* '0x */ devnone,devnone,devnone,devnone,devasr,devnone,devnone,devpnc,
/* '0x */ devnone,devnone,devnone,devnone,devasr,devnone,devnone,devnone,
/* '1x */ devnone,devnone,devnone,devnone,devmt,devnone, devnone, devnone,
/* '2x */ devcp,devnone,devnone,devnone,devnone,devnone,devdisk,devnone,
/* '2x */ devcp,devnone,devnone,devnone,devnone,devnone,devdisk,devdisk,
/* '3x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
/* '4x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
/* '5x */ devnone,devnone,devnone,devnone,devamlc,devnone,devnone,devnone,
/* '5x */ devnone,devnone,devnone,devamlc,devamlc,devnone,devnone,devnone,
/* '6x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
/* '7x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone};
#endif
@@ -4168,17 +4242,12 @@ main (int argc, char **argv) {
static short bootdiskctrl[4] = {026, 027, 022, 023};
/* the dispatch table for generic instructions:
- bits 1-2 are the class (0-3)
- bits 3-6 are always zero
- bits 7-16 are the opcode
the index into the table is bits 1-2, 7-16, for a 12-bit index */
char *bootarg; /* argument to -boot, if any */
char bootfile[16]; /* boot file to load (optional) */
int bootfd=-1; /* initial boot file fd */
int bootctrl, bootunit; /* boot device controller and unit */
int bootskip=0; /* skip this many bytes on boot dev */
unsigned char boottaphdr[4];
short tempa,tempa1,tempa2;
unsigned short utempa,utempa1,utempa2;
@@ -4228,7 +4297,20 @@ main (int argc, char **argv) {
struct timeval boot_tv;
struct timezone tz;
printf("[Prime Emulator ver %d %s]\n", EMULATOR_VERSION, __DATE__);
/* re-open stderr as error.log */
close(2);
if ((templ = open("error.log", O_WRONLY+O_CREAT+O_TRUNC, 0644)) != 2) {
if (templ == -1)
printf("Error redirecting stderr to error.log: %s\n", strerror(errno));
else
printf("Open returned %d redirecting stderr\n", templ);
exit(1);
}
/* initialize global variables */
if (sizeof(gv) > 16*1024)
@@ -4309,7 +4391,6 @@ main (int argc, char **argv) {
gvp->iotlb[i].valid = 0;
bzero(MEM, 64*1024*2); /* zero first 64K words */
verbose = 0;
domemdump = 0;
bootarg = NULL;
bootfile[0] = 0;
@@ -4319,19 +4400,17 @@ main (int argc, char **argv) {
tport = 0;
nport = 0;
/* read license file: id, server name, port */
readlicense();
/* check args */
for (i=1; i<argc; i++) {
if (strcmp(argv[i],"-vv") == 0)
verbose = 2;
else if (strcmp(argv[i],"-v") == 0)
verbose = 1;
else if ((strcmp(argv[i],"-map") == 0) || (strcmp(argv[i],"-maps") == 0)) {
if ((strcmp(argv[i],"-map") == 0) || (strcmp(argv[i],"-maps") == 0)) {
while (i+1 < argc && argv[i+1][0] != '-')
readloadmap(argv[++i]);
readloadmap(argv[++i], 1);
} else if (strcmp(argv[i],"-memdump") == 0) {
domemdump = 1;
@@ -4341,17 +4420,31 @@ main (int argc, char **argv) {
sscanf(argv[++i],"%o", &templ);
sswitch = templ;
} else
sswitch = 0;
fatal("-ss needs an argument\n");
} else if (strcmp(argv[i],"-sd") == 0) {
if (i+1 < argc && argv[i+1][0] != '-') {
sscanf(argv[++i],"%o", &templ);
dswitch = templ;
}
} else if (strcmp(argv[i],"-boot") == 0) {
if (i+1 < argc && argv[i+1][0] != '-') {
i++;
if (strcmp(argv[i],"help") == 0)
if (strcmp(argv[i+1],"help") == 0) {
sswitch = 0;
else if (strlen(argv[i]) <= 6 && sscanf(argv[i],"%o", &templ) == 1)
sswitch = templ;
else
bootarg = argv[i];
i++;
} else {
if (sscanf(argv[i+1],"%o", &templ) == 0)
bootarg = argv[++i];
if (i+1 < argc && argv[i+1][0] != '-' && sscanf(argv[i+1],"%o", &templ) == 1) {
i++;
sswitch = templ;
}
if (i+1 < argc && argv[i+1][0] != '-' && sscanf(argv[i+1],"%o", &templ) == 1) {
i++;
dswitch = templ;
}
}
}
} else if (strcmp(argv[i],"-cpuid") == 0) {
@@ -4424,6 +4517,8 @@ main (int argc, char **argv) {
gvp->traceflags |= T_TERM;
else if (strcmp(argv[i],"rio") == 0)
gvp->traceflags |= T_RIO;
else if (strcmp(argv[i],"lm") == 0)
gvp->traceflags |= T_LM;
else if (strcmp(argv[i],"put") == 0)
gvp->traceflags |= T_PUT;
else if (strcmp(argv[i],"get") == 0)
@@ -4465,6 +4560,16 @@ main (int argc, char **argv) {
}
}
TRACEA("Boot sense switches=%06o, data switches=%06o\n", sswitch, dswitch);
/* if no maps were specified on the command line, look for ring0.map and
ring3.map in the current directory and read them */
if (numsyms == 0) {
readloadmap("ring0.map", 0);
readloadmap("ring3.map", 0);
}
/* finish setting up tracing after all options are read, ie, maps */
if (gvp->traceuser != 0)
@@ -4550,18 +4655,15 @@ main (int argc, char **argv) {
/* setup DMA register '20 (address only) for the next boot record */
regs.sym.regdmx[041] = 03000;
if (globdisk(bootfile, sizeof(bootfile), bootctrl, bootunit) != 0) {
printf("Can't find disk boot device file %s, or multiple files match this device.\nTo boot from tape (dev14u0), use -boot 10005", bootfile);
printf("Can't find disk boot device file %s, or multiple files match this device.\nTo boot from tape (mt0), use -boot 10005", bootfile);
fatal(NULL);
}
} else if ((sswitch & 0x7) == 5) { /* tape boot */
bootctrl = 014;
rvec[0] = 0200; /* tape load starts at '200 */
rvec[1] = rvec[0]+2355-1; /* read in at most 3 pages (6K) */
bootskip = 4; /* to skip .TAP header */
/* setup DMA register '20 (address only) for the next boot record */
regs.sym.regdmx[041] = 0200+2355;;
snprintf(bootfile, sizeof(bootfile), "dev%ou%d", bootctrl, bootunit);
bootskip = 4; /* to skip trailing .TAP header */
snprintf(bootfile, sizeof(bootfile), "mt%d", bootunit);
} else {
printf("\
@@ -4576,17 +4678,17 @@ runfile directly from the Unix file system. For example:\n\
\n\
For disk boots, the last 3 digits can be:\n\
\n\
114 = dev26u0 ctrl '26 unit 0 154 = dev22u0 ctrl '22 unit 0\n\
314 = dev26u1 ctrl '26 unit 1 354 = dev22u1 ctrl '22 unit 1\n\
514 = dev26u2 ctrl '26 unit 2 554 = dev22u2 ctrl '22 unit 2\n\
714 = dev26u3 ctrl '26 unit 3 754 = dev22u3 ctrl '22 unit 3\n\
114 = disk26u0 ctrl '26 unit 0 154 = disk22u0 ctrl '22 unit 0\n\
314 = disk26u1 ctrl '26 unit 1 354 = disk22u1 ctrl '22 unit 1\n\
514 = disk26u2 ctrl '26 unit 2 554 = disk22u2 ctrl '22 unit 2\n\
714 = disk26u3 ctrl '26 unit 3 754 = disk22u3 ctrl '22 unit 3\n\
\n\
134 = dev27u0 ctrl '27 unit 0 174 = dev23u0 ctrl '23 unit 0\n\
334 = dev27u1 ctrl '27 unit 1 374 = dev23u1 ctrl '23 unit 1\n\
534 = dev27u2 ctrl '27 unit 2 574 = dev23u2 ctrl '23 unit 2\n\
734 = dev27u3 ctrl '27 unit 3 774 = dev23u3 ctrl '23 unit 3\n\
134 = disk27u0 ctrl '27 unit 0 174 = disk23u0 ctrl '23 unit 0\n\
334 = disk27u1 ctrl '27 unit 1 374 = disk23u1 ctrl '23 unit 1\n\
534 = disk27u2 ctrl '27 unit 2 574 = disk23u2 ctrl '23 unit 2\n\
734 = disk27u3 ctrl '27 unit 3 774 = disk23u3 ctrl '23 unit 3\n\
\n\
The default option is -boot 14114, to boot from disk dev26u0\n");
The default option is -boot 14114, to boot from disk disk26u0\n");
exit(1);
}
@@ -4595,9 +4697,19 @@ For disk boots, the last 3 digits can be:\n\
perror("Error opening boot device file");
fatal(NULL);
}
if (lseek(bootfd, bootskip, SEEK_CUR) == -1) {
perror("Error skipping on boot device");
fatal(NULL);
/* for tape boots, read the .tap header and setup the DMA registers
as they would be following a tape device read */
if ((sswitch & 0x7) == 5) { /* tape boot */
if ((read(bootfd, boottaphdr, 4)) != 4) {
perror("Error reading boot tape header");
fatal(NULL);
}
nw = (boottaphdr[0] | boottaphdr[1]<<8 | boottaphdr[2]<<16 | boottaphdr[3]<<24)/2;
rvec[1] = rvec[0]+nw-1;
/* setup DMA register '20 (address only) for the next boot record */
regs.sym.regdmx[041] = 0200+nw;
}
}
TRACEA("Sense switches set to %o\n", sswitch);
@@ -4612,12 +4724,15 @@ For disk boots, the last 3 digits can be:\n\
perror("Error reading memory image");
fatal(NULL);
}
if (lseek(bootfd, bootskip, SEEK_CUR) == -1) {
perror("Error skipping on boot device");
fatal(NULL);
}
close(bootfd);
/* check we got it all, except for tape boots; the boot program size
is unpredictable on tape */
/* check we got it all */
if (nw2 != nw*2 && ((sswitch & 0x7) == 4 || bootarg)) {
if (nw2 != nw*2) {
printf("rvec[0]=%d, rvec[1]=%d, nw2=%d, nw=%d, nw*2=%d\n", rvec[0], rvec[1], nw2, nw, nw*2);
fatal("Didn't read entire boot program");
}
@@ -4680,8 +4795,8 @@ fetch:
#endif
#if 0
/* NOTE: doing something like this causes Primos to do a controlled
shutdown, flushing disk buffers, etc. */
/* NOTE: doing something like this sometimes causes Primos to do a
controlled shutdown, flushing disk buffers, etc. */
RPH = 07777;
#endif
@@ -5405,7 +5520,7 @@ d_zmvd: /* 001115 */
It may be worthwhile to special case a 2048-byte fill that is
page-aligned, since ZFIL is often used this way by Primos, but
it isn't a significant overall performance issue. */
this isn't a significant overall emulator performance issue. */
d_zfil: /* 001116 */
stopwatch_push(&sw_zfil);

195
emdev.h
View File

@@ -99,19 +99,6 @@
would support 4-8 physical drives, depending on the controller type.
*/
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <sys/file.h>
#include <glob.h>
#include "secure.h"
/* this macro is used when I/O is successful. In VI modes, it sets
@@ -220,7 +207,7 @@ int devnone (int class, int func, int device) {
break;
}
if (!seen[device])
fprintf(stderr, " pio to unimplemented device '%o, class '%o, func '%o\n", device, class, func);
TRACEA("pio to unimplemented device '%o, class '%o, func '%o\n", device, class, func);
seen[device] = 1;
}
@@ -1015,6 +1002,10 @@ int devmt (int class, int func, int device) {
ready = 0;
IOSKIP;
} else if (func == 011) {
crs[A] = (1 << 8) | 0214; /* backplane slot + device ID */
IOSKIP;
} else {
printf("Unimplemented INA device '%02o function '%02o\n", device, func);
fatal(NULL);
@@ -1058,12 +1049,11 @@ int devmt (int class, int func, int device) {
if (unit[u].fd == -1) {
unit[u].mtstat = 0;
unit[u].firstwrite = 1;
snprintf(devfile,sizeof(devfile),"dev%ou%d", device, u);
snprintf(devfile,sizeof(devfile),"mt%d", u);
TRACE(T_TIO, " filename for tape dev '%o unit %d is %s\n", device, u, devfile);
/* XXX: add code for read-protected tapes */
if ((unit[u].fd = open(devfile, O_RDWR, 0770)) == -1) {
if ((unit[u].fd = open(devfile, O_RDWR+O_CREAT, 0660)) == -1) {
if ((unit[u].fd = open(devfile, O_RDONLY)) == -1) {
fprintf(stderr,"em: unable to open tape device file %s for device '%o unit %d for read/write\n", devfile, device, u);
fprintf(stderr,"em: unable to open tape device file %s for device '%o unit %d\n", devfile, device, u);
IOSKIP;
break;
} else
@@ -1145,7 +1135,7 @@ int devmt (int class, int func, int device) {
/* read/write backward aren't supported */
if (((crs[A] & 0x00E0) == 0x0040) && ((crs[A] & 0x2000) == 0)) {
warn("em: read/write reverse not supported for tapes");
warn("devtape: read/write reverse not supported");
unit[u].mtstat = 0;
IOSKIP;
break;
@@ -1460,10 +1450,10 @@ int devcp (int class, int func, int device) {
crs[A] = 020; /* this is the Option-A board */
crs[A] = 0120; /* this is the SOC board */
//gvp->traceflags = ~T_MAP;
} else if (func == 016) {
} else if (func == 016) { /* read switches that are up */
crs[A] = sswitch;
} else if (func == 017) { /* read switches pushed down */
crs[A] = 0;
crs[A] = dswitch;
} else {
printf("Unimplemented INA device '%02o function '%02o\n", device, func);
fatal(NULL);
@@ -1623,7 +1613,7 @@ int globdisk (char *devfile, int size, int device, int unit) {
glob_t g;
int globerr;
snprintf(devfile, size, "dev%ou%d.*", device, unit);
snprintf(devfile, size, "disk%ou%d.*", device, unit);
if ((globerr=glob(devfile, GLOB_ERR|GLOB_NOSORT, NULL, &g)) != 0) {
fprintf(stderr,"globdisk: glob returned %d opening %s\n", globerr, devfile);
return -1;
@@ -1914,7 +1904,8 @@ int devdisk (int class, int func, int device) {
#endif
if (track > dc[dx].unit[u].maxtrack) {
fprintf(stderr," Device '%o, unit %d, seek to track %d > cylinder limit of %d\n", device, u, track, dc[dx].unit[u].maxtrack);
fatal("Invalid seek");
dc[dx].status |= 4; /* illegal seek */
break;
}
if (head > dc[dx].unit[u].heads) {
@@ -2001,8 +1992,11 @@ int devdisk (int class, int func, int device) {
memcpy((char *)iobufp, hashp, dmanw*2);
hashp += dmanw*2;
} else if ((nb=read(dc[dx].unit[u].devfd, (char *)iobufp, dmanw*2)) != dmanw*2) {
fprintf(stderr, "Disk read error: device='%o, u=%d, fd=%d, nb=%d\n", device, u, dc[dx].unit[u].devfd, nb);
if (nb == -1) perror("Unable to read drive file");
if (nb != 0) fprintf(stderr, "Disk read error: device='%o, u=%d, fd=%d, nb=%d\n", device, u, dc[dx].unit[u].devfd, nb);
if (nb == -1) {
perror("Unable to read drive file");
dc[dx].status |= 010000; /* read check */
}
memset((char *)iobufp, 0, dmanw*2);
}
if (iobufp == iobuf)
@@ -2283,24 +2277,22 @@ int devdisk (int class, int func, int device) {
#define AMLC_SET_POLL \
if ((dc[dx].ctinterrupt || dc[dx].xmitenabled || (dc[dx].recvenabled & dc[dx].connected))) \
if (devpoll[device] == 0 || devpoll[device] > AMLCPOLL*gvp->instpermsec) \
devpoll[device] = AMLCPOLL*gvp->instpermsec; /* setup another poll */
if (devpoll[device] == 0 || devpoll[device] > AMLCPOLL*gvp->instpermsec/pollspeedup) \
devpoll[device] = AMLCPOLL*gvp->instpermsec/pollspeedup; /* setup another poll */
int devamlc (int class, int func, int device) {
#define MAXLINES 128
#define MAXFD MAXLINES+20
#define MAXBOARDS 8
#define MAXROOM 1024
/* AMLC poll rate (ms). Max data rate = queue size*1000/AMLCPOLL
The max AMLC output queue size is 1023 (octal 2000), so a poll
rate of 33 (1000/33 = 30 times per second) will generate about
31,000 chars per second. This rate may be further boosted by
fastpoll getting set in the poll section, for lines with full
DMQ buffers. */
31,000 chars per second. This rate may be further boosted if
there are lines DMQ buffers with 255 or more characters. */
#define AMLCPOLL 33
#define AMLCPOLL 50
/* DSSCOUNTDOWN is the number of carrier status requests that should
occur before polling real serial devices. Primos does a carrier
@@ -2332,14 +2324,11 @@ int devamlc (int class, int func, int device) {
#define TS_OPTION 3 /* inside an option */
static short inited = 0;
static int pollspeedup = 1;
static int baudtable[16] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
static char ttymsg[1024];
static int ttymsglen = 0;
static int tsfd; /* socket fd for terminal server */
static struct { /* maps connection fd to device & line */
int dx;
int lx;
} fdtoline[MAXFD];
static struct {
unsigned short deviceid; /* this board's device ID */
@@ -2397,7 +2386,8 @@ int devamlc (int class, int func, int device) {
int baud;
struct termios terminfo;
int modemstate;
int fastpoll;
int maxxmit;
int tcpoptval;
/* save this board's device id in the dc[] array so we can tell
what order the boards should be in. This is necessary to find
@@ -2462,7 +2452,7 @@ int devamlc (int class, int func, int device) {
if ((cfgfile = fopen("amlc", "r")) == NULL) {
if (errno != ENOENT)
perror("Error opening amlc config file");
printf("em: error opening amlc config file: %s", strerror(errno));
} else {
lc = 0;
while (fgets(line, sizeof(line), cfgfile) != NULL) {
@@ -2473,22 +2463,25 @@ int devamlc (int class, int func, int device) {
else
n = sscanf(line, "%d %s", &i, devname);
if (n != 2) {
printf("devamlc: Can't parse amlc config file line %d: %s\n", lc, line);
printf("em: Can't parse amlc config file line #%d: %s\n", lc, line);
continue;
}
if (i < 0 || i >= MAXLINES) {
printf("devamlc: amlc line # '%o (%d) out of range in amlc config file, line %d: %s\n", i, i, lc, line);
printf("em: amlc line # '%o (%d) out of range in amlc config file at line #%d: %s\n", i, i, lc, line);
continue;
}
printf("devamlc: lc=%d, line '%o (%d) set to device %s\n", lc, i, i, devname);
//printf("devamlc: lc=%d, line '%o (%d) set to device %s\n", lc, i, i, devname);
dx2 = i/16;
lx = i & 0xF;
#if 1
if ((fd = open(devname, O_RDWR | O_NONBLOCK | O_EXLOCK)) == -1) {
printf("devamlc: error connecting AMLC line '%o (%d) to device %s:\n", i, i, devname);
perror("devamlc error");
#else
if ((fd = open(devname, O_RDWR | O_NONBLOCK)) == -1) {
#endif
printf("em: error connecting AMLC line '%o (%d) to device %s: %s\n", i, i, devname, strerror(errno));
continue;
}
printf("em: connected AMLC line '%o (%d) to device %s on fd %d\n", i, i, devname, fd);
printf("em: connected AMLC line '%o (%d) to device %s\n", i, i, devname);
dc[dx2].fd[lx] = fd;
dc[dx2].connected |= BITMASK16(lx+1);
dc[dx2].dedicated |= BITMASK16(lx+1);
@@ -2560,7 +2553,7 @@ int devamlc (int class, int func, int device) {
dc[dx].intenable = 0;
} else if (func == 017) { /* initialize AMLC */
//printf("devamlc: Initializing controller '%d\n", device);
//printf("devamlc: Initializing controller '%d, dx=%d\n", device, dx);
dc[dx].dmcchan = 0;
dc[dx].baseaddr = 0;
dc[dx].intvector = 0;
@@ -2616,7 +2609,7 @@ int devamlc (int class, int func, int device) {
else
dc[dx].dss &= ~BITMASK16(lx+1);
if (modemstate != dc[dx].modemstate[lx]) {
printf("devamlc: line %d modemstate was '%o now '%o\n", lx, dc[dx].modemstate[lx], modemstate);
//printf("devamlc: line %d modemstate was '%o now '%o\n", lx, dc[dx].modemstate[lx], modemstate);
dc[dx].modemstate[lx] = modemstate;
}
}
@@ -2763,8 +2756,8 @@ int devamlc (int class, int func, int device) {
}
#endif
#if 1
printf("SET terminfo: iFlag %x oFlag %x cFlag %x lFlag %x speed %d\n",
#if 0
printf("em: set terminfo: iFlag %x oFlag %x cFlag %x lFlag %x speed %d\n",
terminfo.c_iflag,
terminfo.c_oflag,
terminfo.c_cflag,
@@ -2861,19 +2854,7 @@ int devamlc (int class, int func, int device) {
case 4:
/* fastpoll gets set if the next poll should occur sooner. This
is when:
a) a line is setup with the maximum queue size and has a full
queue to send. (If the line doesn't have the max queue size,
the best way to improve speed is to increase the queue size.)
b) an end-of-range occurs on input. This speeds up input, but
also increases the chance that the user input buffer will
overflow, so it isn't enabled yet.
*/
fastpoll = 0;
maxxmit = 0;
//printf("poll device '%o, cti=%x, xmit=%x, recv=%x, dss=%x\n", device, dc[dx].ctinterrupt, dc[dx].xmitenabled, dc[dx].recvenabled, dc[dx].dss);
@@ -2888,29 +2869,24 @@ int devamlc (int class, int func, int device) {
}
} else {
allbusy = 1;
if (fd >= MAXFD) /* Note: closes below */
warn("devamlc: new socket fd is too big");
else {
for (i=0; dc[i].deviceid && i<MAXBOARDS; i++)
for (lx=0; lx<16; lx++) {
/* NOTE: don't allow connections on clock line */
if (lx == 15 && (i+1 == MAXBOARDS || !dc[i+1].deviceid))
break;
if (dc[i].fd[lx] < 0 && dc[i].ctype[lx] == CT_SOCKET) {
allbusy = 0;
fdtoline[fd].dx = i;
fdtoline[fd].lx = lx;
dc[i].dss |= BITMASK16(lx+1);
dc[i].connected |= BITMASK16(lx+1);
dc[i].fd[lx] = fd;
dc[i].tstate[lx] = TS_DATA;
dc[i].room[lx] = MAXROOM;
dc[i].ctype[lx] = CT_SOCKET;
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, dc[i].deviceid, lx);
for (i=0; dc[i].deviceid && i<MAXBOARDS; i++)
for (lx=0; lx<16; lx++) {
/* NOTE: don't allow connections on clock line */
if (lx == 15 && (i+1 == MAXBOARDS || !dc[i+1].deviceid))
break;
}
if (dc[i].fd[lx] < 0 && dc[i].ctype[lx] == CT_SOCKET) {
allbusy = 0;
dc[i].dss |= BITMASK16(lx+1);
dc[i].connected |= BITMASK16(lx+1);
dc[i].fd[lx] = fd;
dc[i].tstate[lx] = TS_DATA;
dc[i].room[lx] = MAXROOM;
dc[i].ctype[lx] = CT_SOCKET;
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, dc[i].deviceid, lx);
goto endconnect;
}
}
}
endconnect:
if (allbusy) {
warn("No free AMLC connection");
write(fd, "\rAll AMLC lines are in use!\r\n", 29);
@@ -2919,13 +2895,14 @@ int devamlc (int class, int func, int device) {
if ((tsflags = fcntl(fd, F_GETFL)) == -1) {
perror("unable to get ts flags for AMLC line");
fatal(NULL);
}
tsflags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, tsflags) == -1) {
perror("unable to set ts flags for AMLC line");
fatal(NULL);
}
tcpoptval = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &tcpoptval, sizeof(tcpoptval)) == -1)
perror("unable to set TCP_NODELAY");
/* these Telnet commands put the connecting telnet client
into character-at-a-time mode and binary mode. Since
@@ -3049,8 +3026,8 @@ int devamlc (int class, int func, int device) {
put16io(qtop, qcbea);
} else
put16io(0, dc[dx].baseaddr + lx);
if (nw == 1023)
fastpoll = 1;
if (nw > maxxmit)
maxxmit = nw;
} else if (nw == -1)
if (errno == EAGAIN || errno == EWOULDBLOCK)
;
@@ -3158,7 +3135,7 @@ int devamlc (int class, int func, int device) {
state so no telnet processing occurs. */
if (n > 0) {
//printf("devamlc: RECV, b=%d, tried=%d, read=%d\n", dc[dx].bufnum, n2, n);
//printf("devamlc: RECV dx=%d, lx=%d, b=%d, tried=%d, read=%d\n", dx, lx, dc[dx].bufnum, n2, n);
state = dc[dx].tstate[lx];
for (i=0; i<n; i++) {
ch = buf[i];
@@ -3217,7 +3194,17 @@ int devamlc (int class, int func, int device) {
}
}
/* time to interrupt? */
/* time to interrupt?
XXX: might be a bug here: with multiple controllers, maybe only
the last controller (with ctinterrupt set) will get high
performance (higher poll rates) while others will get the
standard poll rate. If a non-clock-line controller wants
faster polling, we probably need to generate an interrupt on
the clock line controller to cause AMLDIM to refill the
buffers, or force the ctinterrupt status bit to be returned
on the next status request.
*/
if (dc[dx].intenable && (dc[dx].ctinterrupt || dc[dx].eor)) {
if (gvp->intvec == -1) {
@@ -3237,12 +3224,32 @@ int devamlc (int class, int func, int device) {
(the last board), so it will always be polling and checking
for new incoming connections */
/* the largest DMQ buffer size is 1023 chars. If any line's DMQ
buffer is getting filled completely, then we need to poll
faster to increase throughput. If the max queue size falls
below 256, then decrease the interrupt rate. Anywhere between
256-1022, leave the poll rate alone.
XXX NOTE: polling faster only causes AMLDIM to fill buffers
faster for the last AMLC board (with ctinterrupt set).
*/
#if 1
if (maxxmit >= 1023) {
if (pollspeedup < 8) {
pollspeedup++;
//printf("%d ", pollspeedup);
//fflush(stdout);
}
} else if (pollspeedup > 1 && maxxmit < 256) {
pollspeedup--;
//printf("%d ", pollspeedup);
//fflush(stdout);
}
#endif
AMLC_SET_POLL;
/* not sure the best way to "poll faster"; this is just a hack */
if (fastpoll)
devpoll[device] = devpoll[device]/4;
break;
}
}
@@ -3982,8 +3989,6 @@ xmitdone:
for (lx=0; lx<16; lx++)
if (!(dc[devices[i]].dss & BITMASK16(lx+1))) {
newdevice = devices[i];
fdtoline[fd].device = newdevice;
fdtoline[fd].line = lx;
dc[newdevice].dss |= BITMASK16(lx+1);
dc[newdevice].sockfd[lx] = fd;
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, newdevice, lx);

7
geom.h
View File

@@ -25,7 +25,7 @@
static int geomcksum = 358767254;
#else
#define NUMGEOM 24
#define NUMGEOM 25
#define MAXDRIVES 8
#define MAXCTRL 8
@@ -38,7 +38,7 @@
} geom[NUMGEOM] = {
1, "80M", 5, 9, 823,
1, "300M", 19, 9, 823,
0, "CMD", 20, 9, 823,
2, "CMD", 21, 9, 823,
4, "68M", 3, 9, 1119,
5, "158M", 7, 9, 1119,
6, "160M", 10, 9, 821,
@@ -51,6 +51,7 @@
13, "496M", 24, 14, 711, /* MODEL_4735 */
14, "258M", 17, 6, 1220, /* MODEL_4719 */
15, "770M", 23, 19, 848, /* MODEL_4845 */
16, "1.1G", 27, 19, 1022, /* MODEL_4935 */
17, "328A", 12, 8, 1641, /* MODEL_4721 */
17, "328B", 31, 254, 20, /* MODEL_4721 (7210 SCSI controller) */
18, "817M", 15, 19, 1379, /* MODEL_4860 */
@@ -62,5 +63,5 @@
25, "2G", 31, 254, 122, /* MODEL_4736 */
};
static int geomcksum = 17176324;
static int geomcksum = -698140431;
#endif