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:
347
em.c
347
em.c
@@ -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
195
emdev.h
@@ -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
7
geom.h
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user