mirror of
https://github.com/simh/simh.git
synced 2026-01-25 19:56:25 +00:00
Notes For V3.1-0
RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially debugged. Do NOT enable these features for normal operations. 1. New Features in 3.1-0 1.1 SCP and libraries - Added simulated Ethernet support for VMS, FreeBSD, Mac OS/X. - Added status return to tmxr_putc_ln. - Added sim_putchar_s to handle possible output stalls. 1.2 All DECtapes - Added "DECtape off reel" error stop. 1.3 All Asynchronous Consoles - Added support for output congestion stall if using a Telnet connection. 1.4 PDP-1 - Added Type 23 parallel drum support. 1.5 PDP-8 - Added instruction history. - Added TSC8-75 option support for ETOS. - Added TD8E DECtape support. 1.6 PDP-18b - Added instruction history. - Changed PDP-9, PDP-15 API default to enabled. 1.7 PDP-11 - Added support for 18b only Qbus devices. - Formalized bus and addressing definitions. - Added control to enable/disable autoconfiguration. - Added stub support for second Unibus Ethernet controller. 1.7 Interdata 32b - Added instruction history. 1.8 Eclipse - Added floating point support. - Added programmable interval timer support. 1.9 H316 - Added DMA/DMC support. - Added fixed head disk support. - Added moving head disk support. - Added magtape support. 1.10 IBM 1130 (Brian Knittel) - Added support for physical card reader, using the Cardread interface (www.ibm1130.org/sim/downloads). - Added support for physical printer (flushes output buffer after each line). 2. Bugs Fixed in 3.1-0 2.1 SCP and libraries - Fixed numerous bugs in Ethernet library. 2.2 All DECtapes - Fixed reverse checksum value in 'read all' mode. - Simplified (and sped up) timing. 2.3 PDP-8 - Fixed bug in RX28 read status (found by Charles Dickman). - Fixed RX28 double density write. 2.4 PDP-18b - Fixed autoincrement bug in PDP-4, PDP-7, PDP-9. 2.5 PDP-11/VAX - Revised RQ MB->LBN conversion for greater accuracy. - Fixed bug in IO configuration (found by David Hittner). - Fixed bug with multiple RQ RAUSER drives. - Fixed bug in second Qbus Ethernet controller interrupts. 2.6 Nova/Eclipse - Fixed bugs in DKP flag clear, map setup, map usage (Charles Owen). - Fixed bug in MT, reset completes despite I/O reset (Charles Owen). - Fixed bug in MT, space operations return word count (Charles Owen). 2.7 IBM 1130 (Brian Knittel) - Fixed bug in setting carry bit in subtract and subtract double. - Fixed timing problem in console printer simulation. 2.8 1620 - Fixed bug in branch digit (found by Dave Babcock). 3. New Features in 3.0 vs prior releases 3.1 SCP and Libraries - Added ASSIGN/DEASSIGN (logical name) commands. - Changed RESTORE to unconditionally detach files. - Added E11 and TPC format support to magtape library. - Fixed bug in SHOW CONNECTIONS. - Added USE_ADDR64 support. 3.2 All magtapes - Magtapes support SIMH format, E11 format, and TPC format (read only). - SET <tape_unit> FORMAT=format sets the specified tape unit's format. - SHOW <tape_unit> FORMAT displays the specified tape unit's format. - Tape format can also be set as part of the ATTACH command, using the -F switch. 3.3 VAX - VAX can be compiled without USE_INT64. - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support files > 2GB. - VAX ROM has speed control (SET ROM DELAY/NODELAY). 3.4 PDP-1 - Added block loader format support to LOAD. - Changed BOOT PTR to allow loading of all of the first bank of memory. - The LOAD command takes an optional argument specifying the memory field to be loaded. - The PTR BOOT command takes its starting memory field from the TA (address switch) register. 3.5 PDP-18b Family - Added PDP-4 EAE support. - Added PDP-15 FP15 support. - Added PDP-15 XVM support. - Added PDP-15 "re-entrancy ECO". - Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR. 4. Bugs Fixed in 3.0 vs prior releases 4.1 SCP and Libraries - Fixed end of file problem in dep, idep. - Fixed handling of trailing spaces in dep, idep. 4.2 VAX - Fixed CVTfi bug: integer overflow not set if exponent out of range - Fixed EMODx bugs: o First and second operands reversed o Separated fraction received wrong exponent o Overflow calculation on separated integer incorrect o Fraction not set to zero if exponent out of range - Fixed interval timer and ROM access to pass power-up self-test even on very fast host processors (fixes from Mark Pizzolato). - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.3 1401 - Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. - Fixed MCE bug, BS off by 1 if zero suppress. - Fixed chaining bug, D lost if return to SCP. - Fixed H branch, branch occurs after continue. - Added check for invalid 8 character MCW, LCA. - Fixed magtape load-mode end of record response. - Revised fetch to model hardware more closely. - Fixed tape read end-of-record handling based on real 1401. - Added diagnostic read (space forward). 4.4 Nova - Fixed DSK variable size interaction with restore. - Fixed bug in DSK set size routine. 4.5 PDP-1 - Fixed DT variable size interaction with restore. - Updated CPU, line printer, standard devices to detect indefinite I/O wait. - Fixed incorrect logical, missing activate, break in drum simulator. - Fixed bugs in instruction decoding, overprinting for line printer. - Fixed system hang if continue after PTR error. - Fixed PTR to start/stop on successive rpa instructions. 4.6 PDP-11 - Fixed DT variable size interaction with restore. - Fixed bug in MMR1 update (found by Tim Stark). - Added XQ features and fixed bugs: o Corrected XQ interrupts on IE state transition (code by Tom Evans). o Added XQ interrupt clear on soft reset. o Removed XQ interrupt when setting XL or RL (multiple people). o Added SET/SHOW XQ STATS. o Added SHOW XQ FILTERS. o Added ability to split received packet into multiple buffers. o Added explicit runt and giant packet processing. - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.7 PDP-18B - Fixed DT, RF variable size interaction with restore. - Fixed MT bug in MTTR. - Fixed bug in PDP-4 line printer overprinting. - Fixed bug in PDP-15 memory protect/skip interaction. - Fixed bug in RF set size routine. - Increased PTP TIME for PDP-15 operating systems. - Fixed priorities in PDP-15 API (differs from PDP-9). - Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9). - Fixed bug in CAF, clears API subsystem. 4.8 PDP-8 - Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed MT bug in SKTR. - Fixed bug in DF, RF set size routine. 4.9 HP2100 - Fixed bug in DP (13210A controller only), DQ read status. - Fixed bug in DP, DQ seek complete. - Fixed DR drum sizes. - Fixed DR variable capacity interaction with SAVE/RESTORE. 4.10 GRI - Fixed bug in SC queue pointer management. 4.11 PDP-10 - Fixed bug in RP read header. 4.12 Ibm1130 - Fixed bugs found by APL 1130. 4.13 Altairz80 - Fixed bug in real-time clock on Windows host. 4.14 1620 - Fixed bug in immediate index add (found by Michael Short).
This commit is contained in:
committed by
Mark Pizzolato
parent
b2101ecdd4
commit
1da2d9452d
362
PDP8/pdp8_cpu.c
362
PDP8/pdp8_cpu.c
@@ -1,6 +1,6 @@
|
||||
/* pdp8_cpu.c: PDP-8 CPU simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
Copyright (c) 1993-2004, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
cpu central processor
|
||||
|
||||
31-Dec-03 RMS Fixed bug in set_cpu_hist
|
||||
13-Oct-03 RMS Added instruction history
|
||||
Added TSC8-75 support (from Bernhard Baehr)
|
||||
12-Mar-03 RMS Added logical name support
|
||||
04-Oct-02 RMS Revamped device dispatching, added device number support
|
||||
06-Jan-02 RMS Added device enable/disable routines
|
||||
@@ -184,12 +187,23 @@
|
||||
|
||||
#define PCQ_SIZE 64 /* must be 2**n */
|
||||
#define PCQ_MASK (PCQ_SIZE - 1)
|
||||
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
|
||||
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = MA
|
||||
#define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */
|
||||
#define UNIT_NOEAE (1 << UNIT_V_NOEAE)
|
||||
#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */
|
||||
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
|
||||
|
||||
#define HIST_PC 0x40000000
|
||||
#define HIST_MIN 64
|
||||
#define HIST_MAX 65536
|
||||
struct InstHistory {
|
||||
int32 pc;
|
||||
int32 ea;
|
||||
int16 ir;
|
||||
int16 opnd;
|
||||
int16 lac;
|
||||
int16 mq; };
|
||||
|
||||
uint16 M[MAXMEMSIZE] = { 0 }; /* main memory */
|
||||
int32 saved_LAC = 0; /* saved L'AC */
|
||||
int32 saved_MQ = 0; /* saved MQ */
|
||||
@@ -203,6 +217,10 @@ int32 SC = 0; /* EAE shift count */
|
||||
int32 UB = 0; /* User mode Buffer */
|
||||
int32 UF = 0; /* User mode Flag */
|
||||
int32 OSR = 0; /* Switch Register */
|
||||
int32 tsc_ir = 0; /* TSC8-75 IR */
|
||||
int32 tsc_pc = 0; /* TSC8-75 PC */
|
||||
int32 tsc_cdf = 0; /* TSC8-75 CDF flag */
|
||||
int32 tsc_enb = 0; /* TSC8-75 enabled */
|
||||
int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
|
||||
int32 pcq_p = 0; /* PC queue ptr */
|
||||
REG *pcq_r = NULL; /* PC queue reg ptr */
|
||||
@@ -211,6 +229,9 @@ int32 int_enable = INT_INIT_ENABLE; /* intr enables */
|
||||
int32 int_req = 0; /* intr requests */
|
||||
int32 stop_inst = 0; /* trap on ill inst */
|
||||
int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat); /* device dispatch */
|
||||
int32 hst_p = 0; /* history pointer */
|
||||
int32 hst_lnt = 0; /* history length */
|
||||
struct InstHistory *hst = NULL; /* instruction history */
|
||||
|
||||
extern int32 sim_interval;
|
||||
extern int32 sim_int_char;
|
||||
@@ -223,6 +244,8 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_reset (DEVICE *dptr);
|
||||
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
t_bool build_dev_tab (void);
|
||||
|
||||
/* CPU data structures
|
||||
@@ -275,6 +298,8 @@ MTAB cpu_mod[] = {
|
||||
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY",
|
||||
&cpu_set_hist, &cpu_show_hist },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE cpu_dev = {
|
||||
@@ -335,9 +360,8 @@ sim_interval = sim_interval - 1;
|
||||
major opcode. For IOT, the extra decode points are not useful;
|
||||
for OPR, only the group flag (IR<3>) is used.
|
||||
|
||||
The following macros define the address calculations for data and
|
||||
jump calculations. Data calculations return a full 15b extended
|
||||
address, jump calculations a 12b field-relative address.
|
||||
AND, TAD, ISZ, DCA calculate a full 15b effective address.
|
||||
JMS, JMP calculate a 12b field-relative effective address.
|
||||
|
||||
Autoindex calculations always occur within the same field as the
|
||||
instruction fetch. The field must exist; otherwise, the instruction
|
||||
@@ -346,84 +370,103 @@ sim_interval = sim_interval - 1;
|
||||
Note that MA contains IF'PC.
|
||||
*/
|
||||
|
||||
#define ZERO_PAGE MA = IF | (IR & 0177)
|
||||
#define CURR_PAGE MA = (MA & 077600) | (IR & 0177)
|
||||
#define INDIRECT if ((MA & 07770) != 00010) MA = DF | M[MA]; \
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777)
|
||||
if (hst_lnt) { /* history enabled? */
|
||||
int32 ea;
|
||||
|
||||
#define ZERO_PAGE_J MA = IR & 0177
|
||||
#define CURR_PAGE_J MA = (MA & 007600) | (IR & 0177)
|
||||
#define INDIRECT_J if ((MA & 07770) != 00010) MA = M[MA]; \
|
||||
else MA = (M[MA] = (M[MA] + 1) & 07777)
|
||||
#define CHANGE_FIELD IF = IB; UF = UB; \
|
||||
int_req = int_req | INT_NO_CIF_PENDING
|
||||
hst_p = (hst_p + 1); /* next entry */
|
||||
if (hst_p >= hst_lnt) hst_p = 0;
|
||||
hst[hst_p].pc = MA | HIST_PC; /* save PC, IR, LAC, MQ */
|
||||
hst[hst_p].ir = IR;
|
||||
hst[hst_p].lac = LAC;
|
||||
hst[hst_p].mq = MQ;
|
||||
if (IR < 06000) { /* mem ref? */
|
||||
if (IR & 0200) ea = (MA & 077600) | (IR & 0177);
|
||||
else ea = IF | (IR & 0177); /* direct addr */
|
||||
if (IR & 0400) { /* indirect? */
|
||||
if (IR < 04000) { /* mem operand? */
|
||||
if ((ea & 07770) != 00010) ea = DF | M[ea];
|
||||
else ea = DF | ((M[ea] + 1) & 07777); }
|
||||
else { /* no, jms/jmp */
|
||||
if ((ea & 07770) != 00010) ea = IB | M[ea];
|
||||
else ea = IB | ((M[ea] + 1) & 07777); }
|
||||
}
|
||||
hst[hst_p].ea = ea; /* save eff addr */
|
||||
hst[hst_p].opnd = M[ea]; /* save operand */
|
||||
}
|
||||
}
|
||||
|
||||
switch ((IR >> 7) & 037) { /* decode IR<0:4> */
|
||||
|
||||
/* Opcode 0, AND */
|
||||
|
||||
case 000: /* AND, dir, zero */
|
||||
ZERO_PAGE;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
LAC = LAC & (M[MA] | 010000);
|
||||
break;
|
||||
case 001: /* AND, dir, curr */
|
||||
CURR_PAGE;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
LAC = LAC & (M[MA] | 010000);
|
||||
break;
|
||||
case 002: /* AND, indir, zero */
|
||||
ZERO_PAGE;
|
||||
INDIRECT;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
LAC = LAC & (M[MA] | 010000);
|
||||
break;
|
||||
case 003: /* AND, indir, curr */
|
||||
CURR_PAGE;
|
||||
INDIRECT;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
LAC = LAC & (M[MA] | 010000);
|
||||
break;
|
||||
|
||||
/* Opcode 1, TAD */
|
||||
|
||||
case 004: /* TAD, dir, zero */
|
||||
ZERO_PAGE;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
LAC = (LAC + M[MA]) & 017777;
|
||||
break;
|
||||
case 005: /* TAD, dir, curr */
|
||||
CURR_PAGE;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
LAC = (LAC + M[MA]) & 017777;
|
||||
break;
|
||||
case 006: /* TAD, indir, zero */
|
||||
ZERO_PAGE;
|
||||
INDIRECT;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
LAC = (LAC + M[MA]) & 017777;
|
||||
break;
|
||||
case 007: /* TAD, indir, curr */
|
||||
CURR_PAGE;
|
||||
INDIRECT;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
LAC = (LAC + M[MA]) & 017777;
|
||||
break;
|
||||
|
||||
/* Opcode 2, ISZ */
|
||||
|
||||
case 010: /* ISZ, dir, zero */
|
||||
ZERO_PAGE;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */
|
||||
if (MB == 0) PC = (PC + 1) & 07777;
|
||||
break;
|
||||
case 011: /* ISZ, dir, curr */
|
||||
CURR_PAGE;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */
|
||||
if (MB == 0) PC = (PC + 1) & 07777;
|
||||
break;
|
||||
case 012: /* ISZ, indir, zero */
|
||||
ZERO_PAGE;
|
||||
INDIRECT;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
MB = (M[MA] + 1) & 07777;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = MB;
|
||||
if (MB == 0) PC = (PC + 1) & 07777;
|
||||
break;
|
||||
case 013: /* ISZ, indir, curr */
|
||||
CURR_PAGE;
|
||||
INDIRECT;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
MB = (M[MA] + 1) & 07777;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = MB;
|
||||
if (MB == 0) PC = (PC + 1) & 07777;
|
||||
@@ -432,91 +475,178 @@ case 013: /* ISZ, indir, curr */
|
||||
/* Opcode 3, DCA */
|
||||
|
||||
case 014: /* DCA, dir, zero */
|
||||
ZERO_PAGE;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
M[MA] = LAC & 07777;
|
||||
LAC = LAC & 010000;
|
||||
break;
|
||||
case 015: /* DCA, dir, curr */
|
||||
CURR_PAGE;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
M[MA] = LAC & 07777;
|
||||
LAC = LAC & 010000;
|
||||
break;
|
||||
case 016: /* DCA, indir, zero */
|
||||
ZERO_PAGE;
|
||||
INDIRECT;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;
|
||||
LAC = LAC & 010000;
|
||||
break;
|
||||
case 017: /* DCA, indir, curr */
|
||||
CURR_PAGE;
|
||||
INDIRECT;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;
|
||||
LAC = LAC & 010000;
|
||||
break;
|
||||
|
||||
/* Opcode 4, JMS */
|
||||
/* Opcode 4, JMS. From Bernhard Baehr's description of the TSC8-75:
|
||||
|
||||
(In user mode) the current JMS opcode is moved to the ERIOT register, the ECDF
|
||||
flag is cleared. The address of the JMS instruction is loaded into the ERTB
|
||||
register and the TSC8-75 I/O flag is raised. When the TSC8-75 is enabled, the
|
||||
target addess of the JMS is loaded into PC, but nothing else (loading of IF, UF,
|
||||
clearing the interrupt inhibit flag, storing of the return address in the first
|
||||
word of the subroutine) happens. When the TSC8-75 is disabled, the JMS is performed
|
||||
as usual. */
|
||||
|
||||
case 020: /* JMS, dir, zero */
|
||||
ZERO_PAGE_J;
|
||||
CHANGE_FIELD;
|
||||
MA = IF | MA;
|
||||
PCQ_ENTRY;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC;
|
||||
MA = IR & 0177; /* dir addr, page zero */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; } /* clear flag */
|
||||
if (UF && tsc_enb) { /* user mode, TSC enab? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } /* request intr */
|
||||
else { /* normal */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
MA = IF | MA;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC; }
|
||||
PC = (MA + 1) & 07777;
|
||||
break;
|
||||
case 021: /* JMS, dir, curr */
|
||||
CURR_PAGE_J;
|
||||
CHANGE_FIELD;
|
||||
MA = IF | MA;
|
||||
PCQ_ENTRY;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC;
|
||||
MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; } /* clear flag */
|
||||
if (UF && tsc_enb) { /* user mode, TSC enab? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } /* request intr */
|
||||
else { /* normal */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
MA = IF | MA;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC; }
|
||||
PC = (MA + 1) & 07777;
|
||||
break;
|
||||
case 022: /* JMS, indir, zero */
|
||||
ZERO_PAGE;
|
||||
INDIRECT_J;
|
||||
CHANGE_FIELD;
|
||||
MA = IF | MA;
|
||||
PCQ_ENTRY;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */
|
||||
else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; } /* clear flag */
|
||||
if (UF && tsc_enb) { /* user mode, TSC enab? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } /* request intr */
|
||||
else { /* normal */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
MA = IF | MA;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC; }
|
||||
PC = (MA + 1) & 07777;
|
||||
break;
|
||||
case 023: /* JMS, indir, curr */
|
||||
CURR_PAGE;
|
||||
INDIRECT_J;
|
||||
CHANGE_FIELD;
|
||||
MA = IF | MA;
|
||||
PCQ_ENTRY;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */
|
||||
else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; } /* clear flag */
|
||||
if (UF && tsc_enb) { /* user mode, TSC enab? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } /* request intr */
|
||||
else { /* normal */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
MA = IF | MA;
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = PC; }
|
||||
PC = (MA + 1) & 07777;
|
||||
break;
|
||||
|
||||
/* Opcode 5, JMP. From Bernhard Baehr's description of the TSC8-75:
|
||||
|
||||
/* Opcode 5, JMP */
|
||||
(In user mode) the current JMP opcode is moved to the ERIOT register, the ECDF
|
||||
flag is cleared. The address of the JMP instruction is loaded into the ERTB
|
||||
register and the TSC8-75 I/O flag is raised. Then the JMP is performed as usual
|
||||
(including the setting of IF, UF and clearing the interrupt inhibit flag). */
|
||||
|
||||
case 024: /* JMP, dir, zero */
|
||||
ZERO_PAGE_J;
|
||||
CHANGE_FIELD;
|
||||
PCQ_ENTRY;
|
||||
MA = IR & 0177; /* dir addr, page zero */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; /* clear flag */
|
||||
if (tsc_enb) { /* TSC8 enabled? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } } /* request intr */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
PC = MA;
|
||||
break;
|
||||
case 025: /* JMP, dir, curr */
|
||||
CURR_PAGE_J;
|
||||
CHANGE_FIELD;
|
||||
PCQ_ENTRY;
|
||||
MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; /* clear flag */
|
||||
if (tsc_enb) { /* TSC8 enabled? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } } /* request intr */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
PC = MA;
|
||||
break;
|
||||
case 026: /* JMP, indir, zero */
|
||||
ZERO_PAGE;
|
||||
INDIRECT_J;
|
||||
CHANGE_FIELD;
|
||||
PCQ_ENTRY;
|
||||
MA = IF | (IR & 0177); /* dir addr, page zero */
|
||||
if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */
|
||||
else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; /* clear flag */
|
||||
if (tsc_enb) { /* TSC8 enabled? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } } /* request intr */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
PC = MA;
|
||||
break;
|
||||
case 027: /* JMP, indir, curr */
|
||||
CURR_PAGE;
|
||||
INDIRECT_J;
|
||||
CHANGE_FIELD;
|
||||
PCQ_ENTRY;
|
||||
MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */
|
||||
if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */
|
||||
else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
if (UF) { /* user mode? */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; /* clear flag */
|
||||
if (tsc_enb) { /* TSC8 enabled? */
|
||||
tsc_pc = (PC - 1) & 07777; /* save PC */
|
||||
int_req = int_req | INT_TSC; } } /* request intr */
|
||||
IF = IB; /* change IF */
|
||||
UF = UB; /* change UF */
|
||||
int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */
|
||||
PC = MA;
|
||||
break;
|
||||
|
||||
@@ -601,7 +731,11 @@ case 034:case 035: /* OPR, group 1 */
|
||||
break; } /* uses address path */
|
||||
break; /* end group 1 */
|
||||
|
||||
/* OPR group 2 */
|
||||
/* OPR group 2. From Bernhard Baehr's description of the TSC8-75:
|
||||
|
||||
(In user mode) HLT (7402), OSR (7404) and microprogrammed combinations with
|
||||
HLT and OSR: Additional to raising a user mode interrupt, the current OPR
|
||||
opcode is moved to the ERIOT register and the ECDF flag is cleared. */
|
||||
|
||||
case 036:case 037: /* OPR, groups 2, 3 */
|
||||
if ((IR & 01) == 0) { /* group 2 */
|
||||
@@ -657,7 +791,10 @@ case 036:case 037: /* OPR, groups 2, 3 */
|
||||
if ((LAC < 04000) && (LAC != 0)) PC = (PC + 1) & 07777;
|
||||
break; } /* end switch skips */
|
||||
if (IR & 0200) LAC = LAC & 010000; /* CLA */
|
||||
if ((IR & 06) && UF) int_req = int_req | INT_UF;
|
||||
if ((IR & 06) && UF) { /* user mode? */
|
||||
int_req = int_req | INT_UF; /* request intr */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
tsc_cdf = 0; } /* clear flag */
|
||||
else {
|
||||
if (IR & 04) LAC = LAC | OSR; /* OSR */
|
||||
if (IR & 02) reason = STOP_HALT; } /* HLT */
|
||||
@@ -745,7 +882,8 @@ case 036:case 037: /* OPR, groups 2, 3 */
|
||||
case 021: /* mode B: DAD */
|
||||
if (emode) {
|
||||
MA = IF | PC;
|
||||
INDIRECT; /* defer state */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
MQ = MQ + M[MA];
|
||||
MA = DF | ((MA + 1) & 07777);
|
||||
LAC = (LAC & 07777) + M[MA] + (MQ >> 12);
|
||||
@@ -764,7 +902,8 @@ case 036:case 037: /* OPR, groups 2, 3 */
|
||||
case 022: /* mode B: DST */
|
||||
if (emode) {
|
||||
MA = IF | PC;
|
||||
INDIRECT; /* defer state */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = MQ & 07777;
|
||||
MA = DF | ((MA + 1) & 07777);
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;
|
||||
@@ -773,7 +912,10 @@ case 036:case 037: /* OPR, groups 2, 3 */
|
||||
LAC = LAC | SC; /* mode A: SCA then */
|
||||
case 002: /* MUY */
|
||||
MA = IF | PC;
|
||||
if (emode) { INDIRECT; } /* mode B: defer */
|
||||
if (emode) { /* mode B: defer */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
}
|
||||
temp = (MQ * M[MA]) + (LAC & 07777);
|
||||
LAC = (temp >> 12) & 07777;
|
||||
MQ = temp & 07777;
|
||||
@@ -788,7 +930,10 @@ case 036:case 037: /* OPR, groups 2, 3 */
|
||||
LAC = LAC | SC; /* mode A: SCA then */
|
||||
case 003: /* DVI */
|
||||
MA = IF | PC;
|
||||
if (emode) { INDIRECT; } /* mode B: defer */
|
||||
if (emode) { /* mode B: defer */
|
||||
if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */
|
||||
else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
|
||||
}
|
||||
if ((LAC & 07777) >= M[MA]) { /* overflow? */
|
||||
LAC = LAC | 010000; /* set link */
|
||||
MQ = ((MQ << 1) + 1) & 07777; /* rotate MQ */
|
||||
@@ -873,11 +1018,18 @@ case 036:case 037: /* OPR, groups 2, 3 */
|
||||
break; } /* end switch */
|
||||
break; /* end case 7 */
|
||||
|
||||
/* Opcode 6, IOT */
|
||||
/* Opcode 6, IOT. From Bernhard Baehr's description of the TSC8-75:
|
||||
|
||||
(In user mode) Additional to raising a user mode interrupt, the current IOT
|
||||
opcode is moved to the ERIOT register. When the IOT is a CDF instruction (62x1),
|
||||
the ECDF flag is set, otherwise it is cleared. */
|
||||
|
||||
case 030:case 031:case 032:case 033: /* IOT */
|
||||
if (UF) { /* privileged? */
|
||||
int_req = int_req | INT_UF;
|
||||
int_req = int_req | INT_UF; /* request intr */
|
||||
tsc_ir = IR; /* save instruction */
|
||||
if ((IR & 07707) == 06201) tsc_cdf = 1; /* set/clear flag */
|
||||
else tsc_cdf = 0;
|
||||
break; }
|
||||
device = (IR >> 3) & 077; /* device = IR<3:8> */
|
||||
pulse = IR & 07; /* pulse = IR<9:11> */
|
||||
@@ -922,6 +1074,7 @@ case 030:case 031:case 032:case 033: /* IOT */
|
||||
dev_done = 0;
|
||||
int_enable = INT_INIT_ENABLE;
|
||||
LAC = 0;
|
||||
reset_all (1); /* reset all dev */
|
||||
break; } /* end switch pulse */
|
||||
break; /* end case 0 */
|
||||
|
||||
@@ -1143,3 +1296,58 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */
|
||||
} /* end for i */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Set history */
|
||||
|
||||
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 i, lnt;
|
||||
t_stat r;
|
||||
|
||||
if (cptr == NULL) {
|
||||
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
|
||||
hst_p = 0;
|
||||
return SCPE_OK; }
|
||||
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
|
||||
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
|
||||
hst_p = 0;
|
||||
if (hst_lnt) {
|
||||
free (hst);
|
||||
hst_lnt = 0;
|
||||
hst = NULL; }
|
||||
if (lnt) {
|
||||
hst = calloc (sizeof (struct InstHistory), lnt);
|
||||
if (hst == NULL) return SCPE_MEM;
|
||||
hst_lnt = lnt; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show history */
|
||||
|
||||
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
int32 l, k, di;
|
||||
t_value sim_eval;
|
||||
struct InstHistory *h;
|
||||
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw);
|
||||
|
||||
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
|
||||
fprintf (st, "PC L AC MQ ea IR\n\n");
|
||||
di = hst_p; /* work forward */
|
||||
for (k = 0; k < hst_lnt; k++) { /* print specified */
|
||||
h = &hst[(++di) % hst_lnt]; /* entry pointer */
|
||||
if (h->pc & HIST_PC) { /* instruction? */
|
||||
l = (h->lac >> 12) & 1; /* link */
|
||||
fprintf (st, "%05o %o %04o %04o ", h->pc & ADDRMASK, l, h->lac & 07777, h->mq);
|
||||
if (h->ir < 06000) fprintf (st, "%05o ", h->ea);
|
||||
else fprintf (st, " ");
|
||||
sim_eval = h->ir;
|
||||
if ((fprint_sym (st, h->pc & ADDRMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
|
||||
fprintf (st, "(undefined) %04o", h->ir);
|
||||
if (h->ir < 04000) fprintf (st, " [%04o]", h->opnd);
|
||||
fputc ('\n', st); /* end line */
|
||||
} /* end else instruction */
|
||||
} /* end for */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
13-Oct-03 RMS Added TSC8-75 support
|
||||
04-Oct-02 RMS Added variable device number support
|
||||
20-Jan-02 RMS Fixed bug in TTx interrupt enable initialization
|
||||
25-Nov-01 RMS Added RL8A support
|
||||
@@ -45,6 +46,7 @@
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_NOTSTD 4 /* non-std devno */
|
||||
#define STOP_DTOFF 5 /* DECtape off reel */
|
||||
|
||||
/* Memory */
|
||||
|
||||
@@ -86,6 +88,7 @@ typedef struct pdp8_dib DIB;
|
||||
#define DEV_TTI 003 /* console input */
|
||||
#define DEV_TTO 004 /* console output */
|
||||
#define DEV_CLK 013 /* clock */
|
||||
#define DEV_TSC 036
|
||||
#define DEV_KJ8 040 /* extra terminals */
|
||||
#define DEV_DF 060 /* DF32 */
|
||||
#define DEV_RF 060 /* RF08 */
|
||||
@@ -95,6 +98,7 @@ typedef struct pdp8_dib DIB;
|
||||
#define DEV_RK 074 /* RK8E */
|
||||
#define DEV_RX 075 /* RX8E/RX28 */
|
||||
#define DEV_DTA 076 /* TC08 */
|
||||
#define DEV_TD8E 077 /* TD8E */
|
||||
|
||||
/* Interrupt flags
|
||||
|
||||
@@ -143,7 +147,8 @@ typedef struct pdp8_dib DIB;
|
||||
#define INT_V_RL (INT_V_DIRECT+6) /* RL8A */
|
||||
#define INT_V_PWR (INT_V_DIRECT+7) /* power int */
|
||||
#define INT_V_UF (INT_V_DIRECT+8) /* user int */
|
||||
#define INT_V_OVHD (INT_V_DIRECT+9) /* overhead start */
|
||||
#define INT_V_TSC (INT_V_DIRECT+9) /* TSC8-75 int */
|
||||
#define INT_V_OVHD (INT_V_DIRECT+10) /* overhead start */
|
||||
#define INT_V_NO_ION_PENDING (INT_V_OVHD+0) /* ion pending */
|
||||
#define INT_V_NO_CIF_PENDING (INT_V_OVHD+1) /* cif pending */
|
||||
#define INT_V_ION (INT_V_OVHD+2) /* interrupts on */
|
||||
@@ -171,6 +176,7 @@ typedef struct pdp8_dib DIB;
|
||||
#define INT_RL (1 << INT_V_RL)
|
||||
#define INT_PWR (1 << INT_V_PWR)
|
||||
#define INT_UF (1 << INT_V_UF)
|
||||
#define INT_TSC (1 << INT_V_TSC)
|
||||
#define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING)
|
||||
#define INT_NO_CIF_PENDING (1 << INT_V_NO_CIF_PENDING)
|
||||
#define INT_ION (1 << INT_V_ION)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
df DF32 fixed head disk
|
||||
|
||||
26-Oct-03 RMS Cleaned up buffer copy code
|
||||
26-Jul-03 RMS Fixed bug in set size routine
|
||||
14-Mar-03 RMS Fixed variable platter interaction with save/restore
|
||||
03-Mar-03 RMS Fixed autosizing
|
||||
@@ -231,6 +232,7 @@ t_stat df_svc (UNIT *uptr)
|
||||
{
|
||||
int32 pa, t, mex;
|
||||
uint32 da;
|
||||
int16 *fbuf = uptr->filebuf;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
@@ -247,13 +249,13 @@ do { if (da >= uptr->capac) { /* nx disk addr? */
|
||||
M[DF_MA] = (M[DF_MA] + 1) & 07777; /* incr mem addr */
|
||||
pa = mex | M[DF_MA]; /* add extension */
|
||||
if (uptr->FUNC == DF_READ) { /* read? */
|
||||
if (MEM_ADDR_OK (pa)) /* check nxm */
|
||||
M[pa] = *(((int16 *) uptr->filebuf) + da); }
|
||||
if (MEM_ADDR_OK (pa)) M[pa] = fbuf[da]; } /* if !nxm, read wd */
|
||||
else { /* write */
|
||||
t = (da >> 14) & 07; /* check wr lock */
|
||||
if ((df_wlk >> t) & 1) df_sta = df_sta | DFS_WLS;
|
||||
if ((df_wlk >> t) & 1) /* locked? set err */
|
||||
df_sta = df_sta | DFS_WLS;
|
||||
else { /* not locked */
|
||||
*(((int16 *) uptr->filebuf) + da) = M[pa];
|
||||
fbuf[da] = M[pa]; /* write word */
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1; } }
|
||||
da = (da + 1) & 0377777; } /* incr disk addr */
|
||||
while ((M[DF_WC] != 0) && (df_burst != 0)); /* brk if wc, no brst */
|
||||
|
||||
@@ -59,6 +59,8 @@ sim/pdp8/ pdp8_defs.h
|
||||
pdp8_rl.c
|
||||
pdp8_rx.c
|
||||
pdp8_sys.c
|
||||
pdp8_td.c
|
||||
pdp8_tsc.c
|
||||
pdp8_tt.c
|
||||
pdp8_ttx.c
|
||||
|
||||
@@ -72,6 +74,7 @@ name(s)
|
||||
CPU PDP-8/E CPU with 4KW-32KW of memory
|
||||
- KE8E extended arithmetic element (EAE)
|
||||
- KM8E memory management and timeshare control
|
||||
TSC TSC8-75 ETOS operating system timeshare control
|
||||
PTR,PTP PC8E paper tape reader/punch
|
||||
TTI,TTO KL8E console terminal
|
||||
TTIX,TTOX KL8JA additional terminals
|
||||
@@ -83,6 +86,7 @@ DF DF32/DS32 fixed head disk controller with 1-4 platters
|
||||
RL RL8A/RL01 cartridge disk controller with four drives
|
||||
RX RX8E/RX01, RX28/RX02 floppy disk controller with two drives
|
||||
DT TC08/TU56 DECtape controller with eight drives
|
||||
TD TD8E/TU56 DECtape controller with two drives
|
||||
MT TM8E/TU10 magnetic tape controller with eight drives
|
||||
|
||||
Most devices can be disabled or enabled, by the commands:
|
||||
@@ -102,17 +106,28 @@ default is the RF08. To change the disk at device numbers 60-61:
|
||||
sim> SET DF ENABLED, or enable DF32
|
||||
sim> SET RL ENABLED enable RL8A
|
||||
|
||||
The PDP-8 can only support one of the set {TC08, TD8E} using the default
|
||||
device numbers, since both use device number 77. The default is the
|
||||
TC08. To change the DECtape controller to the TD8E:
|
||||
|
||||
sim> SET DT DISABLED disable TC08
|
||||
sim> SET TD ENABLED enable TD8E
|
||||
|
||||
Alternately, the device conflict can be eliminated by changing device
|
||||
numbers:
|
||||
|
||||
sim> SET RL DEV=50
|
||||
sim> SET RL ENA
|
||||
sim> SET TD DEV=74
|
||||
sim> SET TD ENA
|
||||
|
||||
However, devices can only be BOOTed with their default device numbers.
|
||||
|
||||
The PDP-8 simulator implements one unique stop condition: if an undefined
|
||||
instruction (unimplemented IOT or OPR) is decoded, and register STOP_INST
|
||||
is set, the simulator halts.
|
||||
The PDP-8 simulator implements several unique stop conditions:
|
||||
|
||||
- if an undefined instruction (unimplemented IOT or OPR) is
|
||||
decoded, and register STOP_INST
|
||||
- if a simulated DECtape runs off the end of its reel
|
||||
|
||||
The PDP-8 loader supports both RIM format and BIN format tapes. If the file
|
||||
extension is .RIM, or the -r switch is specified with LOAD, the file is
|
||||
@@ -172,9 +187,38 @@ control registers for the interrupt system.
|
||||
STOP_INST 1 stop on undefined instruction
|
||||
WRU 8 interrupt character
|
||||
|
||||
2.2 Programmed I/O Devices
|
||||
The CPU can maintain a history of the most recently executed instructions.
|
||||
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
|
||||
|
||||
2.2.1 PC8E Paper Tape Reader (PTR)
|
||||
SET CPU HISTORY clear history buffer
|
||||
SET CPU HISTORY=0 disable history
|
||||
SET CPU HISTORY=n enable history, display length = n
|
||||
SHOW CPU HISTORY print CPU history
|
||||
|
||||
The maximum length for the history is 65536 entries.
|
||||
|
||||
2.2 TSC8-75 ETOS Timeshare Control (TSC)
|
||||
|
||||
ETOS is a timeshared operating system for the PDP-8, providing multiple
|
||||
virtual OS/8 environments for up to 32 users. It requires a special
|
||||
timeshare control option, the TSC8-75. The TSC8-75 is normally disabled;
|
||||
to run ETOS, it must be enabled with the command:
|
||||
|
||||
SET TSC ENABLED
|
||||
|
||||
The TSC8-75 implements these registers:
|
||||
|
||||
IR most recently trapped instruction
|
||||
PC PC of most recently trapped instruction
|
||||
CDF 1 if trapped instruction is CDF, 0 otherwise
|
||||
ENB interrupt enable flag
|
||||
INT interrupt pending flag
|
||||
|
||||
Except for operation of ETOS, the TSC8-75 should be left disabled.
|
||||
|
||||
2.3 Programmed I/O Devices
|
||||
|
||||
2.3.1 PC8E Paper Tape Reader (PTR)
|
||||
|
||||
The paper tape reader (PTR) reads data from a disk file. The POS
|
||||
register specifies the number of the next data item to be read. Thus,
|
||||
@@ -207,7 +251,7 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.2 PC8E Paper Tape Punch (PTP)
|
||||
2.3.2 PC8E Paper Tape Punch (PTP)
|
||||
|
||||
The paper tape punch (PTP) writes data to a disk file. The POS register
|
||||
specifies the number of the next data item to bewritten. Thus, by
|
||||
@@ -234,7 +278,7 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.3 KL8E Terminal Input (TTI)
|
||||
2.3.3 KL8E Terminal Input (TTI)
|
||||
|
||||
The terminal interfaces (TTI, TTO) can be set to one of three modes:
|
||||
KSR, 7B, or 8B. In KSR mode, lower case input and output characters
|
||||
@@ -261,7 +305,7 @@ to simulate typing ^C:
|
||||
|
||||
SET TTI CTRL-C
|
||||
|
||||
2.2.4 KL8E Terminal Output (TTO)
|
||||
2.3.4 KL8E Terminal Output (TTO)
|
||||
|
||||
The terminal output (TTO) writes to the simulator console window. It
|
||||
implements these registers:
|
||||
@@ -275,7 +319,7 @@ implements these registers:
|
||||
POS 32 number of characters output
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
|
||||
2.2.5 LE8E Line Printer (LPT)
|
||||
2.3.5 LE8E Line Printer (LPT)
|
||||
|
||||
The line printer (LPT) writes data to a disk file. The POS register
|
||||
specifies the number of the next data item to be read or written. Thus,
|
||||
@@ -302,7 +346,7 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.6 DK8E Line-Frequency Clock (CLK)
|
||||
2.3.6 DK8E Line-Frequency Clock (CLK)
|
||||
|
||||
The real-time clock (CLK) frequency can be adjusted as follows:
|
||||
|
||||
@@ -323,7 +367,7 @@ The clock implements these registers:
|
||||
The real-time clock autocalibrates; the clock interval is adjusted up or
|
||||
down so that the clock tracks actual elapsed time.
|
||||
|
||||
2.2.7 KL8JA Additional Terminals (TTIX, TTOX)
|
||||
2.3.7 KL8JA Additional Terminals (TTIX, TTOX)
|
||||
|
||||
The additional terminals consist of two independent devices, TTIX and
|
||||
TTOX. The entire set is modelled as a terminal multiplexor, with TTIX
|
||||
@@ -378,9 +422,58 @@ The output device (TTOX) implements these registers:
|
||||
The additional terminals do not support save and restore. All open
|
||||
connections are lost when the simulator shuts down or TTIX is detached.
|
||||
|
||||
2.3 Moving Head Disks
|
||||
2.3.8 TD8E/TU56 DECtape (TD)
|
||||
|
||||
2.3.1 RK8E Cartridge Disk (RK)
|
||||
The TD8E is a programmed I/O, non-interrupt controller, supporting two
|
||||
DECtape drives (0 and 1). The TD8E simulator puts a high burden on the
|
||||
host processor, because tape activity is simulated a line (3b) at a time.
|
||||
Unless the PDP-8 software requires the TD8E, the TC08 should be used
|
||||
to simulate DECtapes. The TD8E is disabled by default.
|
||||
|
||||
TD8E options include the ability to make units write enabled or write
|
||||
locked.
|
||||
|
||||
SET DTn LOCKED set unit n write locked
|
||||
SET DTn WRITEENABLED set unit n write enabled
|
||||
|
||||
Units can also be set ONLINE or OFFLINE. The TD8E supports the BOOT command.
|
||||
|
||||
The TD8E supports supports PDP-8 format, PDP-11 format, and 18b format
|
||||
DECtape images. ATTACH tries to determine the tape format from the DECtape
|
||||
image; the user can force a particular format with switches:
|
||||
|
||||
-r PDP-8 format
|
||||
-s PDP-11 format
|
||||
-t 18b format
|
||||
|
||||
The TD8E controller is a data-only simulator; the timing and mark
|
||||
track, and block header and trailer, are not stored. Thus, read always
|
||||
produces standard values for header and trailer words, and write throws
|
||||
header and trailer words into the bit bucket.
|
||||
|
||||
The TD8E controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
TDCMD 4 command register
|
||||
TDDAT 12 data register
|
||||
TDMTK 6 mark track register
|
||||
TDSLF 1 single line flag
|
||||
TDQLF 1 quad line flag
|
||||
TDTME 1 timing error flag
|
||||
TDQL 2 quad line counter
|
||||
LTIME 31 time between lines
|
||||
DCTIME 31 time to decelerate to a full stop
|
||||
POS[0:7] 32 position, in lines, units 0-7
|
||||
STATT[0:7] 18 unit state, units 0-7
|
||||
|
||||
The LTIME parameter should not be changed, or OS/8 may fail to run
|
||||
correctly. The DCTIME parameter should always be at least 100 times
|
||||
greater than LTIME. Acceleration time is 75% of deceleration time.
|
||||
|
||||
2.4 Moving Head Disks
|
||||
|
||||
2.4.1 RK8E Cartridge Disk (RK)
|
||||
|
||||
RK8E options include the ability to make units write enabled or write locked:
|
||||
|
||||
@@ -414,7 +507,7 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.3.2 RL8A Cartridge Disk (RL)
|
||||
2.4.2 RL8A Cartridge Disk (RL)
|
||||
|
||||
RL8A options include the ability to make units write enabled or write locked:
|
||||
|
||||
@@ -455,7 +548,7 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4 RX8E/RX01, RX28/RX02 Floppy Disk (RX)
|
||||
2.5 RX8E/RX01, RX28/RX02 Floppy Disk (RX)
|
||||
|
||||
The RX can be configured as an RX8E with two RX01 drives, or an RX28 with
|
||||
two RX02 drives:
|
||||
@@ -513,12 +606,12 @@ Error handling is as follows:
|
||||
RX01 and RX02 data files are buffered in memory; therefore, end of file
|
||||
and OS I/O errors cannot occur.
|
||||
|
||||
2.5 Fixed Head Disks
|
||||
2.6 Fixed Head Disks
|
||||
|
||||
Either the RF08 or the DF32 can be present in a configuration, but
|
||||
not both, with default device addressing.
|
||||
|
||||
2.5.1 RF08/RS08 Fixed Head Disk (RF)
|
||||
2.6.1 RF08/RS08 Fixed Head Disk (RF)
|
||||
|
||||
RF08 options include the ability to set the number of platters to a
|
||||
fixed value between 1 and 4, or to autosize the number of platters
|
||||
@@ -564,7 +657,7 @@ Error handling is as follows:
|
||||
RF08 data files are buffered in memory; therefore, end of file and OS
|
||||
I/O errors cannot occur.
|
||||
|
||||
2.5.2 DF32/DS32 Fixed Head Disk (RF)
|
||||
2.6.2 DF32/DS32 Fixed Head Disk (RF)
|
||||
|
||||
DF32 options include the ability to set the number of platters to a
|
||||
fixed value between 1 and 4, or to autosize the number of platters
|
||||
@@ -610,10 +703,10 @@ Error handling is as follows:
|
||||
DF32 data files are buffered in memory; therefore, end of file and OS
|
||||
I/O errors cannot occur.
|
||||
|
||||
2.6 TC08/TU56 DECtape (DT)
|
||||
2.7 TC08/TU56 DECtape (DT)
|
||||
|
||||
DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0.
|
||||
DECtape options include the ability to make units write enabled or write
|
||||
TC08 options include the ability to make units write enabled or write
|
||||
locked.
|
||||
|
||||
SET DTn LOCKED set unit n write locked
|
||||
@@ -629,7 +722,7 @@ image; the user can force a particular format with switches:
|
||||
-s PDP-11 format
|
||||
-t 18b format
|
||||
|
||||
The DECtape controller is a data-only simulator; the timing and mark
|
||||
The TC08 controller is a data-only simulator; the timing and mark
|
||||
track, and block header and trailer, are not stored. Thus, the WRITE
|
||||
TIMING AND MARK TRACK function is not supported; the READ ALL function
|
||||
always returns the hardware standard block header and trailer; and the
|
||||
@@ -648,7 +741,6 @@ The DECtape controller implements these registers:
|
||||
CA 12 current address (memory location 7754)
|
||||
WC 12 word count (memory location 7755)
|
||||
LTIME 31 time between lines
|
||||
ACTIME 31 time to accelerate to full speed
|
||||
DCTIME 31 time to decelerate to a full stop
|
||||
SUBSTATE 2 read/write command substate
|
||||
POS[0:7] 32 position, in lines, units 0-7
|
||||
@@ -659,10 +751,11 @@ among the DECtape parameters, or the DECtape simulator will fail to
|
||||
operate correctly.
|
||||
|
||||
- LTIME must be at least 6
|
||||
- ACTIME must be less than DCTIME, and both need to be at
|
||||
least 100 times LTIME
|
||||
- DCTIME needs to be at least 100 times LTIME
|
||||
|
||||
2.7 TM8E Magnetic Tape (MT)
|
||||
Acceleration time is set to 75% of deceleration time.
|
||||
|
||||
2.8 TM8E Magnetic Tape (MT)
|
||||
|
||||
Magnetic tape options include the ability to make units write enabled or
|
||||
or write locked.
|
||||
@@ -700,7 +793,7 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error parity error; if STOP_IOE, stop
|
||||
|
||||
2.8 Symbolic Display and Input
|
||||
2.9 Symbolic Display and Input
|
||||
|
||||
The PDP-8 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
107
PDP8/pdp8_dt.c
107
PDP8/pdp8_dt.c
@@ -25,6 +25,7 @@
|
||||
|
||||
dt TC08/TU56 DECtape
|
||||
|
||||
18-Oct-03 RMS Fixed bugs in read all, tightened timing
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
14-Mar-03 RMS Fixed sizing interaction with save/restore
|
||||
17-Oct-02 RMS Fixed bug in end of reel logic
|
||||
@@ -52,13 +53,16 @@
|
||||
When a 16b or 18/36bb DECtape file is read in, it is converted to 12b format.
|
||||
|
||||
DECtape motion is measured in 3b lines. Time between lines is 33.33us.
|
||||
Tape density is nominally 300 lines per inch. The format of a DECtape is
|
||||
Tape density is nominally 300 lines per inch. The format of a DECtape (as
|
||||
taken from the TD8E formatter) is:
|
||||
|
||||
reverse end zone 36000 lines ~ 10 feet
|
||||
reverse end zone 8192 reverse end zone codes ~ 10 feet
|
||||
reverse buffer 200 interblock codes
|
||||
block 0
|
||||
:
|
||||
block n
|
||||
forward end zone 36000 lines ~ 10 feet
|
||||
forward buffer 200 interblock codes
|
||||
forward end zone 8192 forward end zone codes ~ 10 feet
|
||||
|
||||
A block consists of five 18b header words, a tape-specific number of data
|
||||
words, and five 18b trailer words. All systems except the PDP-8 use a
|
||||
@@ -73,14 +77,14 @@
|
||||
header word 0 0
|
||||
header word 1 block number (for forward reads)
|
||||
header words 2,3 0
|
||||
header word 4 0
|
||||
header word 4 checksum (for reverse reads)
|
||||
:
|
||||
trailer word 4 checksum
|
||||
trailer word 4 checksum (for forward reads)
|
||||
trailer words 3,2 0
|
||||
trailer word 1 block number (for reverse reads)
|
||||
trailer word 0 0
|
||||
|
||||
Write all writes only the data words and dumps the interblock words in the
|
||||
Write all writes only the data words and dumps the non-data words in the
|
||||
bit bucket.
|
||||
*/
|
||||
|
||||
@@ -101,10 +105,15 @@
|
||||
|
||||
/* System independent DECtape constants */
|
||||
|
||||
#define DT_EZLIN 36000 /* end zone length */
|
||||
#define DT_HTLIN 30 /* header/trailer lines */
|
||||
#define DT_BLKLN 6 /* blk no line in h/t */
|
||||
#define DT_CSMLN 24 /* checksum line in h/t */
|
||||
#define DT_LPERMC 6 /* lines per mark track */
|
||||
#define DT_BLKWD 1 /* blk no word in h/t */
|
||||
#define DT_CSMWD 4 /* checksum word in h/t */
|
||||
#define DT_HTWRD 5 /* header/trailer words */
|
||||
#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */
|
||||
#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */
|
||||
#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */
|
||||
#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */
|
||||
#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */
|
||||
|
||||
/* 16b, 18b, 36b DECtape constants */
|
||||
|
||||
@@ -257,8 +266,7 @@ extern int32 sim_switches;
|
||||
int32 dtsa = 0; /* status A */
|
||||
int32 dtsb = 0; /* status B */
|
||||
int32 dt_ltime = 12; /* interline time */
|
||||
int32 dt_actime = 54000; /* accel time */
|
||||
int32 dt_dctime = 72000; /* decel time */
|
||||
int32 dt_dctime = 40000; /* decel time */
|
||||
int32 dt_substate = 0;
|
||||
int32 dt_log = 0; /* debug */
|
||||
int32 dt_logblk = 0;
|
||||
@@ -319,9 +327,8 @@ REG dt_reg[] = {
|
||||
{ FLDATA (ERF, dtsb, DTB_V_ERF) },
|
||||
{ ORDATA (WC, M[DT_WC], 18) },
|
||||
{ ORDATA (CA, M[DT_CA], 18) },
|
||||
{ DRDATA (LTIME, dt_ltime, 31), REG_NZ },
|
||||
{ DRDATA (ACTIME, dt_actime, 31), REG_NZ },
|
||||
{ DRDATA (DCTIME, dt_dctime, 31), REG_NZ },
|
||||
{ DRDATA (LTIME, dt_ltime, 31), REG_NZ | PV_LEFT },
|
||||
{ DRDATA (DCTIME, dt_dctime, 31), REG_NZ | PV_LEFT },
|
||||
{ ORDATA (SUBSTATE, dt_substate, 2) },
|
||||
{ ORDATA (LOG, dt_log, 4), REG_HIDDEN },
|
||||
{ DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN },
|
||||
@@ -451,7 +458,7 @@ if ((prev_mving | new_mving) == 0) return; /* stop to stop */
|
||||
if (new_mving & ~prev_mving) { /* start? */
|
||||
if (dt_setpos (uptr)) return; /* update pos */
|
||||
sim_cancel (uptr); /* stop current */
|
||||
sim_activate (uptr, dt_actime); /* schedule accel */
|
||||
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* schedule acc */
|
||||
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
|
||||
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
|
||||
return; }
|
||||
@@ -477,7 +484,7 @@ if (prev_dir ^ new_dir) { /* dir chg? */
|
||||
if (prev_mot < DTS_ACCF) { /* not accel/at speed? */
|
||||
if (dt_setpos (uptr)) return; /* update pos */
|
||||
sim_cancel (uptr); /* cancel cur */
|
||||
sim_activate (uptr, dt_actime); /* schedule accel */
|
||||
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */
|
||||
DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */
|
||||
DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */
|
||||
return; }
|
||||
@@ -598,11 +605,13 @@ case DTS_STOP: /* stop */
|
||||
delta = 0;
|
||||
break;
|
||||
case DTS_DECF: /* slowing */
|
||||
ulin = ut / (uint32) dt_ltime; udelt = dt_dctime / dt_ltime;
|
||||
ulin = ut / (uint32) dt_ltime;
|
||||
udelt = dt_dctime / dt_ltime;
|
||||
delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
|
||||
break;
|
||||
case DTS_ACCF: /* accelerating */
|
||||
ulin = ut / (uint32) dt_ltime; udelt = dt_actime / dt_ltime;
|
||||
ulin = ut / (uint32) dt_ltime;
|
||||
udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime;
|
||||
delta = (ulin * ulin) / (2 * udelt);
|
||||
break;
|
||||
case DTS_ATSF: /* at speed */
|
||||
@@ -631,7 +640,7 @@ t_stat dt_svc (UNIT *uptr)
|
||||
int32 mot = DTS_GETMOT (uptr->STATE);
|
||||
int32 dir = mot & DTS_DIR;
|
||||
int32 fnc = DTS_GETFNC (uptr->STATE);
|
||||
int16 *bptr = uptr->filebuf;
|
||||
int16 *fbuf = uptr->filebuf;
|
||||
int32 unum = uptr - dt_dev.units;
|
||||
int32 blk, wrd, ma, relpos, dat;
|
||||
uint32 ba;
|
||||
@@ -645,10 +654,10 @@ uint32 ba;
|
||||
|
||||
switch (mot) {
|
||||
case DTS_DECF: case DTS_DECR: /* decelerating */
|
||||
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
|
||||
if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */
|
||||
uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */
|
||||
if (uptr->STATE) /* not stopped? */
|
||||
sim_activate (uptr, dt_actime); /* must be reversing */
|
||||
sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* must be reversing */
|
||||
return SCPE_OK;
|
||||
case DTS_ACCF: case DTS_ACCR: /* accelerating */
|
||||
dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
|
||||
@@ -666,7 +675,7 @@ default: /* other */
|
||||
Off reel - detach unit (it must be deselected)
|
||||
*/
|
||||
|
||||
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
|
||||
if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */
|
||||
if (DT_QEZ (uptr)) { /* in end zone? */
|
||||
dt_seterr (uptr, DTB_END); /* end zone error */
|
||||
return SCPE_OK; }
|
||||
@@ -721,7 +730,7 @@ case FNC_READ: /* read */
|
||||
M[DT_CA] = (M[DT_CA] + 1) & 07777;
|
||||
ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */
|
||||
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
|
||||
dat = bptr[ba]; /* get tape word */
|
||||
dat = fbuf[ba]; /* get tape word */
|
||||
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
|
||||
if (MEM_ADDR_OK (ma)) M[ma] = dat; /* mem addr legal? */
|
||||
if (M[DT_WC] == 0) dt_substate = DTO_WCO; /* wc ovf? */
|
||||
@@ -773,7 +782,7 @@ case FNC_WRIT: /* write */
|
||||
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
|
||||
dat = dt_substate? 0: M[ma]; /* get word */
|
||||
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
|
||||
bptr[ba] = dat; /* write word */
|
||||
fbuf[ba] = dat; /* write word */
|
||||
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
|
||||
if (M[DT_WC] == 0) dt_substate = DTO_WCO;
|
||||
if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */
|
||||
@@ -809,7 +818,7 @@ case FNC_RALL:
|
||||
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
|
||||
wrd = DT_LIN2WD (uptr->pos, uptr);
|
||||
ba = (blk * DTU_BSIZE (uptr)) + wrd;
|
||||
dat = bptr[ba]; /* get tape word */
|
||||
dat = fbuf[ba]; /* get tape word */
|
||||
if (dir) dat = dt_comobv (dat); } /* rev? comp obv */
|
||||
else dat = dt_gethdr (uptr, blk, relpos, dir); /* get hdr */
|
||||
sim_activate (uptr, DT_WSIZE * dt_ltime);
|
||||
@@ -845,7 +854,7 @@ case FNC_WALL:
|
||||
if (dir) dat = dt_comobv (dat);
|
||||
wrd = DT_LIN2WD (uptr->pos, uptr);
|
||||
ba = (blk * DTU_BSIZE (uptr)) + wrd;
|
||||
bptr[ba] = dat; /* write word */
|
||||
fbuf[ba] = dat; /* write word */
|
||||
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; }
|
||||
/* /* ignore hdr */
|
||||
sim_activate (uptr, DT_WSIZE * dt_ltime);
|
||||
@@ -872,7 +881,7 @@ return SCPE_OK;
|
||||
Word Word Content Word Word Content
|
||||
(abs) (rel) (abs) (rel)
|
||||
|
||||
137 8 rev csm'00 6 6 fwd csm'00
|
||||
137 8 fwd csm'00 6 6 rev csm'00
|
||||
138 9 0000 5 5 0000
|
||||
139 10 0000 4 4 0000
|
||||
140 11 0000 3 3 0000
|
||||
@@ -886,7 +895,7 @@ return SCPE_OK;
|
||||
4 4 0000 139 10 0000
|
||||
5 5 0000 138 9 0000
|
||||
6 6 0000 137 8 0000
|
||||
7 7 00'fwd csm 136 7 00'rev csm
|
||||
7 7 rev csm 136 7 00'fwd csm
|
||||
*/
|
||||
|
||||
int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos, int32 dir)
|
||||
@@ -894,8 +903,8 @@ int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos, int32 dir)
|
||||
if (relpos >= DT_HTLIN) relpos = relpos - (DT_WSIZE * DTU_BSIZE (uptr));
|
||||
if (dir) { /* reverse */
|
||||
switch (relpos / DT_WSIZE) {
|
||||
case 6: /* fwd csum */
|
||||
return (dt_comobv (dt_csum (uptr, blk)));
|
||||
case 6: /* rev csm */
|
||||
return 077;
|
||||
case 2: /* lo fwd blk */
|
||||
return dt_comobv ((blk & 077) << 6);
|
||||
case 1: /* hi fwd blk */
|
||||
@@ -904,11 +913,13 @@ if (dir) { /* reverse */
|
||||
return (blk >> 6) & 07777;
|
||||
case 11: /* lo rev blk */
|
||||
return ((blk & 077) << 6);
|
||||
case 7: /* fwd csum */
|
||||
return (dt_comobv (dt_csum (uptr, blk)) << 6);
|
||||
default: /* others */
|
||||
return 077; } }
|
||||
return 07777; } }
|
||||
else { /* forward */
|
||||
switch (relpos / DT_WSIZE) {
|
||||
case 8: /* rev csum */
|
||||
case 8: /* fwd csum */
|
||||
return (dt_csum (uptr, blk) << 6);
|
||||
case 12: /* lo rev blk */
|
||||
return dt_comobv ((blk & 077) << 6);
|
||||
@@ -918,6 +929,8 @@ else { /* forward */
|
||||
return ((blk >> 6) & 07777);
|
||||
case 3: /* lo fwd blk */
|
||||
return ((blk & 077) << 6);
|
||||
case 7: /* rev csum */
|
||||
return 077;
|
||||
default: /* others */
|
||||
break; } }
|
||||
return 0;
|
||||
@@ -968,13 +981,13 @@ return dat;
|
||||
|
||||
int32 dt_csum (UNIT *uptr, int32 blk)
|
||||
{
|
||||
int16 *bptr = uptr->filebuf;
|
||||
int16 *fbuf = uptr->filebuf;
|
||||
int32 ba = blk * DTU_BSIZE (uptr);
|
||||
int32 i, csum, wrd;
|
||||
|
||||
csum = 077; /* init csum */
|
||||
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
|
||||
wrd = bptr[ba + i] ^ 07777; /* get ~word */
|
||||
wrd = fbuf[ba + i] ^ 07777; /* get ~word */
|
||||
csum = csum ^ (wrd >> 6) ^ wrd; }
|
||||
return (csum & 077);
|
||||
}
|
||||
@@ -1061,7 +1074,7 @@ return SCPE_OK;
|
||||
t_stat dt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
uint16 pdp11b[D18_NBSIZE], *bptr;
|
||||
uint16 pdp11b[D18_NBSIZE], *fbuf;
|
||||
int32 i, k;
|
||||
int32 u = uptr - dt_dev.units;
|
||||
t_stat r;
|
||||
@@ -1086,7 +1099,7 @@ uptr->filebuf = calloc (uptr->capac, sizeof (int16));
|
||||
if (uptr->filebuf == NULL) { /* can't alloc? */
|
||||
detach_unit (uptr);
|
||||
return SCPE_MEM; }
|
||||
bptr = uptr->filebuf; /* file buffer */
|
||||
fbuf = uptr->filebuf; /* file buffer */
|
||||
printf ("%s%d: ", sim_dname (&dt_dev), u);
|
||||
if (uptr->flags & UNIT_8FMT) printf ("12b format");
|
||||
else if (uptr->flags & UNIT_11FMT) printf ("16b format");
|
||||
@@ -1104,10 +1117,10 @@ else { /* 16b/18b */
|
||||
if (k == 0) break;
|
||||
for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0;
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) { /* loop thru blk */
|
||||
bptr[ba] = (pdp18b[k] >> 6) & 07777;
|
||||
bptr[ba + 1] = ((pdp18b[k] & 077) << 6) |
|
||||
fbuf[ba] = (pdp18b[k] >> 6) & 07777;
|
||||
fbuf[ba + 1] = ((pdp18b[k] & 077) << 6) |
|
||||
((pdp18b[k + 1] >> 12) & 077);
|
||||
bptr[ba + 2] = pdp18b[k + 1] & 07777;
|
||||
fbuf[ba + 2] = pdp18b[k + 1] & 07777;
|
||||
ba = ba + 3; } /* end blk loop */
|
||||
} /* end file loop */
|
||||
uptr->hwmark = ba; } /* end else */
|
||||
@@ -1128,19 +1141,19 @@ return SCPE_OK;
|
||||
t_stat dt_detach (UNIT* uptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
uint16 pdp11b[D18_NBSIZE], *bptr;
|
||||
uint16 pdp11b[D18_NBSIZE], *fbuf;
|
||||
int32 i, k;
|
||||
int32 u = uptr - dt_dev.units;
|
||||
uint32 ba;
|
||||
|
||||
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
|
||||
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
|
||||
if (sim_is_active (uptr)) {
|
||||
sim_cancel (uptr);
|
||||
if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) {
|
||||
dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
|
||||
DT_UPDINT; }
|
||||
uptr->STATE = uptr->pos = 0; }
|
||||
bptr = uptr->filebuf; /* file buffer */
|
||||
fbuf = uptr->filebuf; /* file buffer */
|
||||
if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) { /* any data? */
|
||||
printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u);
|
||||
rewind (uptr->fileref); /* start of file */
|
||||
@@ -1150,10 +1163,10 @@ if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) { /* any data? */
|
||||
else { /* 16b/18b */
|
||||
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru buf */
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) {
|
||||
pdp18b[k] = ((uint32) (bptr[ba] & 07777) << 6) |
|
||||
((uint32) (bptr[ba + 1] >> 6) & 077);
|
||||
pdp18b[k + 1] = ((uint32) (bptr[ba + 1] & 077) << 12) |
|
||||
((uint32) (bptr[ba + 2] & 07777));
|
||||
pdp18b[k] = ((uint32) (fbuf[ba] & 07777) << 6) |
|
||||
((uint32) (fbuf[ba + 1] >> 6) & 077);
|
||||
pdp18b[k + 1] = ((uint32) (fbuf[ba + 1] & 077) << 12) |
|
||||
((uint32) (fbuf[ba + 2] & 07777));
|
||||
ba = ba + 3; } /* end loop blk */
|
||||
if (uptr->flags & UNIT_11FMT) { /* 16b? */
|
||||
for (i = 0; i < D18_NBSIZE; i++) pdp11b[i] = pdp18b[i];
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
rf RF08 fixed head disk
|
||||
|
||||
26-Oct-03 RMS Cleaned up buffer copy code
|
||||
26-Jul-03 RMS Fixed bug in set size routine
|
||||
14-Mar-03 RMS Fixed variable platter interaction with save/restore
|
||||
03-Mar-03 RMS Fixed autosizing
|
||||
@@ -274,6 +275,7 @@ return AC;
|
||||
t_stat rf_svc (UNIT *uptr)
|
||||
{
|
||||
int32 pa, t, mex;
|
||||
int16 *fbuf = uptr->filebuf;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
@@ -290,13 +292,14 @@ do { if ((uint32) rf_da >= rf_unit.capac) { /* disk overflow? */
|
||||
M[RF_MA] = (M[RF_MA] + 1) & 07777; /* incr mem addr */
|
||||
pa = mex | M[RF_MA]; /* add extension */
|
||||
if (uptr->FUNC == RF_READ) { /* read? */
|
||||
if (MEM_ADDR_OK (pa)) /* check nxm */
|
||||
M[pa] = *(((int16 *) uptr->filebuf) + rf_da); }
|
||||
if (MEM_ADDR_OK (pa)) /* if !nxm */
|
||||
M[pa] = fbuf[rf_da]; } /* read word */
|
||||
else { /* write */
|
||||
t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
|
||||
if ((rf_wlk >> t) & 1) rf_sta = rf_sta | RFS_WLS;
|
||||
else {
|
||||
*(((int16 *) uptr->filebuf) + rf_da) = M[pa];
|
||||
if ((rf_wlk >> t) & 1) /* write locked? */
|
||||
rf_sta = rf_sta | RFS_WLS;
|
||||
else { /* not locked */
|
||||
fbuf[rf_da] = M[pa]; /* write word */
|
||||
if (((uint32) rf_da) >= uptr->hwmark) uptr->hwmark = rf_da + 1; } }
|
||||
rf_da = (rf_da + 1) & 03777777; } /* incr disk addr */
|
||||
while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
rx RX8E/RX01, RX28/RX02 floppy disk
|
||||
|
||||
05-Nov-03 RMS Fixed bug in RX28 read status (found by Charles Dickman)
|
||||
26-Oct-03 RMS Cleaned up buffer copy code, fixed double density write
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
14-Mar-03 RMS Fixed variable size interaction with save/restore
|
||||
03-Mar-03 RMS Fixed autosizing
|
||||
@@ -129,7 +131,7 @@ int32 rx_swait = 10; /* seek, per track */
|
||||
int32 rx_xwait = 1; /* tr set time */
|
||||
int32 rx_stopioe = 0; /* stop on error */
|
||||
uint8 rx_buf[RX2_NUMBY] = { 0 }; /* sector buffer */
|
||||
static int32 bptr = 0; /* buffer pointer */
|
||||
int32 rx_bptr = 0; /* buffer pointer */
|
||||
|
||||
DEVICE rx_dev;
|
||||
int32 rx (int32 IR, int32 AC);
|
||||
@@ -167,7 +169,7 @@ REG rx_reg[] = {
|
||||
{ ORDATA (RXTA, rx_track, 8) },
|
||||
{ ORDATA (RXSA, rx_sector, 8) },
|
||||
{ DRDATA (STAPTR, rx_state, 4), REG_RO },
|
||||
{ DRDATA (BUFPTR, bptr, 8) },
|
||||
{ DRDATA (BUFPTR, rx_bptr, 8) },
|
||||
{ FLDATA (TR, rx_tr, 0) },
|
||||
{ FLDATA (ERR, rx_err, 0) },
|
||||
{ FLDATA (DONE, dev_done, INT_V_RX) },
|
||||
@@ -226,7 +228,7 @@ case 1: /* LCD */
|
||||
dev_done = dev_done & ~INT_RX; /* clear done, int */
|
||||
int_req = int_req & ~INT_RX;
|
||||
rx_tr = rx_err = 0; /* clear flags */
|
||||
bptr = 0; /* clear buf pointer */
|
||||
rx_bptr = 0; /* clear buf pointer */
|
||||
if (rx_28 && (AC & RXCS_MODE)) { /* RX28 8b mode? */
|
||||
rx_dbr = rx_csr = AC & 0377; /* save 8b */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
@@ -287,9 +289,11 @@ switch (RXCS_GETFNC (rx_csr)) { /* decode command */
|
||||
case RXCS_FILL:
|
||||
rx_state = FILL; /* state = fill */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
break;
|
||||
case RXCS_EMPTY:
|
||||
rx_state = EMPTY; /* state = empty */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
sim_activate (&rx_unit[drv], rx_xwait); /* sched xfer */
|
||||
break;
|
||||
case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
|
||||
@@ -301,6 +305,7 @@ case RXCS_SDEN:
|
||||
if (rx_28) { /* RX28? */
|
||||
rx_state = SDCNF; /* state = get conf */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
break; } /* else fall thru */
|
||||
default:
|
||||
rx_state = CMD_COMPLETE; /* state = cmd compl */
|
||||
@@ -315,10 +320,10 @@ return;
|
||||
RWDS Save sector, set TR, set RWDT
|
||||
RWDT Save track, set RWXFR
|
||||
RWXFR Read/write buffer
|
||||
FILL copy dbr to rx_buf[bptr], advance ptr
|
||||
if bptr > max, finish command, else set tr
|
||||
EMPTY if bptr > max, finish command, else
|
||||
copy rx_buf[bptr] to dbr, advance ptr, set tr
|
||||
FILL copy dbr to rx_buf[rx_bptr], advance ptr
|
||||
if rx_bptr > max, finish command, else set tr
|
||||
EMPTY if rx_bptr > max, finish command, else
|
||||
copy rx_buf[rx_bptr] to dbr, advance ptr, set tr
|
||||
CMD_COMPLETE copy requested data to dbr, finish command
|
||||
INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
|
||||
|
||||
@@ -329,12 +334,13 @@ return;
|
||||
t_stat rx_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i, func, byptr, bps, wps;
|
||||
int8 *fbuf = uptr->filebuf;
|
||||
uint32 da;
|
||||
#define PTR12(x) (((x) + (x) + (x)) >> 1)
|
||||
|
||||
if (rx_28 && (uptr->flags & UNIT_DEN))
|
||||
bps = RX2_NUMBY;
|
||||
else bps = RX_NUMBY;
|
||||
if (rx_28 && (uptr->flags & UNIT_DEN)) /* RX28 and double density? */
|
||||
bps = RX2_NUMBY; /* double bytes/sector */
|
||||
else bps = RX_NUMBY; /* RX8E, normal count */
|
||||
wps = bps / 2;
|
||||
func = RXCS_GETFNC (rx_csr); /* get function */
|
||||
switch (rx_state) { /* case on state */
|
||||
@@ -344,40 +350,40 @@ case IDLE: /* idle */
|
||||
|
||||
case EMPTY: /* empty buffer */
|
||||
if (rx_csr & RXCS_MODE) { /* 8b xfer? */
|
||||
if (bptr >= bps) { /* done? */
|
||||
if (rx_bptr >= bps) { /* done? */
|
||||
rx_done (0, 0); /* set done */
|
||||
break; } /* and exit */
|
||||
rx_dbr = rx_buf[bptr]; } /* else get data */
|
||||
rx_dbr = rx_buf[rx_bptr]; } /* else get data */
|
||||
else {
|
||||
byptr = PTR12 (bptr); /* 12b xfer */
|
||||
if (bptr >= wps) { /* done? */
|
||||
byptr = PTR12 (rx_bptr); /* 12b xfer */
|
||||
if (rx_bptr >= wps) { /* done? */
|
||||
rx_done (0, 0); /* set done */
|
||||
break; } /* and exit */
|
||||
rx_dbr = (bptr & 1)? /* get data */
|
||||
rx_dbr = (rx_bptr & 1)? /* get data */
|
||||
((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]:
|
||||
(rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017); }
|
||||
bptr = bptr + 1;
|
||||
rx_bptr = rx_bptr + 1;
|
||||
rx_tr = 1;
|
||||
break;
|
||||
|
||||
case FILL: /* fill buffer */
|
||||
if (rx_csr & RXCS_MODE) { /* 8b xfer? */
|
||||
rx_buf[bptr] = rx_dbr; /* fill buffer */
|
||||
bptr = bptr + 1;
|
||||
if (bptr < bps) rx_tr = 1; /* if more, set xfer */
|
||||
rx_buf[rx_bptr] = rx_dbr; /* fill buffer */
|
||||
rx_bptr = rx_bptr + 1;
|
||||
if (rx_bptr < bps) rx_tr = 1; /* if more, set xfer */
|
||||
else rx_done (0, 0); } /* else done */
|
||||
else {
|
||||
byptr = PTR12 (bptr); /* 12b xfer */
|
||||
if (bptr & 1) { /* odd or even? */
|
||||
byptr = PTR12 (rx_bptr); /* 12b xfer */
|
||||
if (rx_bptr & 1) { /* odd or even? */
|
||||
rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017);
|
||||
rx_buf[byptr + 1] = rx_dbr & 0377; }
|
||||
else {
|
||||
rx_buf[byptr] = (rx_dbr >> 4) & 0377;
|
||||
rx_buf[byptr + 1] = (rx_dbr & 017) << 4; }
|
||||
bptr = bptr + 1;
|
||||
if (bptr < wps) rx_tr = 1; /* if more, set xfer */
|
||||
rx_bptr = rx_bptr + 1;
|
||||
if (rx_bptr < wps) rx_tr = 1; /* if more, set xfer */
|
||||
else {
|
||||
for (i = PTR12 (RX_NUMWD); i < RX_NUMBY; i++)
|
||||
for (i = PTR12 (wps); i < bps; i++)
|
||||
rx_buf[i] = 0; /* else fill sector */
|
||||
rx_done (0, 0); } } /* set done */
|
||||
break;
|
||||
@@ -412,15 +418,13 @@ case RWXFR: /* transfer */
|
||||
da = CALC_DA (rx_track, rx_sector, bps); /* get disk address */
|
||||
if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */
|
||||
if (func == RXCS_READ) { /* read? */
|
||||
for (i = 0; i < bps; i++)
|
||||
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); }
|
||||
for (i = 0; i < bps; i++) rx_buf[i] = fbuf[da + i]; }
|
||||
else { /* write */
|
||||
if (uptr->flags & UNIT_WPRT) { /* locked? */
|
||||
rx_done (0, 0100); /* done, error */
|
||||
break; }
|
||||
for (i = 0; i < RX_NUMBY; i++) /* write */
|
||||
*(((int8 *) uptr->filebuf) + da + i) = rx_buf[i];
|
||||
da = da + RX_NUMBY;
|
||||
for (i = 0; i < bps; i++) fbuf[da + i] = rx_buf[i];
|
||||
da = da + bps;
|
||||
if (da > uptr->hwmark) uptr->hwmark = da; }
|
||||
rx_done (0, 0); /* done */
|
||||
break;
|
||||
@@ -433,8 +437,7 @@ case SDCNF: /* confirm set density */
|
||||
sim_activate (uptr, rx_cwait * 100); /* schedule operation */
|
||||
break;
|
||||
case SDXFR: /* erase disk */
|
||||
for (i = 0; i < (int32) uptr->capac; i++)
|
||||
*(((int8 *) uptr->filebuf) + i) = 0;
|
||||
for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0;
|
||||
uptr->hwmark = uptr->capac;
|
||||
if (rx_csr & RXCS_DEN) uptr->flags = uptr->flags | UNIT_DEN;
|
||||
else uptr->flags = uptr->flags & ~UNIT_DEN;
|
||||
@@ -445,7 +448,13 @@ case CMD_COMPLETE: /* command complete */
|
||||
if (func == RXCS_ECODE) { /* read ecode? */
|
||||
rx_dbr = rx_ecode; /* set dbr */
|
||||
rx_done (0, -1); } /* don't update */
|
||||
else rx_done (0, 0);
|
||||
else if (rx_28) { /* no, read sta; RX28? */
|
||||
rx_esr = rx_esr & ~RXES_DERR; /* assume dens match */
|
||||
if (((uptr->flags & UNIT_DEN) != 0) ^ /* densities mismatch? */
|
||||
((rx_csr & RXCS_DEN) != 0))
|
||||
rx_done (RXES_DERR, 0240); /* yes, error */
|
||||
else rx_done (0, 0); } /* no, ok */
|
||||
else rx_done (0, 0); /* RX8E status */
|
||||
break;
|
||||
|
||||
case INIT_COMPLETE: /* init complete */
|
||||
@@ -456,7 +465,7 @@ case INIT_COMPLETE: /* init complete */
|
||||
break; }
|
||||
da = CALC_DA (1, 1, bps); /* track 1, sector 1 */
|
||||
for (i = 0; i < bps; i++) /* read sector */
|
||||
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i);
|
||||
rx_buf[i] = fbuf[da + i];
|
||||
rx_done (RXES_ID, 0); /* set done */
|
||||
if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020;
|
||||
break; } /* end case state */
|
||||
@@ -475,7 +484,7 @@ rx_state = IDLE; /* now idle */
|
||||
dev_done = dev_done | INT_RX; /* set done */
|
||||
int_req = INT_UPDATE; /* update ints */
|
||||
rx_esr = (rx_esr | esr_flags) & ~(RXES_DRDY|RXES_RX02|RXES_DEN);
|
||||
if (rx_28) rx_esr = rx_esr | RXES_RX02; /* update estat */
|
||||
if (rx_28) rx_esr = rx_esr | RXES_RX02; /* RX28? */
|
||||
if (rx_unit[drv].flags & UNIT_ATT) { /* update drv rdy */
|
||||
rx_esr = rx_esr | RXES_DRDY;
|
||||
if (rx_unit[drv].flags & UNIT_DEN) /* update density */
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
17-Oct-03 RMS Added TSC8-75, TD8E support, DECtape off reel message
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
30-Dec-01 RMS Revised for new TTX
|
||||
26-Nov-01 RMS Added RL8A support
|
||||
@@ -43,13 +44,15 @@
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern DEVICE tsc_dev;
|
||||
extern DEVICE ptr_dev, ptp_dev;
|
||||
extern DEVICE tti_dev, tto_dev;
|
||||
extern DEVICE clk_dev, lpt_dev;
|
||||
extern DEVICE rk_dev, rl_dev;
|
||||
extern DEVICE rx_dev;
|
||||
extern DEVICE df_dev, rf_dev;
|
||||
extern DEVICE dt_dev, mt_dev;
|
||||
extern DEVICE dt_dev, td_dev;
|
||||
extern DEVICE mt_dev;
|
||||
extern DEVICE ttix_dev, ttox_dev;
|
||||
extern REG cpu_reg[];
|
||||
extern uint16 M[];
|
||||
@@ -74,14 +77,23 @@ int32 sim_emax = 4;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&ptr_dev, &ptp_dev,
|
||||
&tti_dev, &tto_dev,
|
||||
&ttix_dev, &ttox_dev,
|
||||
&clk_dev, &lpt_dev,
|
||||
&rk_dev, &rl_dev,
|
||||
&tsc_dev,
|
||||
&ptr_dev,
|
||||
&ptp_dev,
|
||||
&tti_dev,
|
||||
&tto_dev,
|
||||
&ttix_dev,
|
||||
&ttox_dev,
|
||||
&clk_dev,
|
||||
&lpt_dev,
|
||||
&rk_dev,
|
||||
&rl_dev,
|
||||
&rx_dev,
|
||||
&df_dev, &rf_dev,
|
||||
&dt_dev, &mt_dev,
|
||||
&df_dev,
|
||||
&rf_dev,
|
||||
&dt_dev,
|
||||
&td_dev,
|
||||
&mt_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
@@ -89,7 +101,8 @@ const char *sim_stop_messages[] = {
|
||||
"Unimplemented instruction",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Non-standard device number" };
|
||||
"Non-standard device number",
|
||||
"DECtape off reel" };
|
||||
|
||||
/* Binary loader
|
||||
|
||||
@@ -230,6 +243,8 @@ static const char *opcode[] = {
|
||||
"RLCB", "RLSA", "RLWC",
|
||||
"RRER", "RRWC", "RRCA", "RRCB",
|
||||
"RRSA", "RRSI", "RLSE",
|
||||
"ETDS", "ESKP", "ECTF", "ECDF",
|
||||
"ERTB", "ESME", "ERIOT", "ETEN",
|
||||
|
||||
"CDF", "CIF", "CIF CDF",
|
||||
"AND", "TAD", "ISZ", "DCA", "JMS", "JMP", "IOT",
|
||||
@@ -287,6 +302,8 @@ static const int32 opc_val[] = {
|
||||
06604+I_NPN, 06605+I_NPN, 06607+I_NPN,
|
||||
06610+I_NPN, 06611+I_NPN, 06612+I_NPN, 06613+I_NPN,
|
||||
06614+I_NPN, 06615+I_NPN, 06617+I_NPN,
|
||||
06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN,
|
||||
06364+I_NPN, 06365+I_NPN, 06366+I_NPN, 06367+I_NPN,
|
||||
|
||||
06201+I_FLD, 06202+I_FLD, 06203+I_FLD,
|
||||
00000+I_MRF, 01000+I_MRF, 02000+I_MRF, 03000+I_MRF,
|
||||
@@ -411,7 +428,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
case I_V_OP3: /* operate group 3 */
|
||||
sp = fprint_opr (of, inst & 0320, j, 0);
|
||||
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
|
||||
break; } /* end case */
|
||||
break; } /* end case */
|
||||
return SCPE_OK; } /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
|
||||
847
PDP8/pdp8_td.c
Normal file
847
PDP8/pdp8_td.c
Normal file
@@ -0,0 +1,847 @@
|
||||
/* pdp8_td.c: PDP-8 simple DECtape controller (TD8E) simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK 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.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module was inspired by Gerold Pauler's TD8E simulator for Doug Jones'
|
||||
PDP8 simulator but tracks the hardware implementation more closely.
|
||||
|
||||
td TD8E/TU56 DECtape
|
||||
|
||||
PDP-8 DECtapes are represented in memory by fixed length buffer of 12b words.
|
||||
Three file formats are supported:
|
||||
|
||||
18b/36b 256 words per block [256 x 18b]
|
||||
16b 256 words per block [256 x 16b]
|
||||
12b 129 words per block [129 x 12b]
|
||||
|
||||
When a 16b or 18/36b DECtape file is read in, it is converted to 12b format.
|
||||
|
||||
DECtape motion is measured in 3b lines. Time between lines is 33.33us.
|
||||
Tape density is nominally 300 lines per inch. The format of a DECtape (as
|
||||
taken from the TD8E formatter) is:
|
||||
|
||||
reverse end zone 8192 reverse end zone codes ~ 10 feet
|
||||
reverse buffer 200 interblock codes
|
||||
block 0
|
||||
:
|
||||
block n
|
||||
forward buffer 200 interblock codes
|
||||
forward end zone 8192 forward end zone codes ~ 10 feet
|
||||
|
||||
A block consists of five 18b header words, a tape-specific number of data
|
||||
words, and five 18b trailer words. All systems except the PDP-8 use a
|
||||
standard block length of 256 words; the PDP-8 uses a standard block length
|
||||
of 86 words (x 18b = 129 words x 12b).
|
||||
|
||||
Because a DECtape file only contains data, the simulator cannot support
|
||||
write timing and mark track and can only do a limited implementation
|
||||
of non-data words. Read assumes that the tape has been conventionally
|
||||
written forward:
|
||||
|
||||
header word 0 0
|
||||
header word 1 block number (for forward reads)
|
||||
header words 2,3 0
|
||||
header word 4 checksum (for reverse reads)
|
||||
:
|
||||
trailer word 4 checksum (for forward reads)
|
||||
trailer words 3,2 0
|
||||
trailer word 1 block number (for reverse reads)
|
||||
trailer word 0 0
|
||||
|
||||
Write modifies only the data words and dumps the non-data words in the
|
||||
bit bucket.
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
#define DT_NUMDR 2 /* #drives */
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */
|
||||
#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define UNIT_8FMT (1 << UNIT_V_8FMT)
|
||||
#define UNIT_11FMT (1 << UNIT_V_11FMT)
|
||||
#define STATE u3 /* unit state */
|
||||
#define LASTT u4 /* last time update */
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||
|
||||
/* System independent DECtape constants */
|
||||
|
||||
#define DT_LPERMC 6 /* lines per mark track */
|
||||
#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */
|
||||
#define DT_BFLIN (200 * DT_LPERMC) /* end zone buffer */
|
||||
#define DT_HTLIN (5 * DT_LPERMC) /* lines per hdr/trlr */
|
||||
|
||||
/* 16b, 18b, 36b DECtape constants */
|
||||
|
||||
#define D18_WSIZE 6 /* word sizein lines */
|
||||
#define D18_BSIZE 384 /* block size in 12b */
|
||||
#define D18_TSIZE 578 /* tape size */
|
||||
#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN)
|
||||
#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE))
|
||||
#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */
|
||||
|
||||
#define D18_NBSIZE ((D18_BSIZE * D8_WSIZE) / D18_WSIZE)
|
||||
#define D18_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int32))
|
||||
#define D11_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int16))
|
||||
|
||||
/* 12b DECtape constants */
|
||||
|
||||
#define D8_WSIZE 4 /* word size in lines */
|
||||
#define D8_BSIZE 129 /* block size in 12b */
|
||||
#define D8_TSIZE 1474 /* tape size */
|
||||
#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN)
|
||||
#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE))
|
||||
#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */
|
||||
#define D8_FILSIZ (D8_CAPAC * sizeof (int16))
|
||||
|
||||
/* This controller */
|
||||
|
||||
#define DT_CAPAC D8_CAPAC /* default */
|
||||
#define DT_WSIZE D8_WSIZE
|
||||
|
||||
/* Calculated constants, per unit */
|
||||
|
||||
#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
|
||||
#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
|
||||
#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
|
||||
#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
|
||||
#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)
|
||||
|
||||
#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u))
|
||||
#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u))
|
||||
|
||||
/* Command register */
|
||||
|
||||
#define TDC_UNIT 04000 /* unit select */
|
||||
#define TDC_FWDRV 02000 /* fwd/rev */
|
||||
#define TDC_STPGO 01000 /* stop/go */
|
||||
#define TDC_RW 00400 /* read/write */
|
||||
#define TDC_MASK 07400 /* implemented */
|
||||
#define TDC_GETUNIT(x) (((x) & TDC_UNIT)? 1: 0)
|
||||
|
||||
/* Status register */
|
||||
|
||||
#define TDS_WLO 00200 /* write lock */
|
||||
#define TDS_TME 00100 /* timing/sel err */
|
||||
|
||||
/* Mark track register and codes */
|
||||
|
||||
#define MTK_MASK 077
|
||||
#define MTK_REV_END 055 /* rev end zone */
|
||||
#define MTK_INTER 025 /* interblock */
|
||||
#define MTK_FWD_BLK 026 /* fwd block */
|
||||
#define MTK_REV_GRD 032 /* reverse guard */
|
||||
#define MTK_FWD_PRE 010 /* lock, etc */
|
||||
#define MTK_DATA 070 /* data */
|
||||
#define MTK_REV_PRE 073 /* lock, etc */
|
||||
#define MTK_FWD_GRD 051 /* fwd guard */
|
||||
#define MTK_REV_BLK 045 /* rev block */
|
||||
#define MTK_FWD_END 022 /* fwd end zone */
|
||||
|
||||
/* DECtape state */
|
||||
|
||||
#define STA_STOP 0 /* stopped */
|
||||
#define STA_DEC 2 /* decelerating */
|
||||
#define STA_ACC 4 /* accelerating */
|
||||
#define STA_UTS 6 /* up to speed */
|
||||
#define STA_DIR 1 /* fwd/rev */
|
||||
|
||||
#define ABS(x) (((x) < 0)? (-(x)): (x))
|
||||
#define MTK_BIT(c,p) (((c) >> (DT_LPERMC - 1 - ((p) % DT_LPERMC))) & 1)
|
||||
|
||||
/* State and declarations */
|
||||
|
||||
int32 td_cmd = 0; /* command */
|
||||
int32 td_dat = 0; /* data */
|
||||
int32 td_mtk = 0; /* mark track */
|
||||
int32 td_slf = 0; /* single line flag */
|
||||
int32 td_qlf = 0; /* quad line flag */
|
||||
int32 td_tme = 0; /* timing error flag */
|
||||
int32 td_csum = 0; /* save check sum */
|
||||
int32 td_qlctr = 0; /* quad line ctr */
|
||||
int32 td_ltime = 20; /* interline time */
|
||||
int32 td_dctime = 40000; /* decel time */
|
||||
static uint8 tdb_mtk[DT_NUMDR][D18_LPERB]; /* mark track bits */
|
||||
|
||||
DEVICE td_dev;
|
||||
int32 td77 (int32 IR, int32 AC);
|
||||
t_stat td_svc (UNIT *uptr);
|
||||
t_stat td_reset (DEVICE *dptr);
|
||||
t_stat td_attach (UNIT *uptr, char *cptr);
|
||||
t_stat td_detach (UNIT *uptr);
|
||||
t_stat td_boot (int32 unitno, DEVICE *dptr);
|
||||
t_bool td_newsa (int32 newf);
|
||||
t_bool td_setpos (UNIT *uptr);
|
||||
int32 td_header (UNIT *uptr, int32 blk, int32 line);
|
||||
int32 td_trailer (UNIT *uptr, int32 blk, int32 line);
|
||||
int32 td_read (UNIT *uptr, int32 blk, int32 line);
|
||||
void td_write (UNIT *uptr, int32 blk, int32 line, int32 datb);
|
||||
int32 td_set_mtk (int32 code, int32 u, int32 k);
|
||||
t_stat td_show_pos (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 sim_switches;
|
||||
extern int32 sim_is_running;
|
||||
|
||||
/* TD data structures
|
||||
|
||||
td_dev DT device descriptor
|
||||
td_unit DT unit list
|
||||
td_reg DT register list
|
||||
td_mod DT modifier list
|
||||
*/
|
||||
|
||||
DIB td_dib = { DEV_TD8E, 1, { &td77 } };
|
||||
|
||||
UNIT td_unit[] = {
|
||||
{ UDATA (&td_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
|
||||
UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
|
||||
{ UDATA (&td_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
|
||||
UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) } };
|
||||
|
||||
REG td_reg[] = {
|
||||
{ GRDATA (TDCMD, td_cmd, 8, 4, 8) },
|
||||
{ ORDATA (TDDAT, td_dat, 12) },
|
||||
{ ORDATA (TDMTK, td_mtk, 6) },
|
||||
{ FLDATA (TDSLF, td_slf, 0) },
|
||||
{ FLDATA (TDQLF, td_qlf, 0) },
|
||||
{ FLDATA (TDTME, td_tme, 0) },
|
||||
{ ORDATA (TDQL, td_qlctr, 2) },
|
||||
{ ORDATA (TDCSUM, td_csum, 6), REG_RO },
|
||||
{ DRDATA (LTIME, td_ltime, 31), REG_NZ | PV_LEFT },
|
||||
{ DRDATA (DCTIME, td_dctime, 31), REG_NZ | PV_LEFT },
|
||||
{ URDATA (POS, td_unit[0].pos, 10, T_ADDR_W, 0,
|
||||
DT_NUMDR, PV_LEFT | REG_RO) },
|
||||
{ URDATA (STATT, td_unit[0].STATE, 8, 18, 0,
|
||||
DT_NUMDR, REG_RO) },
|
||||
{ URDATA (LASTT, td_unit[0].LASTT, 10, 32, 0,
|
||||
DT_NUMDR, REG_HRO) },
|
||||
{ ORDATA (DEVNUM, td_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB td_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },
|
||||
{ UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL },
|
||||
{ UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "POSITION", NULL, NULL, &td_show_pos },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE td_dev = {
|
||||
"TD", td_unit, td_reg, td_mod,
|
||||
DT_NUMDR, 8, 24, 1, 8, 12,
|
||||
NULL, NULL, &td_reset,
|
||||
&td_boot, &td_attach, &td_detach,
|
||||
&td_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 td77 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
int32 u = TDC_GETUNIT (td_cmd); /* get unit */
|
||||
int32 diff, t;
|
||||
|
||||
switch (pulse) {
|
||||
case 01: /* SDSS */
|
||||
if (td_slf) return AC | IOT_SKP;
|
||||
break;
|
||||
case 02: /* SDST */
|
||||
if (td_tme) return AC | IOT_SKP;
|
||||
break;
|
||||
case 03: /* SDSQ */
|
||||
if (td_qlf) return AC | IOT_SKP;
|
||||
break;
|
||||
case 04: /* SDLC */
|
||||
td_tme = 0; /* clear tim err */
|
||||
diff = (td_cmd ^ AC) & TDC_MASK; /* cmd changes */
|
||||
td_cmd = AC & TDC_MASK; /* update cmd */
|
||||
if ((diff != 0) && (diff != TDC_RW)) { /* signif change? */
|
||||
if (td_newsa (td_cmd)) /* new command */
|
||||
return AC | (STOP_DTOFF << IOT_V_REASON); }
|
||||
break;
|
||||
case 05: /* SDLD */
|
||||
td_slf = 0; /* clear flags */
|
||||
td_qlf = 0;
|
||||
td_qlctr = 0;
|
||||
td_dat = AC; /* load data reg */
|
||||
break;
|
||||
case 06: /* SDRC */
|
||||
td_slf = 0; /* clear flags */
|
||||
td_qlf = 0;
|
||||
td_qlctr = 0;
|
||||
t = td_cmd | td_mtk; /* form status */
|
||||
if (td_tme || !(td_unit[u].flags & UNIT_ATT)) /* tim/sel err? */
|
||||
t = t | TDS_TME;
|
||||
if (td_unit[u].flags & UNIT_WPRT) /* write locked? */
|
||||
t = t | TDS_WLO;
|
||||
return t; /* return status */
|
||||
case 07: /* SDRD */
|
||||
td_slf = 0; /* clear flags */
|
||||
td_qlf = 0;
|
||||
td_qlctr = 0;
|
||||
return td_dat; } /* return data */
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Command register change (start/stop, forward/reverse, new unit)
|
||||
|
||||
1. If change in motion, stop to start
|
||||
- schedule up to speed
|
||||
- set function as next state
|
||||
2. If change in motion, start to stop, or change in direction
|
||||
- schedule stop
|
||||
*/
|
||||
|
||||
t_bool td_newsa (int32 newf)
|
||||
{
|
||||
int32 prev_mving, new_mving, prev_dir, new_dir;
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = td_dev.units + TDC_GETUNIT (newf); /* new unit */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return FALSE; /* new unit attached? */
|
||||
|
||||
new_mving = ((newf & TDC_STPGO) != 0); /* new moving? */
|
||||
prev_mving = (uptr->STATE != STA_STOP); /* previous moving? */
|
||||
new_dir = ((newf & TDC_FWDRV) != 0); /* new dir? */
|
||||
prev_dir = ((uptr->STATE & STA_DIR) != 0); /* previous dir? */
|
||||
|
||||
td_mtk = 0; /* mark trk reg cleared */
|
||||
|
||||
if (!prev_mving && !new_mving) return FALSE; /* stop from stop? */
|
||||
|
||||
if (new_mving && !prev_mving) { /* start from stop? */
|
||||
if (td_setpos (uptr)) return TRUE; /* update pos */
|
||||
sim_cancel (uptr); /* stop current */
|
||||
sim_activate (uptr, td_dctime - (td_dctime >> 2)); /* sched accel */
|
||||
uptr->STATE = STA_ACC | new_dir; /* set status */
|
||||
td_slf = td_qlf = td_qlctr = 0; /* clear state */
|
||||
return FALSE; }
|
||||
|
||||
if ((prev_mving && !new_mving) || /* stop from moving? */
|
||||
(prev_dir != new_dir)) { /* dir chg while moving? */
|
||||
if (uptr->STATE >= STA_ACC) { /* not stopping? */
|
||||
if (td_setpos (uptr)) return TRUE; /* update pos */
|
||||
sim_cancel (uptr); /* stop current */
|
||||
sim_activate (uptr, td_dctime); /* schedule decel */
|
||||
uptr->STATE = STA_DEC | prev_dir; /* set status */
|
||||
td_slf = td_qlf = td_qlctr = 0; } /* clear state */
|
||||
return FALSE; }
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Update DECtape position
|
||||
|
||||
DECtape motion is modeled as a constant velocity, with linear
|
||||
acceleration and deceleration. The motion equations are as follows:
|
||||
|
||||
t = time since operation started
|
||||
tmax = time for operation (accel, decel only)
|
||||
v = at speed velocity in lines (= 1/td_ltime)
|
||||
|
||||
Then:
|
||||
at speed dist = t * v
|
||||
accel dist = (t^2 * v) / (2 * tmax)
|
||||
decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax)
|
||||
|
||||
This routine uses the relative (integer) time, rather than the absolute
|
||||
(floating point) time, to allow save and restore of the start times.
|
||||
*/
|
||||
|
||||
t_bool td_setpos (UNIT *uptr)
|
||||
{
|
||||
uint32 new_time, ut, ulin, udelt;
|
||||
int32 delta;
|
||||
|
||||
new_time = sim_grtime (); /* current time */
|
||||
ut = new_time - uptr->LASTT; /* elapsed time */
|
||||
if (ut == 0) return FALSE; /* no time gone? exit */
|
||||
uptr->LASTT = new_time; /* update last time */
|
||||
switch (uptr->STATE & ~STA_DIR) { /* case on motion */
|
||||
case STA_STOP: /* stop */
|
||||
delta = 0;
|
||||
break;
|
||||
case STA_DEC: /* slowing */
|
||||
ulin = ut / (uint32) td_ltime;
|
||||
udelt = td_dctime / td_ltime;
|
||||
delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
|
||||
break;
|
||||
case STA_ACC: /* accelerating */
|
||||
ulin = ut / (uint32) td_ltime;
|
||||
udelt = (td_dctime - (td_dctime >> 2)) / td_ltime;
|
||||
delta = (ulin * ulin) / (2 * udelt);
|
||||
break;
|
||||
case STA_UTS: /* at speed */
|
||||
delta = ut / (uint32) td_ltime;
|
||||
break; }
|
||||
if (uptr->STATE & STA_DIR) uptr->pos = uptr->pos - delta; /* update pos */
|
||||
else uptr->pos = uptr->pos + delta;
|
||||
if (((int32) uptr->pos < 0) ||
|
||||
((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) {
|
||||
detach_unit (uptr); /* off reel */
|
||||
sim_cancel (uptr); /* no timing pulses */
|
||||
return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Unit service - unit is either changing speed, or it is up to speed */
|
||||
|
||||
t_stat td_svc (UNIT *uptr)
|
||||
{
|
||||
int32 mot = uptr->STATE & ~STA_DIR;
|
||||
int32 dir = uptr->STATE & STA_DIR;
|
||||
int32 unum = uptr - td_dev.units;
|
||||
int32 su = TDC_GETUNIT (td_cmd);
|
||||
int32 mtkb, datb;
|
||||
|
||||
/* Motion cases
|
||||
|
||||
Decelerating - if go, next state must be accel as specified by td_cmd
|
||||
Accelerating - next state must be up to speed, fall through
|
||||
Up to speed - process line */
|
||||
|
||||
if (mot == STA_STOP) return SCPE_OK; /* stopped? done */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
uptr->STATE = uptr->pos = 0; /* also done */
|
||||
return SCPE_UNATT; }
|
||||
|
||||
switch (mot) { /* case on motion */
|
||||
case STA_DEC: /* deceleration */
|
||||
if (td_setpos (uptr)) return STOP_DTOFF; /* update pos */
|
||||
if ((unum != su) || !(td_cmd & TDC_STPGO)) /* not sel or stop? */
|
||||
uptr->STATE = 0; /* stop */
|
||||
else { /* selected and go */
|
||||
uptr->STATE = STA_ACC | /* accelerating */
|
||||
((td_cmd & TDC_FWDRV)? STA_DIR: 0); /* in new dir */
|
||||
sim_activate (uptr, td_dctime - (td_dctime >> 2)); }
|
||||
return SCPE_OK;
|
||||
case STA_ACC: /* accelerating */
|
||||
if (td_setpos (uptr)) return STOP_DTOFF; /* update pos */
|
||||
uptr->STATE = STA_UTS | dir; /* set up to speed */
|
||||
break;
|
||||
case STA_UTS: /* up to speed */
|
||||
if (dir) uptr->pos = uptr->pos - 1; /* adjust position */
|
||||
else uptr->pos = uptr->pos + 1;
|
||||
uptr->LASTT = sim_grtime (); /* save time */
|
||||
if (((int32) uptr->pos < 0) || /* off reel? */
|
||||
(uptr->pos >= (((uint32) DTU_FWDEZ (uptr)) + DT_EZLIN))) {
|
||||
detach_unit (uptr);
|
||||
return STOP_DTOFF; }
|
||||
break; } /* check function */
|
||||
|
||||
/* At speed - process the current line
|
||||
|
||||
Once the TD8E is running at speed, it operates line by line. If reading,
|
||||
the current mark track bit is shifted into the mark track register, and
|
||||
the current data nibble (3b) is shifted into the data register. If
|
||||
writing, the current mark track bit is shifted into the mark track
|
||||
register, the top nibble from the data register is written to tape, and
|
||||
the data register is shifted up. The complexity here comes from
|
||||
synthesizing the mark track, based on tape position, and the header data. */
|
||||
|
||||
sim_activate (uptr, td_ltime); /* sched next line */
|
||||
if (unum != su) return SCPE_OK; /* not sel? done */
|
||||
td_slf = 1; /* set single */
|
||||
td_qlctr = (td_qlctr + 1) % DT_WSIZE; /* count words */
|
||||
if (td_qlctr == 0) { /* lines mod 4? */
|
||||
if (td_qlf) { /* quad line set? */
|
||||
td_tme = 1; /* timing error */
|
||||
td_cmd = td_cmd & ~TDC_RW; } /* clear write */
|
||||
else td_qlf = 1; } /* no, set quad */
|
||||
|
||||
datb = 0; /* assume no data */
|
||||
if (uptr->pos < (DT_EZLIN - DT_BFLIN)) /* rev end zone? */
|
||||
mtkb = MTK_BIT (MTK_REV_END, uptr->pos);
|
||||
else if (uptr->pos < DT_EZLIN) /* rev buffer? */
|
||||
mtkb = MTK_BIT (MTK_INTER, uptr->pos);
|
||||
else if (uptr->pos < ((uint32) DTU_FWDEZ (uptr))) { /* data zone? */
|
||||
int32 blkno = DT_LIN2BL (uptr->pos, uptr); /* block # */
|
||||
int32 lineno = DT_LIN2OF (uptr->pos, uptr); /* line # within block */
|
||||
if (lineno < DT_HTLIN) { /* header? */
|
||||
if ((td_cmd & TDC_RW) == 0) /* read? */
|
||||
datb = td_header (uptr, blkno, lineno); } /* get nibble */
|
||||
else if (lineno < (DTU_LPERB (uptr) - DT_HTLIN)) { /* data? */
|
||||
if (td_cmd & TDC_RW) /* write? */
|
||||
td_write (uptr, blkno, /* write data nibble */
|
||||
lineno - DT_HTLIN, /* data rel line num */
|
||||
(td_dat >> 9) & 07);
|
||||
else datb = td_read (uptr, blkno, /* no, read */
|
||||
lineno - DT_HTLIN); }
|
||||
else if ((td_cmd & TDC_RW) == 0) /* trailer; read? */
|
||||
datb = td_trailer (uptr, blkno, lineno - /* get trlr nibble */
|
||||
(DTU_LPERB (uptr) - DT_HTLIN));
|
||||
mtkb = tdb_mtk[unum][lineno]; }
|
||||
else if (uptr->pos < (((uint32) DTU_FWDEZ (uptr)) + DT_BFLIN))
|
||||
mtkb = MTK_BIT (MTK_INTER, uptr->pos); /* fwd buffer? */
|
||||
else mtkb = MTK_BIT (MTK_FWD_END, uptr->pos); /* fwd end zone */
|
||||
|
||||
if (dir) { /* reverse? */
|
||||
mtkb = mtkb ^ 01; /* complement mark bit, */
|
||||
datb = datb ^ 07; } /* data bits */
|
||||
td_mtk = ((td_mtk << 1) | mtkb) & MTK_MASK; /* shift mark reg */
|
||||
td_dat = ((td_dat << 3) | datb) & 07777; /* shift data reg */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Header read - reads out 18b words in 3b increments
|
||||
|
||||
word lines contents
|
||||
0 0-5 0
|
||||
1 6-11 block number
|
||||
2 12-17 0
|
||||
3 18-23 0
|
||||
4 24-29 reverse checksum (0777777)
|
||||
*/
|
||||
|
||||
int32 td_header (UNIT *uptr, int32 blk, int32 line)
|
||||
{
|
||||
int32 nibp;
|
||||
|
||||
switch (line) {
|
||||
case 8: case 9: case 10: case 11: /* block num */
|
||||
nibp = 3 * (DT_LPERMC - 1 - (line % DT_LPERMC));
|
||||
return (blk >> nibp) & 07;
|
||||
case 24: case 25: case 26: case 27: case 28: case 29: /* rev csum */
|
||||
return 07; /* 777777 */
|
||||
default:
|
||||
return 0; }
|
||||
}
|
||||
|
||||
/* Trailer read - reads out 18b words in 3b increments
|
||||
Checksum is stored to avoid double calculation
|
||||
|
||||
word lines contents
|
||||
0 0-5 forward checksum (lines 0-1, rest 0)
|
||||
1 6-11 0
|
||||
2 12-17 0
|
||||
3 18-23 reverse block mark
|
||||
4 24-29 0
|
||||
|
||||
Note that the reverse block mark (when read forward) appears
|
||||
as the complement obverse (3b nibbles swapped end for end and
|
||||
complemented).
|
||||
*/
|
||||
|
||||
int32 td_trailer (UNIT *uptr, int32 blk, int32 line)
|
||||
{
|
||||
int32 nibp, i, ba;
|
||||
int16 *fbuf= uptr->filebuf;
|
||||
|
||||
switch (line) {
|
||||
case 0:
|
||||
td_csum = 07777; /* init csum */
|
||||
ba = blk * DTU_BSIZE (uptr);
|
||||
for (i = 0; i < DTU_BSIZE (uptr); i++) /* loop thru buf */
|
||||
td_csum = (td_csum ^ ~fbuf[ba + i]) & 07777;
|
||||
td_csum = ((td_csum >> 6) ^ td_csum) & 077;
|
||||
return (td_csum >> 3) & 07;
|
||||
case 1:
|
||||
return (td_csum & 07);
|
||||
case 18: case 19: case 20: case 21:
|
||||
nibp = 3 * (line % DT_LPERMC);
|
||||
return ((blk >> nibp) & 07) ^ 07;
|
||||
default:
|
||||
return 0; }
|
||||
}
|
||||
|
||||
/* Data read - convert block number/data line # to offset in data array */
|
||||
|
||||
int32 td_read (UNIT *uptr, int32 blk, int32 line)
|
||||
{
|
||||
int16 *fbuf = uptr->filebuf; /* buffer */
|
||||
uint32 ba = blk * DTU_BSIZE (uptr); /* block base */
|
||||
int32 nibp = 3 * (DT_WSIZE - 1 - (line % DT_WSIZE)); /* nibble pos */
|
||||
|
||||
ba = ba + (line / DT_WSIZE); /* block addr */
|
||||
return (fbuf[ba] >> nibp) & 07; /* get data nibble */
|
||||
}
|
||||
|
||||
/* Data write - convert block number/data line # to offset in data array */
|
||||
|
||||
void td_write (UNIT *uptr, int32 blk, int32 line, int32 dat)
|
||||
{
|
||||
int16 *fbuf = uptr->filebuf; /* buffer */
|
||||
uint32 ba = blk * DTU_BSIZE (uptr); /* block base */
|
||||
int32 nibp = 3 * (DT_WSIZE - 1 - (line % DT_WSIZE)); /* nibble pos */
|
||||
|
||||
ba = ba + (line / DT_WSIZE); /* block addr */
|
||||
fbuf[ba] = (fbuf[ba] & ~(07 << nibp)) | (dat << nibp); /* upd data nibble */
|
||||
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; /* upd length */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat td_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */
|
||||
uptr = td_dev.units + i;
|
||||
if (sim_is_running) { /* CAF? */
|
||||
if (uptr->STATE >= STA_ACC) { /* accel or uts? */
|
||||
if (td_setpos (uptr)) continue; /* update pos */
|
||||
sim_cancel (uptr);
|
||||
sim_activate (uptr, td_dctime); /* sched decel */
|
||||
uptr->STATE = STA_DEC | (uptr->STATE & STA_DIR);
|
||||
} }
|
||||
else {
|
||||
sim_cancel (uptr); /* sim reset */
|
||||
uptr->STATE = 0;
|
||||
uptr->LASTT = sim_grtime (); } }
|
||||
td_slf = td_qlf = td_qlctr = 0; /* clear state */
|
||||
td_cmd = td_dat = td_mtk = 0;
|
||||
td_csum = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine - OS/8 only
|
||||
|
||||
1) Read reverse until reverse end zone (mark track is complement obverse
|
||||
2) Read forward until mark track code 031. This is a composite code from
|
||||
the last 4b of the forward block number and the first two bits of the
|
||||
reverse guard (01 -0110 01- 1010). There are 16 lines before the first
|
||||
data word.
|
||||
3) Store data words from 7354 to end of page. This includes header and
|
||||
trailer words.
|
||||
4) Continue at location 7400.
|
||||
*/
|
||||
|
||||
#define BOOT_START 07300
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 boot_rom[] = {
|
||||
01312, /* ST, TAD L4MT ;=2000, reverse */
|
||||
04312, /* JMS L4MT ; rev lk for 022 */
|
||||
04312, /* JMS L4MT ; fwd lk for 031 */
|
||||
06773, /* DAT, SDSQ ; wait for 12b */
|
||||
05303, /* JMP .-1 */
|
||||
06777, /* SDRD ; read word */
|
||||
03726, /* DCA I BUF ; store */
|
||||
02326, /* ISZ BUF ; incr ptr */
|
||||
05303, /* JMP DAT ; if not 0, cont */
|
||||
05732, /* JMP I SCB ; jump to boot */
|
||||
02000, /* L4MT,2000 ; overwritten */
|
||||
01300, /* TAD ST ; =1312, go */
|
||||
06774, /* SDLC ; new command */
|
||||
06771, /* MTK, SDSS ; wait for mark */
|
||||
05315, /* JMP .-1 */
|
||||
06776, /* SDRC ; get mark code */
|
||||
00331, /* AND K77 ; mask to 6b */
|
||||
01327, /* CMP, TAD MCD ; got target code? */
|
||||
07640, /* SZA CLA ; skip if yes */
|
||||
05315, /* JMP MTK ; wait for mark */
|
||||
02321, /* ISZ CMP ; next target */
|
||||
05712, /* JMP I L4MT ; exit */
|
||||
07354, /* BUF, 7354 ; loading point */
|
||||
07756, /* MCD, -22 ; target 1 */
|
||||
07747, /* -31 ; target 2 */
|
||||
00077, /* 77 ; mask */
|
||||
07400 /* SCB, 7400 ; secondary boot */
|
||||
};
|
||||
|
||||
t_stat td_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if (unitno) return SCPE_ARG; /* only unit 0 */
|
||||
if (td_dib.dev != DEV_TD8E) return STOP_NOTSTD; /* only std devno */
|
||||
td_unit[unitno].pos = DT_EZLIN;
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine
|
||||
|
||||
Determine 12b, 16b, or 18b/36b format
|
||||
Allocate buffer
|
||||
If 16b or 18b, read 16b or 18b format and convert to 12b in buffer
|
||||
If 12b, read data into buffer
|
||||
Set up mark track bit array
|
||||
*/
|
||||
|
||||
t_stat td_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
uint16 pdp11b[D18_NBSIZE], *fbuf;
|
||||
int32 i, k, mtkpb;
|
||||
int32 u = uptr - td_dev.units;
|
||||
t_stat r;
|
||||
uint32 ba, sz;
|
||||
|
||||
r = attach_unit (uptr, cptr); /* attach */
|
||||
if (r != SCPE_OK) return r; /* fail? */
|
||||
if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */
|
||||
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
|
||||
if (sim_switches & SWMASK ('T')) /* att 18b? */
|
||||
uptr->flags = uptr->flags & ~UNIT_8FMT;
|
||||
else if (sim_switches & SWMASK ('S')) /* att 16b? */
|
||||
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
|
||||
else if (!(sim_switches & SWMASK ('R')) && /* autosize? */
|
||||
(sz = sim_fsize (cptr))) {
|
||||
if (sz == D11_FILSIZ)
|
||||
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
|
||||
else if (sz > D8_FILSIZ)
|
||||
uptr->flags = uptr->flags & ~UNIT_8FMT; } }
|
||||
uptr->capac = DTU_CAPAC (uptr); /* set capacity */
|
||||
uptr->filebuf = calloc (uptr->capac, sizeof (int16));
|
||||
if (uptr->filebuf == NULL) { /* can't alloc? */
|
||||
detach_unit (uptr);
|
||||
return SCPE_MEM; }
|
||||
fbuf = uptr->filebuf; /* file buffer */
|
||||
printf ("%s%d: ", sim_dname (&td_dev), u);
|
||||
if (uptr->flags & UNIT_8FMT) printf ("12b format");
|
||||
else if (uptr->flags & UNIT_11FMT) printf ("16b format");
|
||||
else printf ("18b/36b format");
|
||||
printf (", buffering file in memory\n");
|
||||
if (uptr->flags & UNIT_8FMT) /* 12b? */
|
||||
uptr->hwmark = fxread (uptr->filebuf, sizeof (int16),
|
||||
uptr->capac, uptr->fileref);
|
||||
else { /* 16b/18b */
|
||||
for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
|
||||
if (uptr->flags & UNIT_11FMT) {
|
||||
k = fxread (pdp11b, sizeof (int16), D18_NBSIZE, uptr->fileref);
|
||||
for (i = 0; i < k; i++) pdp18b[i] = pdp11b[i]; }
|
||||
else k = fxread (pdp18b, sizeof (int32), D18_NBSIZE, uptr->fileref);
|
||||
if (k == 0) break;
|
||||
for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0;
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) { /* loop thru blk */
|
||||
fbuf[ba] = (pdp18b[k] >> 6) & 07777;
|
||||
fbuf[ba + 1] = ((pdp18b[k] & 077) << 6) |
|
||||
((pdp18b[k + 1] >> 12) & 077);
|
||||
fbuf[ba + 2] = pdp18b[k + 1] & 07777;
|
||||
ba = ba + 3; } /* end blk loop */
|
||||
} /* end file loop */
|
||||
uptr->hwmark = ba; } /* end else */
|
||||
uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */
|
||||
uptr->pos = DT_EZLIN; /* beyond leader */
|
||||
uptr->LASTT = sim_grtime (); /* last pos update */
|
||||
uptr->STATE = STA_STOP; /* stopped */
|
||||
|
||||
mtkpb = (DTU_BSIZE (uptr) * DT_WSIZE) / DT_LPERMC; /* mtk codes per blk */
|
||||
k = td_set_mtk (MTK_INTER, u, 0); /* fill mark track */
|
||||
k = td_set_mtk (MTK_FWD_BLK, u, k); /* bit array */
|
||||
k = td_set_mtk (MTK_REV_GRD, u, k);
|
||||
for (i = 0; i < 4; i++) k = td_set_mtk (MTK_FWD_PRE, u, k);
|
||||
for (i = 0; i < (mtkpb - 4); i++) k = td_set_mtk (MTK_DATA, u, k);
|
||||
for (i = 0; i < 4; i++) k = td_set_mtk (MTK_REV_PRE, u, k);
|
||||
k = td_set_mtk (MTK_FWD_GRD, u, k);
|
||||
k = td_set_mtk (MTK_REV_BLK, u, k);
|
||||
k = td_set_mtk (MTK_INTER, u, k);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach routine
|
||||
|
||||
If 12b, write buffer to file
|
||||
If 16b or 18b, convert 12b buffer to 16b or 18b and write to file
|
||||
Deallocate buffer
|
||||
*/
|
||||
|
||||
t_stat td_detach (UNIT* uptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
uint16 pdp11b[D18_NBSIZE], *fbuf;
|
||||
int32 i, k;
|
||||
int32 u = uptr - td_dev.units;
|
||||
uint32 ba;
|
||||
|
||||
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
|
||||
fbuf = uptr->filebuf; /* file buffer */
|
||||
if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) { /* any data? */
|
||||
printf ("%s%d: writing buffer to file\n", sim_dname (&td_dev), u);
|
||||
rewind (uptr->fileref); /* start of file */
|
||||
if (uptr->flags & UNIT_8FMT) /* PDP8? */
|
||||
fxwrite (uptr->filebuf, sizeof (int16), /* write file */
|
||||
uptr->hwmark, uptr->fileref);
|
||||
else { /* 16b/18b */
|
||||
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru buf */
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) {
|
||||
pdp18b[k] = ((uint32) (fbuf[ba] & 07777) << 6) |
|
||||
((uint32) (fbuf[ba + 1] >> 6) & 077);
|
||||
pdp18b[k + 1] = ((uint32) (fbuf[ba + 1] & 077) << 12) |
|
||||
((uint32) (fbuf[ba + 2] & 07777));
|
||||
ba = ba + 3; } /* end loop blk */
|
||||
if (uptr->flags & UNIT_11FMT) { /* 16b? */
|
||||
for (i = 0; i < D18_NBSIZE; i++) pdp11b[i] = pdp18b[i];
|
||||
fxwrite (pdp11b, sizeof (int16),
|
||||
D18_NBSIZE, uptr->fileref); }
|
||||
else fxwrite (pdp18b, sizeof (int32),
|
||||
D18_NBSIZE, uptr->fileref);
|
||||
} /* end loop buf */
|
||||
} /* end else */
|
||||
if (ferror (uptr->fileref)) perror ("I/O error");
|
||||
} /* end if hwmark */
|
||||
free (uptr->filebuf); /* release buf */
|
||||
uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */
|
||||
uptr->filebuf = NULL; /* clear buf ptr */
|
||||
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; /* default fmt */
|
||||
uptr->capac = DT_CAPAC; /* default size */
|
||||
uptr->pos = uptr->STATE = 0;
|
||||
sim_cancel (uptr); /* no more pulses */
|
||||
return detach_unit (uptr);
|
||||
}
|
||||
|
||||
/* Set mark track code into bit array */
|
||||
|
||||
int32 td_set_mtk (int32 code, int32 u, int32 k)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 5; i >= 0; i--) tdb_mtk[u][k++] = (code >> i) & 1;
|
||||
return k;
|
||||
}
|
||||
|
||||
/* Show position */
|
||||
|
||||
t_stat td_show_pos (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
|
||||
if (uptr->pos < DT_EZLIN) /* rev end zone? */
|
||||
fprintf (st, "Reverse end zone\n");
|
||||
else if (uptr->pos < ((uint32) DTU_FWDEZ (uptr))) { /* data zone? */
|
||||
int32 blkno = DT_LIN2BL (uptr->pos, uptr); /* block # */
|
||||
int32 lineno = DT_LIN2OF (uptr->pos, uptr); /* line # within block */
|
||||
fprintf (st, "Block %d, line %d, ", blkno, lineno);
|
||||
if (lineno < DT_HTLIN) /* header? */
|
||||
fprintf (st, "header cell %d, nibble %d\n",
|
||||
lineno / DT_LPERMC, lineno % DT_LPERMC);
|
||||
else if (lineno < (DTU_LPERB (uptr) - DT_HTLIN)) /* data? */
|
||||
fprintf (st, "data word %d, nibble %d\n",
|
||||
(lineno - DT_HTLIN) / DT_WSIZE, (lineno - DT_HTLIN) % DT_WSIZE);
|
||||
else fprintf (st, "trailer cell %d, nibble %d\n",
|
||||
(lineno - (DTU_LPERB (uptr) - DT_HTLIN)) / DT_LPERMC,
|
||||
(lineno - (DTU_LPERB (uptr) - DT_HTLIN)) % DT_LPERMC); }
|
||||
else fprintf (st, "Forward end zone\n"); /* fwd end zone */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
143
PDP8/pdp8_tsc.c
Normal file
143
PDP8/pdp8_tsc.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/* pdp8_tsc.c: PDP-8 ETOS timesharing option board (TSC8-75)
|
||||
|
||||
Copyright (c) 2003, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK 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.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module is based on Bernhard Baehr's PDP-8/E simulator
|
||||
|
||||
PDP-8/E Simulator Source Code
|
||||
|
||||
Copyright ) 2001-2003 Bernhard Baehr
|
||||
|
||||
TSC8iots.c - IOTs for the TSC8-75 Board plugin
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
tsc TSC8-75 option board
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req;
|
||||
extern int32 SF;
|
||||
extern int32 tsc_ir; /* "ERIOT" */
|
||||
extern int32 tsc_pc; /* "ERTB" */
|
||||
extern int32 tsc_cdf; /* "ECDF" */
|
||||
extern int32 tsc_enb; /* enable */
|
||||
|
||||
#define UNIT_V_SN699 (UNIT_V_UF + 0) /* SN 699 or above */
|
||||
#define UNIT_SN699 (1 << UNIT_V_SN699)
|
||||
|
||||
DEVICE tsc_dev;
|
||||
int32 tsc (int32 IR, int32 AC);
|
||||
t_stat tsc_reset (DEVICE *dptr);
|
||||
|
||||
/* TSC data structures
|
||||
|
||||
tsc_dev TSC device descriptor
|
||||
tsc_unit TSC unit descriptor
|
||||
tsc_reg TSC register list
|
||||
*/
|
||||
|
||||
DIB tsc_dib = { DEV_TSC, 1, { &tsc } };
|
||||
|
||||
UNIT tsc_unit = { UDATA (NULL, UNIT_SN699, 0) };
|
||||
|
||||
REG tsc_reg[] = {
|
||||
{ ORDATA (IR, tsc_ir, 12) },
|
||||
{ ORDATA (PC, tsc_pc, 12) },
|
||||
{ FLDATA (CDF, tsc_cdf, 0) },
|
||||
{ FLDATA (ENB, tsc_enb, 0) },
|
||||
{ FLDATA (INT, int_req, INT_V_TSC) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tsc_mod[] = {
|
||||
{ UNIT_SN699, UNIT_SN699, "ESME", "ESME", NULL },
|
||||
{ UNIT_SN699, 0, "no ESME", "NOESME", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tsc_dev = {
|
||||
"TSC", &tsc_unit, tsc_reg, tsc_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tsc_reset,
|
||||
NULL, NULL, NULL,
|
||||
&tsc_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 tsc (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* ETDS */
|
||||
tsc_enb = 0; /* disable int req */
|
||||
int_req = int_req & ~INT_TSC; /* clear flag */
|
||||
break;
|
||||
case 1: /* ESKP */
|
||||
return (int_req & INT_TSC)? IOT_SKP + AC: AC; /* skip on int req */
|
||||
case 2: /* ECTF */
|
||||
int_req = int_req & ~INT_TSC; /* clear int req */
|
||||
break;
|
||||
case 3: /* ECDF */
|
||||
AC = AC | ((tsc_ir >> 3) & 07); /* read "ERIOT"<6:8> */
|
||||
if (tsc_cdf) AC = AC | IOT_SKP; /* if cdf, skip */
|
||||
tsc_cdf = 0;
|
||||
break;
|
||||
case 4: /* ERTB */
|
||||
return tsc_pc;
|
||||
case 5: /* ESME */
|
||||
if (tsc_unit.flags & UNIT_SN699) { /* enabled? */
|
||||
if (tsc_cdf && ((tsc_ir & 070) >> 3) == (SF & 07)) {
|
||||
AC = AC | IOT_SKP;
|
||||
tsc_cdf = 0; } }
|
||||
break;
|
||||
case 6: /* ERIOT */
|
||||
return tsc_ir;
|
||||
case 7: /* ETEN */
|
||||
tsc_enb = 1;
|
||||
break; } /* end switch */
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat tsc_reset (DEVICE *dptr)
|
||||
{
|
||||
tsc_ir = 0;
|
||||
tsc_pc = 0;
|
||||
tsc_cdf = 0;
|
||||
tsc_enb = 0;
|
||||
int_req = int_req & ~INT_TSC;
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* pdp8_tt.c: PDP-8 console terminal simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
Copyright (c) 1993-2004, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
tti,tto KL8E terminal input/output
|
||||
|
||||
29-Dec-03 RMS Added console output backpressure support
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
02-Mar-02 RMS Added SET TTI CTRL-C
|
||||
22-Dec-02 RMS Added break support
|
||||
@@ -233,13 +234,15 @@ t_stat tto_svc (UNIT *uptr)
|
||||
int32 c;
|
||||
t_stat r;
|
||||
|
||||
dev_done = dev_done | INT_TTO; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
if (tto_unit.flags & UNIT_KSR) { /* UC only? */
|
||||
c = tto_unit.buf & 0177;
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
|
||||
if ((r = sim_putchar (c)) != SCPE_OK) return r;
|
||||
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output char; error? */
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
return ((r == SCPE_STALL)? SCPE_OK: r); } /* if !stall, report */
|
||||
dev_done = dev_done | INT_TTO; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
tto_unit.pos = tto_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user