1
0
mirror of https://github.com/simh/simh.git synced 2026-02-01 06:13:34 +00:00

Notes For V3.9

The makefile now works for Linux and most Unix's. However, for Solaris
and MacOS, you must first export the OSTYPE environment variable:

> export OSTYPE
> make

Otherwise, you will get build errors.

1. New Features

1.1 3.9-0

1.1.1 SCP and libraries

	- added *nix READLINE support (Mark Pizzolato)
	- added "SHOW SHOW" and "SHOW <dev> SHOW" commands (Mark Pizzolato)
	- added support for BREAK key on Windows (Mark Pizzolato)

1.1.2 PDP-8

	- floating point processor is now enabled

2. Bugs Fixed

Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.

3. Status Report

This is the last release of SimH for which I will be sole editor. After this
release, the source is moving to a public repository:

under the general editorship of Dave Hittner and Mark Pizzolato. The status
of the individual simulators is as follows:

3.1 PDP-1

Stable and working; runs available software.

3.2 PDP-4/7/9/15

Stable and working; runs available software.

3.3 PDP-8

Stable and working; runs available software.

3.4 PDP-10 [KS-10 only]

Stable and working; runs available software.

3.5 PDP-11

Stable and working; runs available system software. The emulation of individual
models has numerous errors of detail, which prevents many diagnostics from
running correctly.

3.6 VAX-11/780

Stable and working; runs available software.

3.7 MicroVAX 3900 (VAX)

Stable and working; runs available software. Thanks to the kind generosity of
Camiel Vanderhoeven, this simulator has been verified with AXE, the VAX
architectural exerciser.

3.8 Nova

Stable and working; runs available software.

3.9 Eclipse

Stable and working, but not really supported. There is no Eclipse-specific
software available under a hobbyist license.

3.10 Interdata 16b

Stable and working, but no software for it has been found, other than
diagnostics.

3.11 Interdata 32b

Stable and working; runs 32b UNIX and diagnostics.

3.12 IBM 1401

Stable and working; runs available software.

3.13 IBM 1620

Hand debug only.  No software for it has been found or tested.

3.14 IBM 7094

Stable and working as a stock system; runs IBSYS. The CTSS extensions
have not been debugged.

3.15 IBM S/3

Stable and working, but not really supported. Runs available software.

3.16 IBM 1130

Stable and working; runs available software.  Supported and edited by
Brian Knittel.

3.17 HP 2100/1000

Stable and working; runs available software. Supported and edited by
Dave Bryan.

3.18 Honeywell 316/516

Stable and working; runs available software.

3.19 GRI-909/99

Hand debug only.  No software for it has been found or tested.

3.20 SDS-940

Hand debug only, and a few diagnostics.

3.21 LGP-30

Unfinished; hand debug only. Does not run available software, probably
due to my misunderstanding of the LGP-30 operational procedures.

3.22 Altair (original 8080 version)

Stable and working, but not really supported. Runs available software.

3.23 AltairZ80 (Z80 version)

Stable and working; runs available software. Supported and edited by
Peter Schorn.

3.24 SWTP 6800

Stable and working; runs available software. Supported and edited by
Bill Beech

3.25 Sigma 32b

Incomplete; more work is needed on the peripherals for accuracy.

3.26 Alpha

Incomplete; essentially just an EV-5 (21164) chip emulator.

4. Suggestions for Future Work

4.1 General Structure

	- Multi-threading, to allow true concurrency between SCP and the simulator
	- Graphics device support, particularly for the PDP-1 and PDP-11

4.2 Current Simulators

	- PDP-1 graphics, to run Space War
	- PDP-11 GT40 graphics, to run Lunar Lander
	- PDP-15 MUMPS-15
	- Interdata native OS debug, both 16b and 32b
	- SDS 940 timesharing operating system debug
	- IBM 7094 CTSS feature debug and operating system debug
	- IBM 1620 debug and software
	- GRI-909 software
	- Sigma 32b completion and debug
	- LGP-30 debug

4.3 Possible Future Simulators

	- Data General MV8000 (if a hobbyist license can be obtained for AOS)
	- Alpha simulator
	- HP 3000 (16b) simulator with MPE
This commit is contained in:
Mark Pizzolato
2012-03-18 09:43:12 -07:00
parent a9fd3dd518
commit 3071894c78
158 changed files with 32250 additions and 15125 deletions

Binary file not shown.

149
sigma/sigma_bugs.txt Normal file
View File

@@ -0,0 +1,149 @@
1. CPU: register pointer was being loaded from PSW1 instead of PSW2.
2. CPU: register pointer was not preserved on an XPSD 0.
3. CPU: some decode points were taking unimplemented rather than non-existent
instruction traps.
4. CPU: BDR branches on result >=0, instead of > 0.
5. CPU: PSD change instructions were not saving old PC in PC queue.
6. CPU: illegal register pointer does not stop the system on the Sigma 5-7;
instead, registers read as 0's, and writes are ignored.
7. CPU: traps were setting the Sigma 9 vector field unconditionally.
8. CPU: CH does not SEXT Rn<16:31>.
9. CPU: MTW and MTH overflow traps not implemented.
10. CPU: MTH condition code calculations not implemented correctly.
11. CPU: illegal shift opcodes on the Sigma 5-7 are treated as arithmetic
single (according to the AUTO diagnostic).
12. FP: SF did not calculate condition codes correctly.
13. FP: SF left did not detect normalized if the count reached zero.
14. FP: SF right was retaining a guard digit incorrectly.
15. FP: SF right test was not taking into account single/double precision.
16. FP: fp_unpack killed the operand sign before testing it.
17. FP: fp_pack did not recomplement a negative operand.
18. CPU: DW overflow test was incorrect.
19. IO: device status bit field was incorrectly defined.
20. IO: AIO was testing for == 0 instead of != 0.
21. TT: input keyboard character mappings were incorrect.
22. SYS: shifts were not displaying or accepting an index register.
23. CPU: mapping from pulse interrupt number to counter interrupt number
was incorrect.
24. CPU, CIS: handling of instructions aborts was incorrect.
25. CPU: CC2,4 set incorrectly on aborted stack instruction.
26. CPU: CC2,4 set incorrectly on MSP,0 instruction.
27. CPU: PLW not converting operand address to byte address.
28. CPU: PSM, PLM not converting limit operand address to byte address correctly.
29. CPU: PLM wrote registers in inverse order.
30. Definitions: number of virtual, physical pages derived incorrectly.
31. MAP: MMC control set wrap incorrect.
32. MAP: MMC register update of Rn|1 incorrect.
33. CPU: CBS set CC's incorrectly on unequal.
34. CPU: TTBS set CC's incorrectly on early exit.
35. IO: chan_proc_epilog and four other routines extracted device address incorrectly.
36. CPU: DW was fetching halfwords instead of words.
37. CPU: multiples were not setting condition codes on 0 operands.
38. FP: floating add zero test on second operand was inverted.
39. FP: floating add zero cases failed to set the result variable.
40. FP: floating add zero cases failed to go through postnormalization logic.
41. FP: double precision add macro lost high carry out.
42. FP: double precision add macro had an undocumented restriction about operands.
43. FP: all double precision instructions unpacked the wrong low order memory operand.
44. FP: normalization failed to decrement the exponent.
45. FP: in single precision, removing the guard digit created a spurious low-order digit.
46. FP: denormalization failed to clear the low word (single precision).
47. FP: denormalization failed to clear the guard digit (double precision).
48. FP: add/subtract failed to treat abnormal 0's as normal numbers.
49. CIS: WriteDecA set local rather than global condition codes.
50. CIS: Illegal digit check missed byte 0.
51. CIS: Overflow check set wrong condition codes.
52. CIS: NibbleLShift routine overflow check was (also broken in VAX, PDP11).
53. CIS: WordLShift routine overflow check was wrong (also broken in VAX, PDP11).
54. CIS: WordLShift had signed/unsigned variable conflict in compare.
55. CIS: WriteDecA not setting correct condition codes for -0.
55. CIS: WriteDECA not clearing CC3/4 before setting.
56. CIS: DM shift-and-test loop did 14 iterations instead of 15.
57. CIS: DM final shift of 16 done outside non-zero case instead of inside.
58. CIS: DD put quotient and remainder in wrong registers.
59. CIS: DD did not shift remainder to proper place, based on dividend/divisor widths.
60. CIS: DD overflow test missed exact 16 digit quotient case.
61. CIS: algorithm to compute length of operand failed for certain lengths (also broken
in VAX, PDP11).
62. CIS: DM and DD answer was wrong on restart cases. [NOT FIXED YET]
63. CIS: EBS fetched pattern from wrong address pointer.
64. CIS: EBS field separator wrote wrong byte.
65. MAP: Access codes defined incorrectly for access protection check.
66. CPU: LPSD fetching operands with write check rather than read check.
67. CPU: Illegal instruction stop (and other trap stops) weren't rolling back the PC.
68. CPU: History routine merged CC's into history array incorrectly.
69. CPU: History routine stored incremented rather than actualy PC.
70. CPU: History reporting routine printed wrong operand value, due to colliding declarations.
71. IO: Power up/down interrupts should not be implemented.
72. IO: WD was not recalculating int_hiact.
73. IO: Interrupt chain was not linked at powerup.
74. IO: Interrupt chain link algorithm was wrong.
75. IO: WD processing was spanning [beg,end) rather than [beg,end].
76. RTC: RTC interrupts were happening at the wrong level.
77. PTR: leader skip was testing for channel end.
78. PTR: leader skip was testing per command instead of per reel/file.
79. PTR: end of file was treated as fatal error instead of channel end + length error.
80. PTR, PTP: units were not marked UNIT_SEQ.
81. LPT: unit was not marked UNIT_SEQ.
82. IO: device address set/show updated/displayed wrong field in single unit devices.
83. CPU: address calculation for MTx in interrupt location used incorrect length.
84. LPT: print, format opcode definitions inverted.
85. LPT: wrong index used to count buffer fill loop.
86. IO: CPU/IOP communications through 20/21 were not modelled.
87. CIS: Multiply algorithm incorrect, multiply restart not modelled.
88. CIS: Divide algorithm incorrect, divide restart not modelled.
89. IO: WD .44 not recognized as effective NOP.
90. CPU: Sigma 5 (uniquely) does not implement CVA or CVS.
91. IO: AIO merging status incorrectly.
92. IO: system for returning status byte from IO was muddled; rewrite required.
93. RAD: 7232 track shift offset was incorrectly defined.
94. CPU: MTX for interrupts returned wrong value.
95. CPU: Counter overflow trigger equation was incorrect.
96. CPU: MTX interrupts not recalculating interrupt summary values.
97. RTC: SET/SHOW C1-C4 routines were broken.
98. DP: comparison for sector field overflow was incorrect.
99. DP: cross-cylinder incorrectly set on read to end of cylinder.
100. DP: seek never executed.
101. DP: seek followon state codes set incorrectly.
102. DP: cylinder offset defined incorrectly.
103. DP: SIO not initing unit thread properly for non-zero units.
104. MUX: Line enable must be remembered for lines that are not currently connected.
105. RAD: write check was reading words off disk instead of bytes.
106. RAD: end of transfer routine checking for address error incorrectly.
107. DK: end of transfer routine checking for address error incorrectly.
Diagnostic Notes
----------------
1. PATTERN paper tape (SA = 60, end pass = 1AC), SET CPU RBLKS=32.
Break at 60 is triggered once during loading process.
2. VERIFY paper tape (SA = 140, end pass = 8E6).
3. AUTO paper tape (SA = 105), SET CPU LASLMS to suppress spurious error message.
AUTO magtape runs correctly with no messages.
4. SUFFIX magtape (SA = 100, end pass = 115), no printouts.
5. FLOAT magtape.
6. DECIMAL paper tape (SA = EE).
7. PROTECT paper tape (SA = F9), long runtime until printout.
8. MAP paper tape (SA = 7C).
9. MEDIC paper tape (SA = 68), set SSW2 after breakpoint, long runtime.
10. INT magtape, stops after M6, set SSW2 and continue,
enters pattern generator and loops forever, as expected.
11. RTC paper tape, clocks must be 500Mhz, reports clocks as "too slow" due
to faster simulation speed.
Runs correctly with SET THROTTLE 500K.

990
sigma/sigma_cis.c Normal file
View File

@@ -0,0 +1,990 @@
/* sigma_cis.c: Sigma decimal instructions
Copyright (c) 2007-2008, 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.
Questions:
1. On the Sigma 9, in ASCII mode, is an ASCII blank used in EBS?
*/
#include "sigma_defs.h"
/* Decimal string structure */
#define DSTRLNT 4 /* words per dec string */
#define DECA 12 /* first dec accum reg */
/* Standard characters */
#define ZONE_E 0xF0 /* EBCDIC zone bits */
#define ZONE_A 0x30 /* ASCII zone bits */
#define ZONE ((PSW1 & PSW1_AS)? ZONE_A: ZONE_E)
#define PKPLUS_E 0xC /* EBCDIC preferred plus */
#define PKPLUS_A 0xA /* ASCII preferred plus */
#define PKPLUS ((PSW1 & PSW1_AS)? PKPLUS_A: PKPLUS_E)
#define BLANK_E 0x40 /* EBCDIC blank */
#define BLANK_A 0x20 /* ASCII blank */
#define BLANK ((PSW1 & PSW1_AS)? BLANK_A: BLANK_E)
/* Edit special characters */
#define ED_DS 0x20 /* digit select */
#define ED_SS 0x21 /* start significance */
#define ED_FS 0x22 /* field separator */
#define ED_SI 0x23 /* immediate significance */
/* Decimal strings run low order (word 0/R15) to high order (word 3/R12) */
typedef struct {
uint32 sign;
uint32 val[DSTRLNT];
} dstr_t;
/* Copy decimal accumulator to decimal string, no validation or sign separation */
#define ReadDecA(src) for (i = 0; i < DSTRLNT; i++) \
src.val[DSTRLNT - 1 - i] = R[DECA + i];
static dstr_t Dstr_zero = { 0, 0, 0, 0, 0 };
extern uint32 *R;
extern uint32 CC;
extern uint32 PSW1;
extern uint32 bvamqrx;
extern uint32 cpu_model;
uint32 ReadDstr (uint32 lnt, uint32 addr, dstr_t *dec);
uint32 WriteDstr (uint32 lnt, uint32 addr, dstr_t *dec);
void WriteDecA (dstr_t *dec, t_bool cln);
void SetCC2Dstr (uint32 lnt, dstr_t *dst);
uint32 TestDstrValid (dstr_t *src);
uint32 DstrInvd (void);
uint32 AddDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst, uint32 cin);
void SubDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst);
int32 CmpDstr (dstr_t *src1, dstr_t *src2);
uint32 LntDstr (dstr_t *dsrc);
uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin);
uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin);
t_bool GenLshift (dstr_t *dsrc, uint32 sc);
void GenRshift (dstr_t *dsrc, uint32 sc);
uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d);
void ed_advsrc (uint32 rn, uint32 c);
t_bool cis_test_int (dstr_t *src1, uint32 *kint);
void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint);
void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 t, uint32 *kint);
/* Decimal instructions */
uint32 cis_dec (uint32 op, uint32 lnt, uint32 bva)
{
dstr_t src1, src2, src2x, dst;
uint32 i, t, kint, ldivr, ldivd, ad, c, d, end;
int32 sc;
uint32 tr;
if (lnt == 0) /* adjust length */
lnt = 16;
CC &= ~(CC1|CC2); /* clear CC1, CC2 */
switch (op) { /* case on opcode */
case OP_DL: /* decimal load */
if ((tr = ReadDstr (lnt, bva, &dst)) != 0) /* read mem string */
return tr;
WriteDecA (&dst, FALSE); /* store result */
break;
case OP_DST: /* decimal store */
ReadDecA (dst); /* read dec accum */
if ((tr = TestDstrValid (&dst)) != 0) /* valid? */
return tr;
if ((tr = WriteDstr (lnt, bva, &dst)) != 0) /* write to mem */
return tr;
break;
case OP_DS: /* decimal subtract */
case OP_DA: /* decimal add */
ReadDecA (src1); /* read dec accum */
if ((tr = TestDstrValid (&src1)) != 0) /* valid? */
return tr;
if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */
return tr;
if (op == OP_DS) /* sub? invert sign */
src2.sign = src2.sign ^ 1;
if (src1.sign ^ src2.sign) { /* opp signs? sub */
if (CmpDstr (&src1, &src2) < 0) { /* src1 < src2? */
SubDstr (&src1, &src2, &dst); /* src2 - src1 */
dst.sign = src2.sign; /* sign = src2 */
}
else {
SubDstr (&src2, &src1, &dst); /* src1 - src2 */
dst.sign = src1.sign; /* sign = src1 */
}
}
else { /* addition */
if (AddDstr (&src1, &src2, &dst, 0)) { /* add, overflow? */
CC |= CC2; /* set CC2 */
return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */
}
dst.sign = src1.sign; /* set result sign */
}
WriteDecA (&dst, TRUE); /* store result */
break;
case OP_DC: /* decimal compare */
ReadDecA ( src1); /* read dec accum */
if ((tr = TestDstrValid (&src1)) != 0) /* valid? */
return tr;
if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */
return tr;
LntDstr (&src1); /* clean -0 */
LntDstr (&src2);
if (src1.sign ^ src2.sign) /* signs differ? */
CC = src1.sign? CC4: CC3; /* set < or > */
else { /* same signs */
t = CmpDstr (&src1, &src2); /* compare strings */
if (t < 0)
CC = (src1.sign? CC3: CC4);
else if (t > 0)
CC = (src1.sign? CC4: CC3);
else CC = 0;
}
break;
/* Decimal multiply - algorithm from George Plue.
The Sigma does decimal multiply one digit at a time, using the multiplicand
and a doubled copy of the multiplicand. Multiplying by digits 1-5 is
synthesized by 1-3 adds; multiplying by digits 6-9 is synthesized by 1-2
subtractions, and adding 1 to the next multiplier digit. (That is,
multiplying by 7 is done by multiplying by "10 - 3".) This requires at
most one extra add to fixup the last digit, and minimizes the overall
number of adds (average 1.5 adds per multiplier digit). Note that
multiplication proceeds from right to left.
The Sigma 5-9 allowed decimal multiply to be interrupted; the 5X0 series
did not. An interrupted multiply uses a sign digit in R12 and R13 as the
divider between the remaining multiplier (to the left of the sign, and
in the low-order digit of R15) and the partial product (to the right of
the sign). Because the partial product may be negative, leading 0x99's
may have been stripped and need to be restored.
The real Sigma's probably didn't run a validty test after separation of
the partial product and multiplier, but it doesn't hurt, and prevents
certain corner cases from causing errors. */
case OP_DM: /* decimal multiply */
if (lnt >= 9) /* invalid length? */
return DstrInvd ();
ReadDecA (src1); /* get dec accum */
if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */
return tr;
dst = Dstr_zero; /* clear result */
kint = 0; /* assume no int */
if (!QCPU_5X0 && /* S5-9? */
(cis_test_int (&src1, &kint))) /* interrupted? */
cis_dm_int (&src1, &dst, kint); /* restore */
else if ((tr = TestDstrValid (&src1)) != 0) /* mpyr valid? */
return tr;
if (LntDstr (&src1) && LntDstr (&src2)) { /* both opnds != 0? */
dst.sign = src1.sign ^ src2.sign; /* sign of result */
AddDstr (&src2, &src2, &src2x, 0); /* get 2*mplcnd */
for (i = 1; i <= 16; i++) { /* 16 iterations */
if (i >= kint) { /* past int point? */
NibbleRshift (&src1, 1, 0); /* mpyr right 4 */
d = src1.val[0] & 0xF; /* get digit */
switch (d) { /* case */
case 5: /* + 2 + 2 + 1 */
AddDstr (&src2x, &dst, &dst, 0);
case 3: /* + 2 + 1 */
AddDstr (&src2x, &dst, &dst, 0);
case 1: /* + 1 */
AddDstr (&src2, &dst, &dst, 0);
case 0:
break;
case 4: /* + 2 + 2 */
AddDstr (&src2x, &dst, &dst, 0);
case 2: /* + 2 */
AddDstr (&src2x, &dst, &dst, 0);
break;
case 6: /* - 2 - 2 + 10 */
SubDstr (&src2x, &dst, &dst);
case 8: /* - 2 + 10 */
SubDstr (&src2x, &dst, &dst);
src1.val[0] += 0x10; /* + 10 */
break;
case 7: /* -2 - 1 + 10 */
SubDstr (&src2x, &dst, &dst);
case 9: /* -1 + 10 */
SubDstr (&src2, &dst, &dst);
default: /* + 10 */
src1.val[0] += 0x10;
} /* end switch */
} /* end if >= kint */
NibbleLshift (&src2, 1, 0); /* shift mplcnds */
NibbleLshift (&src2x, 1, 0);
} /* end for */
} /* end if != 0 */
WriteDecA (&dst, TRUE); /* store result */
break;
/* Decimal divide overflow calculation - if the dividend has true length d,
and the divisor true length r, then the quotient will have (d - r) or
(d - r + 1) digits. Therefore, if (d - r) > 15, the quotient will not
fit. However, if (d - r) == 15, it may or may not fit, depending on
whether the first subtract succeeds. Therefore, it's necessary to test
after the divide to see if the quotient has one extra digit. */
case OP_DD: /* decimal divide */
if (lnt >= 9) /* invalid length? */
return DstrInvd ();
ReadDecA (src1); /* read dec accum */
if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */
return tr;
dst = Dstr_zero; /* clear result */
kint = 0; /* no interrupt */
if (!QCPU_5X0 && /* S5-9? */
(cis_test_int (&src1, &t))) { /* interrupted? */
cis_dd_int (&src1, &dst, t, &kint); /* restore */
t = t - 1;
}
else { /* normal start? */
if ((tr = TestDstrValid (&src1)) != 0) /* divd valid? */
return tr;
ldivr = LntDstr (&src2); /* divr lnt */
ldivd = LntDstr (&src1); /* divd lnt */
if ((ldivr == 0) || /* div by zero? */
(ldivd > (ldivr + 15))) { /* quo too big? */
CC |= CC2; /* divide check */
return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */
}
if (CmpDstr (&src1, &src2) < 0) { /* no divide? */
R[12] = src1.val[1]; /* remainder */
R[13] = src1.val[0] | (PKPLUS + src1.sign);
R[14] = 0; /* quotient */
R[15] = PKPLUS;
CC = 0;
return SCPE_OK;
}
t = ldivd - ldivr;
}
dst.sign = src1.sign ^ src2.sign; /* calculate sign */
GenLshift (&src2, t); /* align */
for (i = 0; i <= t; i++) { /* divide loop */
for (d = kint; /* find digit */
(d < 10) && (CmpDstr (&src1, &src2) >= 0);
d++)
SubDstr (&src2, &src1, &src1);
dst.val[0] = (dst.val[0] & ~0xF) | d; /* insert quo dig */
NibbleLshift (&dst, 1, 0); /* shift quotient */
NibbleRshift (&src2, 1, 0); /* shift divisor */
kint = 0; /* no more int */
} /* end divide loop */
if (dst.val[2]) { /* quotient too big? */
CC |= CC2; /* divide check */
return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */
}
CC = dst.sign? CC4: CC3; /* set CC's */
R[12] = src1.val[1]; /* remainder */
R[13] = src1.val[0] | (PKPLUS + src1.sign);
R[14] = dst.val[1]; /* quotient */
R[15] = dst.val[0] | (PKPLUS + dst.sign);
break;
case OP_DSA: /* decimal shift */
ReadDecA (dst); /* read dec accum */
if ((tr = TestDstrValid (&dst)) != 0) /* valid? */
return tr;
CC = 0; /* clear CC's */
sc = SEXT_H_W (bva >> 2); /* shift count */
if (sc > 31) /* sc in [-31,31] */
sc = 31;
if (sc < -31)
sc = -31;
if (sc < 0) { /* right shift? */
sc = -sc; /* |shift| */
GenRshift (&dst, sc); /* do shift */
dst.val[0] = dst.val[0] & ~0xF; /* clear sign */
} /* end right shift */
else if (sc) { /* left shift? */
if (GenLshift (&dst, sc)) /* do shift */
CC |= CC2;
} /* end left shift */
WriteDecA (&dst, FALSE); /* store result */
break;
case OP_PACK: /* zoned to packed */
dst = Dstr_zero; /* clear result */
end = (2 * lnt) - 1; /* zoned length */
for (i = 1; i <= end; i++) { /* loop thru char */
ad = (bva + end - i) & bvamqrx; /* zoned character */
if ((tr = ReadB (ad, &c, VR)) != 0) /* read char */
return tr;
if (i == 1) { /* sign + digit? */
uint32 s;
s = (c >> 4) & 0xF; /* get sign */
if (s < 0xA)
return DstrInvd ();
if ((s == 0xB) || (s == 0xD)) /* negative */
dst.sign = 1;
}
d = c & 0xF; /* get digit */
if (d > 0x9)
return DstrInvd ();
dst.val[i / 8] = dst.val[i / 8] | (d << ((i % 8) * 4));
}
WriteDecA (&dst, FALSE); /* write result */
break;
case OP_UNPK: /* packed to zoned */
ReadDecA (dst); /* read dec accum */
if ((tr = TestDstrValid (&dst)) != 0) /* valid? */
return tr;
end = (2 * lnt) - 1; /* zoned length */
if ((tr = ReadB (bva, &c, VW)) != 0) /* prove writeable */
return tr;
for (i = 1; i <= end; i++) { /* loop thru chars */
c = (dst.val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */
if (i == 1) /* first? */
c |= ((PKPLUS + dst.sign) << 4); /* or in sign */
else c |= ZONE; /* no, or in zone */
ad = (bva + end - i) & bvamqrx;
if ((tr = WriteB (ad, c, VW)) != 0) /* write to memory */
return tr;
}
SetCC2Dstr (lnt, &dst); /* see if too long */
break;
}
return 0;
}
/* Test for interrupted multiply or divide */
t_bool cis_test_int (dstr_t *src, uint32 *kint)
{
int32 i;
uint32 wd, sc, d;
for (i = 15; i >= 1; i--) { /* test 15 nibbles */
wd = (DSTRLNT/2) + (i / 8);
sc = (i % 8) * 4;
d = (src->val[wd] >> sc) & 0xF;
if (d >= 0xA) {
*kint = (uint32) i;
return TRUE;
}
}
return FALSE;
}
/* Resume interrupted multiply
The sign that was found is the "fence" between the the remaining multiplier
and the partial product:
R val
+--+--+--+--+--+--+--+--+
| mpyer |sn|pp| 12 3
+--+--+--+--+--+--+--+--+
| partial product | 13 2
+--+--+--+--+--+--+--+--+
| partial product | 14 1
+--+--+--+--+--+--+--+--+
| partial product |mp| 15 0
+--+--+--+--+--+--+--+--+
This routine separates the multiplier and partial product, returns the
multiplier as a valid decimal string in src, and the partial product
as a value with no sign in dst */
void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint)
{
uint32 ppneg, wd, sc, d, curd;
int32 k;
*dst = *src; /* copy input */
wd = (DSTRLNT/2) + (kint / 8);
sc = (kint % 8) * 4;
d = (src->val[wd] >> sc) & 0xF; /* get sign fence */
ppneg = ((d >> 2) & 1) ^ 1; /* partial prod neg? */
curd = (src->val[0] & 0xF) + ppneg; /* bias cur digit */
src->val[wd] = (src->val[wd] & ~(0xF << sc)) | /* replace sign */
(curd << sc); /* with digit */
GenRshift (src, kint + 15); /* right justify */
src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set mpyr sign */
src->val[0] = src->val[0] & ~0xF; /* clear sign pos */
/* Mask out multiplier */
for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */
dst->val[k] &= ~(0xFFFFFFFFu <<
((k > (int32) wd)? 0: sc));
/* Recreate missing high order digits for negative partial product */
if (ppneg) { /* negative? */
for (k = (DSTRLNT * 4) - 1; k != 0; k--) { /* bytes hi to lo */
wd = k / 4;
sc = (k % 4) * 8;
if (((dst->val[wd] >> sc) & 0xFF) != 0)
break;
dst->val[wd] |= (0x99 << sc); /* repl 00 with 99 */
} /* end for */
}
dst->val[0] &= ~0xF; /* clear pp sign */
return;
}
/* Resume interrupted divide
The sign that was found is the "fence" between the the quotient and the
remaining dividend product:
R val
+--+--+--+--+--+--+--+--+
| quotient |sn|dv| 12 3
+--+--+--+--+--+--+--+--+
| dividend | 13 2
+--+--+--+--+--+--+--+--+
| dividend | 14 1
+--+--+--+--+--+--+--+--+
| dividend |qu| 15 0
+--+--+--+--+--+--+--+--+
This routine separates the quotient and the remaining dividend, returns
the dividend as a valid decimal string, the quotient as a decimal string
without sign, and kint is the partial value of the last quotient digit. */
void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 nib, uint32 *kint)
{
uint32 wd, sc, d, curd;
int32 k;
wd = (DSTRLNT/2) + (nib / 8);
sc = (nib % 8) * 4;
curd = src->val[0] & 0xF; /* last quo digit */
*dst = *src; /* copy input */
GenRshift (dst, nib + 16); /* right justify quo */
d = dst->val[0] & 0xF; /* get sign fence */
dst->val[0] = (dst->val[0] & ~0xF) | curd; /* repl with digit */
*kint = curd;
/* Mask out quotient */
for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */
src->val[k] &= ~(0xFFFFFFFFu <<
((k > (int32) wd)? 0: sc));
src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set divd sign */
src->val[0] = src->val[0] & ~0xF; /* clr sign digit */
return;
}
/* Get packed decimal string from memory
Arguments:
lnt = decimal string length
adr = decimal string address
src = decimal string structure
Output:
trap or abort signal
Per the Sigma spec, bad digits or signs cause a fault or abort */
uint32 ReadDstr (uint32 lnt, uint32 adr, dstr_t *src)
{
uint32 i, c, bva;
uint32 tr;
*src = Dstr_zero; /* clear result */
for (i = 0; i < lnt; i++) { /* loop thru string */
bva = (adr + lnt - i - 1) & bvamqrx; /* from low to high */
if ((tr = ReadB (bva, &c, VR)) != 0) /* read byte */
return tr;
src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8));
} /* end for */
return TestDstrValid (src);
}
/* Separate sign, validate sign and digits of decimal string */
uint32 TestDstrValid (dstr_t *src)
{
uint32 i, j, s, t;
s = src->val[0] & 0xF; /* get sign */
if (s < 0xA) /* valid? */
return DstrInvd ();
if ((s == 0xB) || (s == 0xD)) /* negative? */
src->sign = 1;
else src->sign = 0;
src->val[0] &= ~0xF; /* clear sign */
for (i = 0; i < DSTRLNT; i++) { /* check 4 words */
for (j = 0; j < 8; j++) { /* 8 digit/word */
t = (src->val[i] >> (28 - (j * 4))) & 0xF; /* get digit */
if (t > 0x9) /* invalid digit? */
return DstrInvd (); /* exception */
}
}
return 0;
}
/* Invalid digit or sign: set CC1, trap or abort instruction */
uint32 DstrInvd (void)
{
CC |= CC1; /* set CC1 */
if (PSW1 & PSW1_DM) /* if enabled, trap */
return TR_DEC;
return WSIGN; /* otherwise, abort */
}
/* Store decimal string
Arguments:
lnt = decimal string length
adr = decimal string address
dst = decimal string structure
Returns memory management traps (if any)
Bad digits and invalid sign are impossible
*/
uint32 WriteDstr (uint32 lnt, uint32 adr, dstr_t *dst)
{
uint32 i, bva, c;
uint32 tr;
dst->val[0] = dst->val[0] | (PKPLUS + dst->sign); /* set sign */
if ((tr = ReadB (adr, &c, VW)) != 0) /* prove writeable */
return tr;
for (i = 0; i < lnt; i++) { /* loop thru bytes */
c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF; /* from low to high */
bva = (adr + lnt - i - 1) & bvamqrx;
if ((tr = WriteB (bva, c, VW)) != 0) /* store byte */
return tr;
} /* end for */
SetCC2Dstr (lnt, dst); /* check overflow */
return 0;
}
/* Store result in decimal accumulator
Arguments:
dst = decimal string structure
cln = clean -0 if true
Sets condition codes CC3 and CC4
Bad digits and invalid sign are impossible */
void WriteDecA (dstr_t *dst, t_bool cln)
{
uint32 i, nz;
CC &= ~(CC3|CC4); /* assume zero */
for (i = 0, nz = 0; i < DSTRLNT; i++) { /* save 32 digits */
R[DECA + i] = dst->val[DSTRLNT - 1 - i];
nz |= dst->val[DSTRLNT - 1 - i];
}
if (nz) /* non-zero? */
CC |= (dst->sign)? CC4: CC3; /* set CC3 or CC4 */
else if (cln) /* zero, clean? */
dst->sign = 0; /* clear sign */
R[DECA + DSTRLNT - 1] |= (PKPLUS + dst->sign); /* or in sign */
return;
}
/* Set CC2 for decimal string store
Arguments:
lnt = string length
dst = decimal string structure
Output:
sets CC2 if information won't fit */
void SetCC2Dstr (uint32 lnt, dstr_t *dst)
{
uint32 i, limit, mask;
static uint32 masktab[8] = {
0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,
0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000
};
lnt = (lnt * 2) - 1; /* number of digits */
mask = 0; /* can't ovflo */
limit = lnt / 8; /* limit for test */
for (i = 0; i < DSTRLNT; i++) { /* loop thru value */
if (i == limit) /* @limit, get mask */
mask = masktab[lnt % 8];
else if (i > limit) /* >limit, test all */
mask = 0xFFFFFFFF;
if (dst->val[i] & mask) /* test for ovflo */
CC |= CC2;
}
return;
}
/* Add decimal string magnitudes
Arguments:
s1 = src1 decimal string
s2 = src2 decimal string
ds = dest decimal string
cy = carry in
Output:
1 if carry, 0 if no carry
This algorithm courtesy Anton Chernoff, circa 1992 or even earlier.
We trace the history of a pair of adjacent digits to see how the
carry is fixed; each parenthesized item is a 4b digit.
Assume we are adding:
(a)(b) I
+ (x)(y) J
First compute I^J:
(a^x)(b^y) TMP
Note that the low bit of each digit is the same as the low bit of
the sum of the digits, ignoring the carry, since the low bit of the
sum is the xor of the bits.
Now compute I+J+66 to get decimal addition with carry forced left
one digit:
(a+x+6+carry mod 16)(b+y+6 mod 16) SUM
Note that if there was a carry from b+y+6, then the low bit of the
left digit is different from the expected low bit from the xor.
If we xor this SUM into TMP, then the low bit of each digit is 1
if there was a carry, and 0 if not. We need to subtract 6 from each
digit that did not have a carry, so take ~(SUM ^ TMP) & 0x11, shift
it right 4 to the digits that are affected, and subtract 6*adjustment
(actually, shift it right 3 and subtract 3*adjustment).
*/
uint32 AddDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds, uint32 cy)
{
uint32 i;
uint32 sm1, sm2, tm1, tm2, tm3, tm4;
for (i = 0; i < DSTRLNT; i++) { /* loop low to high */
tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */
sm1 = s1->val[i] + (s2->val[i] + cy); /* sum operands */
sm2 = sm1 + 0x66666666; /* force carry out */
cy = ((sm1 < s1->val[i]) || (sm2 < sm1)); /* check for ovflo */
tm2 = tm1 ^ sm2; /* get carry flags */
tm3 = (tm2 >> 3) | (cy << 29); /* compute adjust */
tm4 = 0x22222222 & ~tm3; /* clrr where carry */
ds->val[i] = (sm2 - (3 * tm4)) & WMASK; /* final result */
}
return cy;
}
/* Subtract decimal string magnitudes
Arguments:
s1 = src1 decimal string
s2 = src2 decimal string
ds = dest decimal string
Note: the routine assumes that s1 <= s2
*/
void SubDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds)
{
uint32 i;
dstr_t compl;
for (i = 0; i < DSTRLNT; i++) /* 9's comp s2 */
compl.val[i] = 0x99999999 - s1->val[i];
AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */
return;
}
/* Compare decimal string magnitudes
Arguments:
s1 = src1 decimal string
s2 = src2 decimal string
Output:
1 if >, 0 if =, -1 if <
*/
int32 CmpDstr (dstr_t *s1, dstr_t *s2)
{
int32 i;
for (i = DSTRLNT - 1; i >=0; i--) {
if (s1->val[i] > s2->val[i])
return 1;
if (s1->val[i] < s2->val[i])
return -1;
}
return 0;
}
/* Get exact length of decimal string, clean -0
Arguments:
dst = decimal string structure
Output:
number of non-zero digits
*/
uint32 LntDstr (dstr_t *dst)
{
int32 nz, i;
for (nz = DSTRLNT - 1; nz >= 0; nz--) {
if (dst->val[nz]) {
for (i = 7; i >= 0; i--) {
if ((dst->val[nz] >> (i * 4)) & 0xF)
return (nz * 8) + i;
}
}
}
dst->sign = 0;
return 0;
}
/* Word shift right
Arguments:
dsrc = decimal string structure
sc = shift count in nibbles
*/
void GenRshift (dstr_t *dsrc, uint32 cnt)
{
uint32 i, sc, sc1;
sc = cnt / 8;
sc1 = cnt % 8;
if (sc) {
for (i = 0; i < DSTRLNT; i++) {
if ((i + sc) < DSTRLNT)
dsrc->val[i] = dsrc->val[i + sc];
else dsrc->val[i] = 0;
}
}
if (sc1)
NibbleRshift (dsrc, sc1, 0);
return;
}
/* General shift left
Arguments:
dsrc = decimal string structure
cnt = shift count in nibbles
*/
t_bool GenLshift (dstr_t *dsrc, uint32 cnt)
{
t_bool i, c, sc, sc1;
c = 0;
sc = cnt / 8;
sc1 = cnt % 8;
if (sc) {
for (i = DSTRLNT - 1; (int32) i >= 0; i--) {
if (i >= sc)
dsrc->val[i] = dsrc->val[i - sc];
else {
c |= dsrc->val[i];
dsrc->val[i] = 0;
}
}
}
if (sc1)
c |= NibbleLshift (dsrc, sc1, 0);
return (c? TRUE: FALSE);
}
/* Nibble shift right
Arguments:
dsrc = decimal string structure
sc = shift count in nibbles
cin = carry in
*/
uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin)
{
int32 i;
uint32 s, nc;
if (s = sc * 4) {
for (i = DSTRLNT - 1; (int32) i >= 0; i--) {
nc = (dsrc->val[i] << (32 - s)) & WMASK;
dsrc->val[i] = ((dsrc->val[i] >> s) |
cin) & WMASK;
cin = nc;
}
return cin;
}
return 0;
}
/* Nibble shift left
Arguments:
dsrc = decimal string structure
sc = shift count in nibbles
cin = carry in
*/
uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin)
{
uint32 i, s, nc;
if (s = sc * 4) {
for (i = 0; i < DSTRLNT; i++) {
nc = dsrc->val[i] >> (32 - s);
dsrc->val[i] = ((dsrc->val[i] << s) |
cin) & WMASK;
cin = nc;
}
return cin;
}
return 0;
}
/* Edit instruction */
uint32 cis_ebs (uint32 rn, uint32 disp)
{
uint32 sa, da, c, d, dst, fill, pat;
uint32 tr;
disp = SEXT_LIT_W (disp) & WMASK; /* sext operand */
fill = S_GETMCNT (R[rn]); /* fill char */
while (S_GETMCNT (R[rn|1])) { /* while pattern */
sa = (disp + R[rn]) & bvamqrx; /* dec str addr */
da = R[rn|1] & bvamqrx; /* pattern addr */
if ((tr = ReadB (da, &pat, VR)) != 0) /* get pattern byte */
return tr;
switch (pat) { /* case on pattern */
case ED_DS: /* digit select */
if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */
return tr;
if (CC & CC4) /* signif? unpack */
dst = ZONE | d;
else if (d) { /* non-zero? */
R[1] = da; /* save addr */
dst = ZONE | d; /* unpack */
CC |= CC4; /* set signif */
}
else dst = fill; /* otherwise fill */
if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */
return tr;
ed_advsrc (rn, c); /* next src digit */
break;
case ED_SS: /* signif start */
if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */
return tr;
if (CC & CC4) /* signif? unpack */
dst = ZONE | d;
else if (d) { /* non-zero? */
R[1] = da; /* save addr */
dst = ZONE | d; /* unpack */
}
else { /* otherwise */
R[1] = da + 1; /* save next */
dst = fill; /* fill */
}
CC |= CC4; /* set signif */
if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */
return tr;
ed_advsrc (rn, c); /* next src digit */
break;
case ED_SI: /* signif immediate */
if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */
return tr;
R[1] = da; /* save addr */
dst = ZONE | d; /* unpack */
CC |= CC4; /* set signif */
if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */
return tr;
ed_advsrc (rn, c); /* next src digit */
break;
case ED_FS: /* field separator */
CC &= ~(CC1|CC3|CC4); /* clr all exc CC2 */
if ((tr = WriteB (da, fill, VW)) != 0) /* overwrite dst */
return tr;
break;
default: /* all others */
if ((CC & CC4) == 0) { /* signif off? */
dst = (CC & CC1)? BLANK: fill; /* blank or fill */
if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */
return tr;
}
break;
} /* end switch dst */
R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* next pattern */
} /* end while */
return 0;
}
/* Routine to get and validate the next source digit */
uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d)
{
uint32 tr;
if ((tr = ReadB (sa, c, VR)) != 0) /* read source byte */
return tr;
*d = ((CC & CC2)? *c: *c >> 4) & 0xF; /* isolate digit */
if (*d > 0x9) /* invalid? */
return TR_DEC;
if (*d) /* non-zero? */
CC |= CC3;
return 0;
}
/* Routine to advance source string */
void ed_advsrc (uint32 rn, uint32 c)
{
c = c & 0xF; /* get low digit */
if (((CC & CC2) == 0) && (c > 0x9)) { /* sel left, with sign? */
if ((c == 0xB) || (c == 0xD)) /* minus? */
CC = CC | (CC1|CC4); /* CC1, CC4 */
else CC = (CC | CC1) & ~CC4; /* no, CC1, ~CC4 */
R[rn] = R[rn] + 1; /* skip two digits */
}
else { /* adv 1 digit */
if (CC & CC2)
R[rn] = R[rn] + 1;
CC = CC ^ CC2;
}
return;
}

620
sigma/sigma_coc.c Normal file
View File

@@ -0,0 +1,620 @@
/* sigma_coc.c: Sigma character-oriented communications subsystem simulator
Copyright (c) 2007-2008, 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 substanXIAl 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.
coc 7611 communications multiplexor
*/
#include "sigma_io_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>
/* Constants */
#define MUX_LINES 64 /* max lines */
#define MUX_LINES_DFLT 8 /* default lines */
#define MUX_INIT_POLL 8000
#define MUXL_WAIT 500
#define MUX_NUMLIN mux_desc.lines /* curr # lines */
#define MUXC 0 /* channel thread */
#define MUXI 1 /* input thread */
/* Line status */
#define MUXL_XIA 0x01 /* xmt intr armed */
#define MUXL_XIR 0x02 /* xmt intr req */
#define MUXL_REP 0x04 /* rcv enable pend */
#define MUXL_RBP 0x10 /* rcv break pend */
/* Channel state */
#define MUXC_IDLE 0 /* idle */
#define MUXC_INIT 1 /* init */
#define MUXC_RCV 2 /* receive */
#define MUXC_END 3 /* end */
/* DIO address */
#define MUXDIO_V_FNC 0 /* function */
#define MUXDIO_M_FNC 0xF
#define MUXDIO_V_COC 4 /* ctlr num */
#define MUXDIO_M_COC 0xF
#define MUXDIO_GETFNC(x) (((x) >> MUXDIO_V_FNC) & MUXDIO_M_FNC)
#define MUXDIO_GETCOC(x) (((x) >> MUXDIO_V_COC) & MUXDIO_M_COC)
#define MUXDAT_V_LIN 0 /* line num */
#define MUXDAT_M_LIN (MUX_LINES - 1)
#define MUXDAT_V_CHR 8 /* output char */
#define MUXDAT_M_CHR 0xFF
#define MUXDAT_GETLIN(x) (((x) >> MUXDAT_V_LIN) & MUXDAT_M_LIN)
#define MUXDAT_GETCHR(x) (((x) >> MUXDAT_V_CHR) & MUXDAT_M_CHR)
uint8 mux_rbuf[MUX_LINES]; /* rcv buf */
uint8 mux_xbuf[MUX_LINES]; /* xmt buf */
uint8 mux_sta[MUX_LINES]; /* status */
uint32 mux_tps = RTC_HZ_50; /* polls/second */
uint32 mux_scan = 0; /* scanner */
uint32 mux_slck = 0; /* scanner locked */
uint32 muxc_cmd = MUXC_IDLE; /* channel state */
uint32 mux_rint = INTV (INTG_E2, 0);
uint32 mux_xint = INTV (INTG_E2, 1);
TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descrs */
TMXR mux_desc = { MUX_LINES_DFLT, 0, 0, mux_ldsc }; /* mux descrr */
extern uint32 chan_ctl_time;
extern uint32 CC;
extern uint32 *R;
uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 mux_dio (uint32 op, uint32 rn, uint32 ad);
uint32 mux_tio_status (void);
t_stat mux_chan_err (uint32 st);
t_stat muxc_svc (UNIT *uptr);
t_stat muxo_svc (UNIT *uptr);
t_stat muxi_rtc_svc (UNIT *uptr);
t_stat mux_reset (DEVICE *dptr);
t_stat mux_attach (UNIT *uptr, char *cptr);
t_stat mux_detach (UNIT *uptr);
t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
void mux_reset_ln (int32 ln);
void mux_scan_next (t_bool clr);
t_stat muxi_put_char (uint32 c, uint32 ln);
/* MUX data structures
mux_dev MUX device descriptor
mux_unit MUX unit descriptor
mux_reg MUX register list
mux_mod MUX modifiers list
*/
dib_t mux_dib = { DVA_MUX, &mux_disp, DIO_MUX, &mux_dio };
UNIT mux_unit[] = {
{ UDATA (&muxc_svc, UNIT_ATTABLE, 0) },
{ UDATA (&muxi_rtc_svc, UNIT_DIS, 0) }
};
REG mux_reg[] = {
{ BRDATA (STA, mux_sta, 16, 8, MUX_LINES) },
{ BRDATA (RBUF, mux_rbuf, 16, 8, MUX_LINES) },
{ BRDATA (XBUF, mux_xbuf, 16, 8, MUX_LINES) },
{ DRDATA (SCAN, mux_scan, 6) },
{ FLDATA (SLCK, mux_slck, 0) },
{ DRDATA (CMD, muxc_cmd, 2) },
{ DRDATA (TPS, mux_tps, 8), REG_HRO },
{ NULL }
};
MTAB mux_mod[] = {
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &mux_desc },
{ UNIT_ATT, UNIT_ATT, "summary", NULL,
NULL, &tmxr_show_summ, (void *) &mux_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &tmxr_show_cstat, (void *) &mux_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tmxr_show_cstat, (void *) &mux_desc },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",
&mux_vlines, &tmxr_show_lines, (void *) &mux_desc },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_COC, "POLL", "POLL",
&rtc_set_tps, &rtc_show_tps, (void *) &mux_tps },
{ 0 }
};
DEVICE mux_dev = {
"MUX", mux_unit, mux_reg, mux_mod,
2, 10, 31, 1, 16, 8,
&tmxr_ex, &tmxr_dep, &mux_reset,
NULL, &mux_attach, &mux_detach,
&mux_dib, DEV_NET | DEV_DISABLE
};
/* MUXL data structures
muxl_dev MUXL device descriptor
muxl_unit MUXL unit descriptor
muxl_reg MUXL register list
muxl_mod MUXL modifiers list
*/
UNIT muxl_unit[] = {
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }
};
MTAB muxl_mod[] = {
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &mux_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &mux_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &mux_desc },
{ 0 }
};
REG muxl_reg[] = {
{ URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,
MUX_LINES, REG_NZ + PV_LEFT) },
{ NULL }
};
DEVICE muxl_dev = {
"MUXL", muxl_unit, muxl_reg, muxl_mod,
MUX_LINES, 10, 31, 1, 8, 8,
NULL, NULL, &mux_reset,
NULL, NULL, NULL,
NULL, 0
};
/* MUX: IO dispatch routine */
uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst)
{
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = mux_tio_status (); /* get status */
if ((*dvst & DVS_CST) == 0) { /* ctrl idle? */
muxc_cmd = MUXC_INIT; /* start dev thread */
sim_activate (&mux_unit[MUXC], chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = mux_tio_status (); /* return status */
break;
case OP_TDV: /* test status */
*dvst = 0; /* no status */
break;
case OP_HIO: /* halt I/O */
*dvst = mux_tio_status (); /* get status */
muxc_cmd = MUXC_IDLE; /* stop dev thread */
sim_cancel (&mux_unit[MUXC]);
io_sclr_req (mux_rint, 0); /* clr rcv int */
io_sclr_req (mux_xint, 0);
break;
case OP_AIO: /* acknowledge int */
*dvst = 0; /* no status */
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* MUX: DIO dispatch routine */
uint32 mux_dio (uint32 op, uint32 rn, uint32 ad)
{
int32 ln;
uint32 fnc = MUXDIO_GETFNC (ad);
uint32 coc = MUXDIO_GETCOC (ad);
if (op == OP_RD) { /* read direct */
if (coc != 0) /* nx COC? */
return 0;
R[rn] = mux_scan | 0x40; /* return line num */
mux_sta[mux_scan] &= ~MUXL_XIR; /* clear int req */
return 0;
}
ln = MUXDAT_GETLIN (R[rn]); /* get line num */
if (fnc & 0x4) { /* transmit */
if ((coc != 0) || /* nx COC or */
(ln >= MUX_NUMLIN)) { /* nx line? */
CC |= CC4;
return 0;
}
if ((fnc & 0x7) == 0x5) { /* send char? */
if (fnc & 0x8) /* space? */
mux_xbuf[ln] = 0;
else mux_xbuf[ln] = MUXDAT_GETCHR (R[rn]); /* no, get char */
sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
mux_sta[ln] = (mux_sta[ln] | MUXL_XIA) & ~MUXL_XIR;
mux_scan_next (1); /* unlock scanner */
}
else if (fnc == 0x06) { /* stop transmit */
mux_sta[ln] &= ~MUXL_XIA|MUXL_XIR; /* disable int */
mux_scan_next (1); /* unlock scanner */
}
else if (fnc == 0x07) { /* disconnect */
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
mux_reset_ln (ln); /* reset state */
}
CC = (sim_is_active (&muxl_unit[ln])? 0: CC4) |
(mux_ldsc[ln].conn? CC3: 0);
}
else { /* receive */
if ((coc != 0) || /* nx COC or */
(ln >= MUX_NUMLIN)) /* nx line */
return 0;
if (fnc == 0x01) { /* set rcv enable */
if (mux_ldsc[ln].conn) /* connected? */
mux_ldsc[ln].rcve = 1; /* just enable */
else mux_sta[ln] |= MUXL_REP; /* enable pending */
}
else if (fnc == 0x02) { /* clr rcv enable */
mux_ldsc[ln].rcve = 0;
mux_sta[ln] &= ~MUXL_REP;
}
else if (fnc == 0x03) { /* disconnect */
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
mux_reset_ln (ln); /* reset state */
}
if (mux_sta[ln] & MUXL_RBP) /* break pending? */
CC = CC3|CC4;
else CC = mux_ldsc[ln].rcve? CC4: CC3;
}
return 0;
}
/* Unit service - channel overhead */
t_stat muxc_svc (UNIT *uptr)
{
uint32 st;
uint32 cmd;
if (muxc_cmd == MUXC_INIT) { /* init state? */
st = chan_get_cmd (mux_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
mux_chan_err (st); /* go idle */
else muxc_cmd = MUXC_RCV; /* no, receive */
}
else if (muxc_cmd == MUXC_END) { /* end state? */
st = chan_end (mux_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
mux_chan_err (st); /* go idle */
else if (st == CHS_CCH) { /* command chain? */
muxc_cmd = MUXC_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time); /* schedule soon */
}
else muxc_cmd = MUXC_IDLE; /* else idle */
}
return SCPE_OK;
}
/* Unit service - polled input - called from rtc scheduler
Poll for new connections
Poll all connected lines for input
*/
t_stat muxi_rtc_svc (UNIT *uptr)
{
t_stat r;
int32 newln, ln, c;
if ((mux_unit[MUXC].flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
newln = tmxr_poll_conn (&mux_desc); /* look for connect */
if ((newln >= 0) && (mux_sta[newln] & MUXL_REP)) { /* rcv enb pending? */
mux_ldsc[newln].rcve = 1; /* enable rcv */
mux_sta[newln] &= ~MUXL_REP; /* clr pending */
}
tmxr_poll_rx (&mux_desc); /* poll for input */
for (ln = 0; ln < MUX_NUMLIN; ln++) { /* loop thru lines */
if (mux_ldsc[ln].conn) { /* connected? */
if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */
if (c & SCPE_BREAK) /* break? */
mux_sta[ln] |= MUXL_RBP; /* set rcv brk */
else { /* normal char */
mux_sta[ln] &= ~MUXL_RBP; /* clr rcv brk */
c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags));
mux_rbuf[ln] = c; /* save char */
if ((muxc_cmd == MUXC_RCV) && /* chan active? */
(r = muxi_put_char (c, ln))) /* char to chan */
return r;
} /* end else char */
} /* end if char */
} /* end if conn */
else mux_sta[ln] &= ~MUXL_RBP; /* disconnected */
} /* end for */
return SCPE_OK;
}
/* Put character and line number in memory via channel */
t_stat muxi_put_char (uint32 c, uint32 ln)
{
uint32 st;
st = chan_WrMemB (mux_dib.dva, c); /* write char */
if (CHS_IFERR (st)) /* channel error? */
return mux_chan_err (st);
st = chan_WrMemB (mux_dib.dva, ln); /* write line */
if (CHS_IFERR (st)) /* channel error? */
return mux_chan_err (st);
if (st == CHS_ZBC) { /* bc == 0? */
muxc_cmd = MUXC_END; /* end state */
sim_activate (&mux_unit[MUXC], chan_ctl_time); /* quick schedule */
}
io_sclr_req (mux_rint, 1); /* req ext intr */
return SCPE_OK;
}
/* Channel error */
t_stat mux_chan_err (uint32 st)
{
chan_uen (mux_dib.dva); /* uend */
muxc_cmd = MUXC_IDLE; /* go idle */
if (st < CHS_ERR)
return st;
return 0;
}
/* Unit service - transmit side */
t_stat muxo_svc (UNIT *uptr)
{
int32 c;
uint32 ln = uptr - muxl_unit; /* line # */
if (mux_ldsc[ln].conn) { /* connected? */
if (mux_ldsc[ln].xmte) { /* xmt enabled? */
c = sim_tt_outcvt (mux_xbuf[ln], TT_GET_MODE (muxl_unit[ln].flags));
if (c >= 0)
tmxr_putc_ln (&mux_ldsc[ln], c); /* output char */
tmxr_poll_tx (&mux_desc); /* poll xmt */
if (mux_sta[ln] & MUXL_XIA) { /* armed? */
mux_sta[ln] |= MUXL_XIR; /* req intr */
mux_scan_next (0); /* kick scanner */
}
}
else { /* buf full */
tmxr_poll_tx (&mux_desc); /* poll xmt */
sim_activate (uptr, muxl_unit[ln].wait); /* wait */
return SCPE_OK;
}
}
return SCPE_OK;
}
/* MUX status routine */
uint32 mux_tio_status (void)
{
if (muxc_cmd == MUXC_IDLE) /* idle? */
return DVS_AUTO;
else return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC));
}
/* Kick scanner */
void mux_scan_next (t_bool clr)
{
int32 i;
if (clr) /* unlock? */
mux_slck = 0;
else if (mux_slck) /* locked? */
return;
for (i = 0; i < MUX_NUMLIN; i++) { /* scan lines */
mux_scan = mux_scan + 1; /* next line */
if (mux_scan >= (uint32) MUX_NUMLIN)
mux_scan = 0;
if (mux_sta[mux_scan] & MUXL_XIR) { /* flag set? */
mux_slck = 1; /* lock scanner */
io_sclr_req (mux_xint, 1); /* req ext int */
return;
}
}
return;
}
/* Reset routine */
t_stat mux_reset (DEVICE *dptr)
{
int32 i;
if (mux_dev.flags & DEV_DIS) /* master disabled? */
muxl_dev.flags = muxl_dev.flags | DEV_DIS; /* disable lines */
else muxl_dev.flags = muxl_dev.flags & ~DEV_DIS;
if (mux_unit[MUXC].flags & UNIT_ATT) /* master att? */
rtc_register (RTC_COC, mux_tps, &mux_unit[MUXI]); /* register timer */
else rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* else dereg */
for (i = 0; i < MUX_LINES; i++) /* reset lines */
mux_reset_ln (i);
return SCPE_OK;
}
/* Attach master unit */
t_stat mux_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) /* error */
return r;
rtc_register (RTC_COC, mux_tps, &mux_unit[MUXC]); /* register timer */
return SCPE_OK;
}
/* Detach master unit */
t_stat mux_detach (UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach (&mux_desc, uptr); /* detach */
for (i = 0; i < MUX_LINES; i++) /* disable rcv */
mux_reset_ln (i);
rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* dereg */
return r;
}
/* Change number of lines */
t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
newln = get_uint (cptr, 10, MUX_LINES, &r);
if ((r != SCPE_OK) || (newln == MUX_NUMLIN))
return r;
if (newln == 0) return SCPE_ARG;
if (newln < MUX_NUMLIN) {
for (i = newln, t = 0; i < MUX_NUMLIN; i++) t = t | mux_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < MUX_NUMLIN; i++) {
if (mux_ldsc[i].conn) {
tmxr_linemsg (&mux_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&mux_ldsc[i]); /* reset line */
}
muxl_unit[i].flags = muxl_unit[i].flags | UNIT_DIS;
mux_reset_ln (i);
}
}
else {
for (i = MUX_NUMLIN; i < newln; i++) {
muxl_unit[i].flags = muxl_unit[i].flags & ~UNIT_DIS;
mux_reset_ln (i);
}
}
MUX_NUMLIN = newln;
return SCPE_OK;
}
/* Reset an individual line */
void mux_reset_ln (int32 ln)
{
sim_cancel (&muxl_unit[ln]);
mux_sta[ln] = 0;
mux_rbuf[ln] = 0;
mux_xbuf[ln] = 0;
mux_ldsc[ln].rcve = 0;
return;
}

2848
sigma/sigma_cpu.c Normal file

File diff suppressed because it is too large Load Diff

478
sigma/sigma_defs.h Normal file
View File

@@ -0,0 +1,478 @@
/* sigma_defs.h: XDS Sigma simulator definitions
Copyright (c) 2007-2010, 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.
The author gratefullly acknowledges the help of George Plue, who provided
answers to many puzzling questions about how the Sigma series worked.
22-May-10 RMS Added check for 64b definitions
*/
#ifndef _SIGMA_DEFS_H_
#define _SIGMA_DEFS_H_ 0
#include "sim_defs.h" /* simulator defns */
#if defined(USE_INT64) || defined(USE_ADDR64)
#error "Sigma 32b does not support 64b values!"
#endif
/* Simulator stops */
#define STOP_INVIOC 1 /* invalid IO config */
#define STOP_IBKPT 2 /* breakpoint */
#define STOP_ASTOP 3 /* address stop */
#define STOP_WAITNOINT 4 /* WAIT, no intr */
#define STOP_INVPSD 5 /* invalid PSD */
#define STOP_ROLLBACK 6 /* >= here, rollback PC */
#define STOP_EXULIM 6 /* EXU loop */
#define STOP_ILLEG 7 /* illegal instr */
#define STOP_ILLTRP 8 /* illegal trap inst */
#define STOP_ILLVEC 9 /* illegal vector */
#define STOP_TRPT 10 /* trap inside int/trap */
#define STOP_MAX 15 /* <= here for all stops */
/* Timers */
#define TMR_RTC 0 /* clocks */
/* Architectural constants */
#define PASIZE17 17 /* phys addr width, S5-8 */
#define PASIZE20 20 /* phys addr width, 5X0 */
#define PASIZE22 22 /* phys addr width, S9 */
#define PAMASK17 ((1u << PASIZE17) - 1)
#define BPAMASK17 ((1u << (PASIZE17 + 2)) - 1)
#define PAMASK20 ((1u << PASIZE20) - 1)
#define BPAMASK20 ((1u << (PASIZE20 + 2)) - 1)
#define PAMASK22 ((1u << PASIZE22) - 1)
#define BPAMASK22 ((1u << (PASIZE22 + 2)) - 1)
#define MAXMEMSIZE (1u << PASIZE20) /* maximum memory */
#define MEMSIZE (cpu_unit.capac)
#define MEM_IS_NXM(x) ((x) >= MEMSIZE)
#define BPA_IS_NXM(x) (((x) >> 2) >= MEMSIZE)
#define VASIZE 17 /* virtual addr width */
#define VAMASK ((1u << VASIZE) - 1) /* virtual addr mask */
#define BVAMASK ((1u << (VASIZE + 2)) - 1) /* byte virtual addr mask */
#define RF_NUM 16 /* number of registers */
#define RF_NBLK 32 /* max number reg blocks */
#define RF_DFLT 4 /* default reg blocks */
/* CPU models, options, and variable data */
#define CPUF_STR (1u << (UNIT_V_UF + 0)) /* byte string */
#define CPUF_DEC (1u << (UNIT_V_UF + 1)) /* decimal */
#define CPUF_FP (1u << (UNIT_V_UF + 2)) /* floating point */
#define CPUF_MAP (1u << (UNIT_V_UF + 3)) /* memory map */
#define CPUF_WLK (1u << (UNIT_V_UF + 4)) /* write lock protect */
#define CPUF_LAMS (1u << (UNIT_V_UF + 5)) /* LAS/LMS */
#define CPUF_ALLOPT (CPUF_STR|CPUF_DEC|CPUF_FP|CPUF_MAP|CPUF_WLK|CPUF_LAMS)
#define CPUF_MSIZE (1u << (UNIT_V_UF + 6)) /* dummy for memory */
#define CPU_V_S5 0
#define CPU_V_S6 1
#define CPU_V_S7 2
#define CPU_V_S8 3 /* not supported */
#define CPU_V_S9 4 /* not supported */
#define CPU_V_550 5 /* not supported */
#define CPU_V_560 6 /* not supported */
#define CPU_S5 (1u << CPU_V_S5)
#define CPU_S6 (1u << CPU_V_S6)
#define CPU_S7 (1u << CPU_V_S7)
#define CPU_S7B (1u << CPU_V_S7B)
#define CPU_S8 (1u << CPU_V_S8)
#define CPU_S9 (1u << CPU_V_S9)
#define CPU_550 (1u << CPU_V_550)
#define CPU_560 (1u << CPU_V_560)
#define QCPU_S5 (cpu_model == CPU_V_S5)
#define QCPU_S9 (cpu_model == CPU_V_S9)
#define QCPU_5X0 ((1u << cpu_model) & (CPU_550|CPU_560))
#define QCPU_S567 ((1u << cpu_model) & (CPU_S5|CPU_S6|CPU_S7))
#define QCPU_S89 ((1u << cpu_model) & (CPU_S8|CPU_S9))
#define QCPU_S89_5X0 ((1u << cpu_model) & (CPU_S8|CPU_S9|CPU_550|CPU_560))
#define QCPU_BIGM ((1u << cpu_model) & (CPU_S9|CPU_550|CPU_560))
#define CPU_MUNIT_SIZE (1u << 15) /* mem unit size */
typedef struct {
uint32 psw1_mbz; /* PSW1 mbz */
uint32 psw2_mbz; /* PSW2 mbz */
uint32 mmc_cm_map1; /* MMC mode 1 cmask */
uint32 pamask; /* physical addr mask */
uint32 eigrp_max; /* max num ext int groups */
uint32 chan_max; /* max num channels */
uint32 iocc; /* IO instr CC bits */
uint32 std; /* required options */
uint32 opt; /* variable options */
} cpu_var_t;
/* Instruction format */
#define INST_V_IND 31 /* indirect */
#define INST_IND (1u << INST_V_IND)
#define INST_V_OP 24 /* opcode */
#define INST_M_OP 0x7F
#define INST_V_RN 20 /* register */
#define INST_M_RN 0xF
#define INST_V_XR 17 /* index */
#define INST_M_XR 0x7
#define INST_V_ADDR 0 /* 17b addr */
#define INST_M_ADDR 0x1FFFF
#define INST_V_LIT 0 /* 20b literal or addr */
#define INST_M_LIT 0xFFFFF
#define TST_IND(x) ((x) & INST_IND)
#define I_GETOP(x) (((x) >> INST_V_OP) & INST_M_OP)
#define I_GETRN(x) (((x) >> INST_V_RN) & INST_M_RN)
#define I_GETXR(x) (((x) >> INST_V_XR) & INST_M_XR)
#define I_GETADDR(x) (((x) >> INST_V_ADDR) & INST_M_ADDR)
#define I_GETADDR20(x) (((x) >> INST_V_ADDR) & PAMASK20)
#define I_GETLIT(x) (((x) >> INST_V_LIT) & INST_M_LIT)
#define IRB(x) (1u << (31 - (x)))
/* Shift instructions */
#define SHF_V_SOP 8 /* shift operation */
#define SHF_M_SOP 0x7
#define SHF_V_SC 0 /* shift count */
#define SHF_M_SC 0x7F
#define SCSIGN 0x40
#define SHF_GETSOP(x) (((x) >> SHF_V_SOP) & SHF_M_SOP)
#define SHF_GETSC(x) (((x) >> SHF_V_SC) & SHF_M_SC)
/* String instructions */
#define S_V_MCNT 24 /* string mask/count */
#define S_M_MCNT 0xFF
#define S_MCNT (S_M_MCNT << S_V_MCNT)
#define S_GETMCNT(x) (((x) >> S_V_MCNT) & S_M_MCNT)
#define S_ADDRINC (S_MCNT + 1)
/* Data types */
#define WMASK 0xFFFFFFFF /* word */
#define WSIGN 0x80000000 /* word sign */
#define LITMASK (INST_M_LIT) /* literal */
#define LITSIGN 0x80000 /* literal sign */
#define HMASK 0xFFFF /* halfword mask */
#define HSIGN 0x8000 /* halfword sign */
#define BMASK 0xFF /* byte */
#define BSIGN 0x80 /* byte sign */
#define RNMASK (INST_M_RN) /* reg lit */
#define RNSIGN 0x08 /* reg lit sign */
#define FP_V_SIGN 31 /* sign */
#define FP_SIGN (1u << FP_V_SIGN)
#define FP_V_EXP 24 /* exponent */
#define FP_M_EXP 0x7F
#define FP_BIAS 0x40 /* exponent bias */
#define FP_V_FRHI 0 /* high fraction */
#define FP_M_FRHI 0x00FFFFFF
#define FP_NORM 0x00F00000
#define FP_M_FRLO 0xFFFFFFFF /* low fraction */
#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & 1)
#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP)
#define FP_GETFRHI(x) (((x) >> FP_V_FRHI) & FP_M_FRHI)
#define FP_GETFRLO(x) ((x) & FP_M_FRLO)
/* PSW1 fields */
#define PSW1_V_CC 28 /* cond codes */
#define PSW1_M_CC 0xF
#define CC1 0x8
#define CC2 0x4
#define CC3 0x2
#define CC4 0x1
#define PSW1_V_FR 27 /* fp mode controls */
#define PSW1_V_FS 26
#define PSW1_V_FZ 25
#define PSW1_V_FN 24
#define PSW1_V_FPC 24 /* as a group */
#define PSW1_M_FPC 0xF
#define PSW1_FPC (PSW1_M_FPC << PSW1_V_FPC)
#define PSW1_V_MS 23 /* master/slave */
#define PSW1_V_MM 22 /* memory map */
#define PSW1_V_DM 21 /* decimal trap */
#define PSW1_V_AM 20 /* arithmetic trap */
#define PSW1_V_AS 19 /* EBCDIC/ASCII, S9 */
#define PSW1_V_XA 15 /* ext addr flag, S9 */
#define PSW1_V_PC 0 /* PC */
#define PSW1_M_PC (VAMASK)
#define PSW1_FR (1u << PSW1_V_FR)
#define PSW1_FS (1u << PSW1_V_FS)
#define PSW1_FZ (1u << PSW1_V_FZ)
#define PSW1_FN (1u << PSW1_V_FN)
#define PSW1_MS (1u << PSW1_V_MS)
#define PSW1_MM (1u << PSW1_V_MM)
#define PSW1_DM (1u << PSW1_V_DM)
#define PSW1_AM (1u << PSW1_V_AM)
#define PSW1_AS (1u << PSW1_V_AS)
#define PSW1_XA (1u << PSW1_V_XA)
#define PSW1_CCMASK (PSW1_M_CC << PSW1_V_CC)
#define PSW1_PCMASK (PSW1_M_PC << PSW1_V_PC)
#define PSW1_GETCC(x) (((x) >> PSW1_V_CC) & PSW1_M_CC)
#define PSW1_GETPC(x) (((x) >> PSW1_V_PC) & PSW1_M_PC)
#define PSW1_DFLT 0
/* PSW2 fields */
#define PSW2_V_WLK 28 /* write key */
#define PSW2_M_WLK 0xF
#define PSW2_V_CI 26 /* counter int inhibit */
#define PSW2_V_II 25 /* IO int inhibit */
#define PSW2_V_EI 24 /* external int inhibit */
#define PSW2_V_INH (PSW2_V_EI) /* inhibits as a group */
#define PSW2_M_INH 0x7
#define PSW2_V_MA9 23 /* mode altered, S9 */
#define PSW2_V_EA 16 /* ext addr, S9 */
#define PSW2_M_EA 0x3F
#define PSW2_EA (PSW2_M_EA << PSW2_V_EA)
#define PSW2_V_TSF 8 /* trapped status, S9 */
#define PSW2_M_TSF 0xFF
#define PSW2_TSF (PSW2_M_TSF << PSW2_V_TSF)
#define PSW2_V_RP 4 /* register block ptr */
#define PSW2_M_RP5B 0x1F
#define PSW2_M_RP4B 0xF
#define PSW2_RP ((QCPU_S567? PSW2_M_RP5B: PSW2_M_RP4B) << PSW2_V_RP)
#define PSW2_V_RA 3 /* reg altered, 9,5X0 */
#define PSW2_V_MA5X0 2 /* mode altered, 5X0 */
#define PSW2_CI (1u << PSW2_V_CI)
#define PSW2_II (1u << PSW2_V_II)
#define PSW2_EI (1u << PSW2_V_EI)
#define PSW2_ALLINH (PSW2_CI|PSW2_II|PSW2_EI) /* all inhibits */
#define PSW2_MA9 (1u << PSW2_V_MA9)
#define PSW2_RA (1u << PSW2_V_RA)
#define PSW2_MA5X0 (1u << PSW2_V_MA5X0)
#define PSW2_WLKMASK (PSW2_M_WLK << PSW2_V_WLK)
#define PSW2_RPMASK (PSW2_M_RP << PSW2_V_RP)
#define PSW2_GETINH(x) (((x) >> PSW2_V_INH) & PSW2_M_INH);
#define PSW2_GETWLK(x) (((x) >> PSW2_V_WLK) & PSW2_M_WLK)
#define PSW2_GETRP(x) (((x) & PSW2_RP) >> PSW2_V_RP)
#define PSW2_DFLT 0
/* Stack pointers */
#define SP_V_TS 31 /* space trap enable */
#define SP_TS (1u << SP_V_TS)
#define SP_V_SPC 16 /* space */
#define SP_M_SPC 0x7FFF
#define SP_V_TW 15 /* words trap enable */
#define SP_TW (1u << SP_V_TW)
#define SP_V_WDS 0 /* words */
#define SP_M_WDS 0x7FFF
#define SP_GETSPC(x) (((x) >> SP_V_SPC) & SP_M_SPC)
#define SP_GETWDS(x) (((x) >> SP_V_WDS) & SP_M_WDS)
/* System stack pointer (5X0 only) */
#define SSP_TOS 0 /* system stack */
#define SSP_SWC 1 /* space/word count */
#define SSP_DFLT_PSW1 2 /* default PSD */
#define SSP_DFLT_PSW2 3
#define SSP_FR_LNT 28 /* frame length */
#define SSP_FR_RN 0 /* registers */
#define SSP_FR_PSW1 24 /* PSD */
#define SSP_FR_PSW2 25
#define SSP_FR_PSW4 27
/* The Sigma series had word addressable memory, but byte addressable
data. Virtual addresses in the simulator are BYTE addresses, and
these definitions are in terms of a byte address (word << 2). */
#define VA_NUM_PAG (1 << (VASIZE - (BVA_V_PAG - 2)))
#define PA_NUM_PAG (1 << (PASIZE22 - (BVA_V_PAG - 2)))
#define BVA_V_OFF 0 /* offset */
#define BVA_M_OFF 0x7FF
#define BVA_V_PAG 11 /* page */
#define BVA_M_PAG 0xFF
#define BVA_GETOFF(x) (((x) >> BVA_V_OFF) & BVA_M_OFF)
#define BVA_GETPAG(x) (((x) >> BVA_V_PAG) & BVA_M_PAG)
#define BPA_V_PAG (BVA_V_PAG) /* phys page */
#define BPA_M_PAG 0x1FFF
#define BPA_GETPAG(x) (((x) >> BPA_V_PAG) & BPA_M_PAG)
/* Memory maps */
#define MMC_V_CNT 24 /* count */
#define MMC_M_CNT 0xFF
#define MMC_CNT (MMC_M_CNT << MMC_V_CNT)
#define MMC_V_CS 9 /* start of page */
/* /* map 1: 2b locks, per model */
#define MMC_M_CS2 0xFC /* map 2: access controls */
#define MMC_M_CS3 0x7FE /* map 3: 4b locks */
#define MMC_M_CS4 0xFF /* map 4: 8b relocation */
#define MMC_M_CS5 0xFF /* map 5: 13b relocation */
#define MMC_GETCNT(x) (((x) >> MMC_V_CNT) & MMC_M_CNT)
#define MMC_L_CS1 (VA_NUM_PAG) /* map lengths */
#define MMC_L_CS2 (VA_NUM_PAG)
#define MMC_L_CS3 (PA_NUM_PAG)
#define MMC_L_CS4 (VA_NUM_PAG)
#define MMC_L_CS5 (VA_NUM_PAG)
/* Trap codes */
#define TR_V_FL 17 /* trap flag */
#define TR_FL (1u << TR_V_FL)
#define TR_V_PDF 16 /* proc detected fault */
#define TR_PDF (1u << TR_V_FL)
#define TR_V_CC 12 /* or'd to CC/addr offset */
#define TR_M_CC 0xF
#define TR_V_VEC 0 /* trap address */
#define TR_M_VEC 0xFFF
#define TR_GETVEC(x) (((x) >> TR_V_VEC) & TR_M_VEC)
#define TR_GETCC(x) (((x) >> TR_V_CC) & TR_M_CC)
#define TR_NXI (TR_FL|0x8040) /* non-existent inst */
#define TR_NXM (TR_FL|0x4040) /* non-existent memory */
#define TR_PRV (TR_FL|0x2040) /* privileged inst */
#define TR_MPR (TR_FL|0x1040) /* mem protect violation */
#define TR_WLK (TR_FL|0x3040) /* write lock (5x0 only) */
#define TR_UNI (TR_FL|0x0041) /* unimplemented inst */
#define TR_PSH (TR_FL|0x0042) /* pushdown overflow */
#define TR_FIX (TR_FL|0x0043) /* fixed point arith */
#define TR_FLT (TR_FL|0x0044) /* floating point arith */
#define TR_DEC (TR_FL|0x0045) /* decimal arithmetic */
#define TR_WAT (TR_FL|0x0046) /* watchdog timer */
#define TR_47 (TR_FL|0x0047) /* 5X0 - WD trap */
#define TR_C1(x) (TR_FL|0x0048|((x) << TR_V_CC)) /* call instruction */
#define TR_C2(x) (TR_FL|0x0049|((x) << TR_V_CC)) /* call instruction */
#define TR_C3(x) (TR_FL|0x004A|((x) << TR_V_CC)) /* call instruction */
#define TR_C4(x) (TR_FL|0x004B|((x) << TR_V_CC)) /* call instruction */
#define TR_NESTED (TR_FL|TR_PDF|0xF04D) /* 9,5X0 - fault in inv/trap */
#define TR_INVTRP (TR_FL|TR_PDF|0xC04D) /* 9,5X0 - inv int/trap inst */
#define TR_INVRPT (TR_FL|TR_PDF|0x804D) /* 9 - inv new RP in trap */
#define TR_INVSSP (TR_FL|TR_PDF|0x404D) /* 5X0 - inv SSP for PLS */
#define TR_INVMMC (TR_FL|TR_PDF|0x204D) /* 9,5X0 - inv MMC config */
#define TR_INVREG (TR_FL|0x104D) /* 9,5x0 - inv reg num */
#define TR_INVRPN (TR_FL|TR_PDF|0x004D) /* 9 - inv new RP, non-trap */
/* Effective address and memory access routines interface
The access types are defined to make the following equation work:
trap if ((access_type != 0) && (access_control >= access_type))
The length codes are defined so that length in bytes = 1 << length_code */
#define PH 0x0 /* physical */
#define VW 0x1 /* write */
#define VI 0x2 /* instruction */
#define VR 0x3 /* read */
#define VNT 0x4 /* no traps */
#define BY 0x0 /* byte */
#define HW 0x1 /* halfword */
#define WD 0x2 /* word */
#define DW 0x3 /* doubleword */
/* Interrupt groups - the Sigma's have flexibly configured interrupt groups
of various widths that map non-uniformly to control register bits */
typedef struct {
uint32 psw2_inh; /* PSW2 inhibit */
uint32 nbits; /* number of bits */
uint32 vecbase; /* vector base */
uint32 rwgroup; /* RWdirect group */
uint32 regbit; /* RWdirect reg bit */
} int_grp_t;
#define INTG_MAX 17 /* max # int groups */
#define EIGRP_DFLT 1 /* dflt # ei groups */
#define INTG_OVR 0 /* override group */
#define INTG_CTR 1 /* counter group */
#define INTG_IO 2 /* I/O group */
#define INTGIO_IO 0x2 /* I/O interrupt */
#define INTGIO_PANEL 0x1 /* panel interrupt */
#define INTG_E2 3 /* ext group 2 */
#define INTG_E3 4 /* ext group 3 */
#define INT_V_GRP 4 /* interrupt group */
#define INT_M_GRP 0x1F
#define INT_V_BIT 0 /* interrupt bit */
#define INT_M_BIT 0xF
#define INT_GETGRP(x) (((x) >> INT_V_GRP) & INT_M_GRP)
#define INT_GETBIT(x) (((x) >> INT_V_BIT) & INT_M_BIT)
#define INTV(x,y) (((x) << INT_V_GRP) | ((y) << INT_V_BIT))
#define NO_INT (INTV (INTG_MAX, 0))
#define VEC_C1P 0x52 /* clock pulse vectors */
#define VEC_C4P 0x55
#define VEC_C1Z 0x58 /* clock zero vector */
/* Integer data operations and condition codes */
#define SEXT_RN_W(x) (((x) & RNSIGN)? ((x) | ~RNMASK): ((x) & RNMASK))
#define SEXT_H_W(x) (((x) & HSIGN)? ((x) | ~HMASK): ((x) & HMASK))
#define SEXT_LIT_W(x) (((x) & LITSIGN)? ((x) | ~LITMASK): ((x) & LITMASK))
#define NEG_W(x) ((~(x) + 1) & WMASK)
#define NEG_D(x,y) do { y = NEG_W(y); x = (~(x) + ((y) == 0)) & WMASK; } while (0)
#define CC34_W(x) CC = (((x) & WSIGN)? \
((CC & ~CC3) | CC4): \
(((x) != 0)? \
((CC & ~CC4) | CC3): \
(CC & ~(CC3|CC4))))
#define CC234_CMP(x,y) CC = (CC & CC1) | Cmp32 ((x), (y)) | \
(((x) & (y))? CC2: 0)
/* Instructions */
enum opcodes {
OP_00, OP_01, OP_LCFI, OP_03, OP_CAL1, OP_CAL2, OP_CAL3, OP_CAL4,
OP_PLW, OP_PSW, OP_PLM, OP_PSM, OP_PLS, OP_PSS, OP_LPSD, OP_XPSD,
OP_AD, OP_CD, OP_LD, OP_MSP, OP_14, OP_STD, OP_16, OP_17,
OP_SD, OP_CLM, OP_LCD, OP_LAD, OP_FSL, OP_FAL, OP_FDL, OP_FML,
OP_AI, OP_CI, OP_LI, OP_MI, OP_SF, OP_S, OP_LAS, OP_27,
OP_CVS, OP_CVA, OP_LM, OP_STM, OP_LRA, OP_LMS, OP_WAIT, OP_LRP,
OP_AW, OP_CW, OP_LW, OP_MTW, OP_LVAW, OP_STW, OP_DW, OP_MW,
OP_SW, OP_CLR, OP_LCW, OP_LAW, OP_FSS, OP_FAS, OP_FDS, OP_FMS,
OP_TTBS, OP_TBS, OP_42, OP_43, OP_ANLZ, OP_CS, OP_XW, OP_STS,
OP_EOR, OP_OR, OP_LS, OP_AND, OP_SIO, OP_TIO, OP_TDV, OP_HIO,
OP_AH, OP_CH, OP_LH, OP_MTH, OP_54, OP_STH, OP_DH, OP_MH,
OP_SH, OP_59, OP_LCH, OP_LAH, OP_5C, OP_5D, OP_5E, OP_5F,
OP_CBS, OP_MBS, OP_62, OP_EBS, OP_BDR, OP_BIR, OP_AWM, OP_EXU,
OP_BCR, OP_BCS, OP_BAL, OP_INT, OP_RD, OP_WD, OP_AIO, OP_MMC,
OP_LCF, OP_CB, OP_LB, OP_MTB, OP_STCF, OP_STB, OP_PACK, OP_UNPK,
OP_DS, OP_DA, OP_DD, OP_DM, OP_DSA, OP_DC, OP_DL, OP_DST
};
/* Function prototypes */
uint32 Ea (uint32 ir, uint32 *bva, uint32 acc, uint32 lnt);
uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc);
uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc);
uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc);
uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc);
uint32 WriteB (uint32 bva, uint32 dat, uint32 acc);
uint32 WriteH (uint32 bva, uint32 dat, uint32 acc);
uint32 WriteW (uint32 bva, uint32 dat, uint32 acc);
uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc);
uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc);
uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc);
uint32 ReadPB (uint32 ba, uint32 *dat);
uint32 WritePB (uint32 ba, uint32 dat);
uint32 ReadPW (uint32 pa, uint32 *dat);
uint32 WritePW (uint32 pa, uint32 dat);
uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt);
#endif

470
sigma/sigma_dk.c Normal file
View File

@@ -0,0 +1,470 @@
/* sigma_dk.c: 7250/7251-7252 cartridge disk simulator
Copyright (c) 2007-2008, 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.
dk 7250/7251-7252 cartridge disk
Transfers are always done a sector at a time.
*/
#include "sigma_io_defs.h"
#include <math.h>
#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_HWLK (1u << UNIT_V_HWLK)
#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */
#define UTRK u3 /* current track */
/* Constants */
#define DK_NUMDR 8 /* drives/ctlr */
#define DK_WDSC 90 /* words/sector */
#define DK_SCTK 16 /* sectors/track */
#define DK_TKUN 408 /* tracks/unit */
#define DK_WDUN (DK_WDSC*DK_SCTK*DK_TKUN) /* words/unit */
/* Address bytes */
#define DKA_V_TK 4 /* track offset */
#define DKA_M_TK 0x1FF
#define DKA_V_SC 0 /* sector offset */
#define DKA_M_SC 0xF
#define DKA_GETTK(x) (((x) >> DKA_V_TK) & DKA_M_TK)
#define DKA_GETSC(x) (((x) >> DKA_V_SC) & DKA_M_SC)
/* Status byte 3 is current sector */
#define DKS_NBY 3
/* Device state */
#define DKS_INIT 0x101
#define DKS_END 0x102
#define DKS_WRITE 0x01
#define DKS_READ 0x02
#define DKS_SEEK 0x03
#define DKS_SEEK2 0x103
#define DKS_SENSE 0x04
#define DKS_CHECK 0x05
#define DKS_RDEES 0x12
#define DKS_TEST 0x13
/* Device status */
#define DKV_OVR 0x80 /* overrun - NI */
#define DKV_BADS 0x20 /* bad track */
#define DKV_WPE 0x10
#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * DK_WDSC)), \
((double) DK_SCTK)))
uint32 dk_cmd = 0; /* state */
uint32 dk_flags = 0; /* status flags */
uint32 dk_ad = 0; /* disk address */
uint32 dk_time = 5; /* inter-word time */
uint32 dk_stime = 20; /* inter-track time */
uint32 dk_stopioe = 1; /* stop on I/O error */
extern uint32 chan_ctl_time;
uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 dk_tio_status (uint32 un);
uint32 dk_tdv_status (uint32 un);
t_stat dk_chan_err (uint32 st);
t_stat dk_svc (UNIT *uptr);
t_stat dk_reset (DEVICE *dptr);
t_bool dk_inv_ad (uint32 *da);
t_bool dk_inc_ad (void);
t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st);
/* DK data structures
dk_dev DK device descriptor
dk_unit DK unit descriptor
dk_reg DK register list
*/
dib_t dk_dib = { DVA_DK, &dk_disp };
UNIT dk_unit[] = {
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) },
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) },
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) },
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) },
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) },
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) },
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) },
{ UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }
};
REG dk_reg[] = {
{ HRDATA (CMD, dk_cmd, 9) },
{ HRDATA (FLAGS, dk_flags, 8) },
{ HRDATA (ADDR, dk_ad, 8) },
{ DRDATA (TIME, dk_time, 24), PV_LEFT+REG_NZ },
{ DRDATA (STIME, dk_stime, 24), PV_LEFT+REG_NZ },
{ FLDATA (STOPIOE, dk_stopioe, 0) },
{ HRDATA (DEVNO, dk_dib.dva, 12), REG_HRO },
{ NULL }
};
MTAB dk_mod[] = {
{ UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ 0 }
};
DEVICE dk_dev = {
"DK", dk_unit, dk_reg, dk_mod,
DK_NUMDR, 16, 22, 1, 16, 32,
NULL, NULL, &dk_reset,
NULL, NULL, NULL,
&dk_dib, DEV_DISABLE
};
/* DK: IO dispatch routine */
uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst)
{
uint32 i;
uint32 un = DVA_GETUNIT (dva);
UNIT *uptr;
if ((un >= DK_NUMDR) || /* inv unit num? */
(dk_unit[un].flags & UNIT_DIS)) /* disabled unit? */
return DVT_NODEV;
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = dk_tio_status (un); /* get status */
if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */
dk_cmd = DKS_INIT; /* start dev thread */
sim_activate (&dk_unit[un], chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = dk_tio_status (un); /* return status */
break;
case OP_TDV: /* test status */
*dvst = dk_tdv_status (un); /* return status */
break;
case OP_HIO: /* halt I/O */
chan_clr_chi (dk_dib.dva); /* clr int */
*dvst = dk_tio_status (un); /* get status */
if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */
for (i = 0; i < DK_NUMDR; i++) { /* find busy unit */
uptr = &dk_unit[i];
if (sim_is_active (uptr)) { /* active? */
sim_cancel (uptr); /* stop */
chan_uen (dk_dib.dva); /* uend */
} /* end if active */
} /* end for */
}
break;
case OP_AIO: /* acknowledge int */
chan_clr_chi (dk_dib.dva); /* clr int */
*dvst = dk_tdv_status (un); /* status like TDV */
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* Unit service */
t_stat dk_svc (UNIT *uptr)
{
uint32 i, sc, da, wd, wd1, cmd, c[3];
uint32 *fbuf = (uint32 *) uptr->filebuf;
int32 t, dc;
uint32 st;
switch (dk_cmd) {
case DKS_INIT: /* init state */
st = chan_get_cmd (dk_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
return dk_chan_err (st);
if ((cmd == 0) || /* invalid cmd? */
((cmd > DKS_CHECK) && (cmd != DKS_RDEES) && (cmd != DKS_TEST))) {
chan_uen (dk_dib.dva); /* uend */
return SCPE_OK;
}
dk_flags = 0; /* clear status */
dk_cmd = cmd & 0x17; /* next state */
if ((cmd == DKS_SEEK) || /* fast cmd? */
(cmd == DKS_SENSE) ||
(cmd == DKS_TEST))
sim_activate (uptr, chan_ctl_time); /* schedule soon */
else { /* data transfer */
sc = DKA_GETSC (dk_ad); /* new sector */
t = sc - GET_PSC (dk_time); /* delta to new */
if (t < 0) /* wrap around? */
t = t + DK_SCTK;
sim_activate (uptr, t * dk_time * DK_WDSC); /* schedule op */
}
return SCPE_OK;
case DKS_END: /* end state */
st = chan_end (dk_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
return dk_chan_err (st);
if (st == CHS_CCH) { /* command chain? */
dk_cmd = DKS_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time);
}
return SCPE_OK; /* done */
case DKS_SEEK: /* seek */
c[0] = c[1] = 0;
for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) {
st = chan_RdMemB (dk_dib.dva, &c[i]); /* get byte */
if (CHS_IFERR (st)) /* channel error? */
return dk_chan_err (st);
}
dk_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */
if (((i != 2) || (st != CHS_ZBC)) && /* length error? */
chan_set_chf (dk_dib.dva, CHF_LNTE)) /* care? */
return SCPE_OK;
dc = DKA_GETTK (dk_ad); /* desired track */
t = abs (uptr->UTRK - dc); /* get track diff */
if (t == 0)
t = 1;
sim_activate (uptr, t * dk_stime);
uptr->UTRK = dc; /* put on track */
dk_cmd = DKS_SEEK2;
return SCPE_OK;
case DKS_SEEK2: /* seek complete */
if (uptr->UTRK >= DK_TKUN) {
dk_flags |= DKV_BADS;
chan_uen (dk_dib.dva);
return SCPE_OK;
}
break; /* seek done */
case DKS_SENSE: /* sense */
c[0] = ((dk_ad >> 8) & 0x7F) | ((uptr->flags & UNIT_RO)? 0x80: 0);
c[1] = dk_ad & 0xFF; /* address */
c[2] = GET_PSC (dk_time); /* curr sector */
for (i = 0, st = 0; (i < DKS_NBY) && (st != CHS_ZBC); i++) {
st = chan_WrMemB (dk_dib.dva, c[i]); /* store char */
if (CHS_IFERR (st)) /* channel error? */
return dk_chan_err (st);
}
if (((i != DKS_NBY) || (st != CHS_ZBC)) &&
chan_set_chf (dk_dib.dva, CHF_LNTE)) /* length error? */
return SCPE_OK;
break;
case DKS_WRITE: /* write */
if (uptr->flags & UNIT_RO) { /* write locked? */
dk_flags |= DKV_WPE; /* set status */
chan_uen (dk_dib.dva); /* uend */
return SCPE_OK;
}
if (dk_inv_ad (&da)) { /* invalid addr? */
chan_uen (dk_dib.dva); /* uend */
return SCPE_OK;
}
for (i = 0, st = 0; i < DK_WDSC; da++, i++) { /* sector loop */
if (st != CHS_ZBC) { /* chan not done? */
st = chan_RdMemW (dk_dib.dva, &wd); /* read word */
if (CHS_IFERR (st)) { /* channel error? */
dk_inc_ad (); /* da increments */
return dk_chan_err (st);
}
}
else wd = 0;
fbuf[da] = wd; /* store in buffer */
if (da >= uptr->hwmark) /* update length */
uptr->hwmark = da + 1;
}
if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
break;
/* Must be done by bytes to get precise miscompare */
case DKS_CHECK: /* write check */
if (dk_inv_ad (&da)) { /* invalid addr? */
chan_uen (dk_dib.dva); /* uend */
return SCPE_OK;
}
for (i = 0, st = 0; (i < (DK_WDSC * 4)) && (st != CHS_ZBC); ) {
st = chan_RdMemB (dk_dib.dva, &wd); /* read byte */
if (CHS_IFERR (st)) { /* channel error? */
dk_inc_ad (); /* da increments */
return dk_chan_err (st);
}
wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */
if (wd != wd1) { /* check error? */
dk_inc_ad (); /* da increments */
chan_set_chf (dk_dib.dva, CHF_XMDE); /* set xmt err flag */
chan_uen (dk_dib.dva); /* force uend */
return SCPE_OK;
}
da = da + ((++i % 4) == 0); /* every 4th byte */
}
if (dk_end_sec (uptr, i, DK_WDSC * 4, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
break;
case DKS_READ: /* read */
if (dk_inv_ad (&da)) { /* invalid addr? */
chan_uen (dk_dib.dva); /* uend */
return SCPE_OK;
}
for (i = 0, st = 0; (i < DK_WDSC) && (st != CHS_ZBC); da++, i++) {
st = chan_WrMemW (dk_dib.dva, fbuf[da]); /* store in mem */
if (CHS_IFERR (st)) { /* channel error? */
dk_inc_ad (); /* da increments */
return dk_chan_err (st);
}
}
if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */
return SCPE_OK; /* err or cont */
break;
}
dk_cmd = DKS_END; /* op done, next state */
sim_activate (uptr, chan_ctl_time);
return SCPE_OK;
}
/* Common read/write sector end routine
case 1 - more to transfer, not end disk - reschedule, return TRUE
case 2 - more to transfer, end disk - uend, return TRUE
case 3 - transfer done, length error - uend, return TRUE
case 4 - transfer done, no length error - return FALSE (sched end state)
*/
t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st)
{
if (st != CHS_ZBC) { /* end record? */
if (dk_inc_ad ()) /* inc addr, ovf? */
chan_uen (dk_dib.dva); /* uend */
else sim_activate (uptr, dk_time * 16); /* no, next sector */
return TRUE;
}
dk_inc_ad (); /* just incr addr */
if ((lnt != exp) && /* length error? */
chan_set_chf (dk_dib.dva, CHF_LNTE)) /* do we care? */
return TRUE;
return FALSE; /* cmd done */
}
/* DK status routine */
uint32 dk_tio_status (uint32 un)
{
uint32 i;
for (i = 0; i < DK_NUMDR; i++) { /* loop thru units */
if (sim_is_active (&dk_unit[i])) /* active? */
return (DVS_AUTO | DVS_CBUSY | (CC2 << DVT_V_CC) |
((i == un)? DVS_DBUSY: 0));
}
return DVS_AUTO;
}
uint32 dk_tdv_status (uint32 un)
{
return dk_flags | (dk_inv_ad (NULL)? DKV_BADS: 0);
}
/* Validate disk address */
t_bool dk_inv_ad (uint32 *da)
{
uint32 tk = DKA_GETTK (dk_ad);
uint32 sc = DKA_GETSC (dk_ad);
if (tk >= DK_TKUN) /* badtrk? */
return TRUE;
if (da) /* return word addr */
*da = ((tk * DK_SCTK) + sc) * DK_WDSC;
return FALSE;
}
/* Increment disk address */
t_bool dk_inc_ad (void)
{
uint32 tk = DKA_GETTK (dk_ad);
uint32 sc = DKA_GETSC (dk_ad);
sc = sc + 1; /* sector++ */
if (sc >= DK_SCTK) { /* overflow? */
sc = 0; /* wrap sector */
tk = tk + 1; /* track++ */
}
dk_ad = ((tk << DKA_V_TK) | /* rebuild dk_ad */
(sc << DKA_V_SC));
if (tk >= DK_TKUN) /* invalid addr? */
return TRUE;
return FALSE;
}
/* Channel error */
t_stat dk_chan_err (uint32 st)
{
chan_uen (dk_dib.dva); /* uend */
if (st < CHS_ERR)
return st;
return SCPE_OK;
}
/* Reset routine */
t_stat dk_reset (DEVICE *dptr)
{
uint32 i;
for (i = 0; i < DK_NUMDR; i++) {
sim_cancel (&dk_unit[i]); /* stop dev thread */
dk_unit[i].UTRK = 0;
}
dk_cmd = 0;
dk_flags = 0;
dk_ad = 0;
chan_reset_dev (dk_dib.dva); /* clr int, active */
return SCPE_OK;
}

BIN
sigma/sigma_doc.doc Normal file

Binary file not shown.

1278
sigma/sigma_dp.c Normal file

File diff suppressed because it is too large Load Diff

421
sigma/sigma_fp.c Normal file
View File

@@ -0,0 +1,421 @@
/* sigma_fp.c: XDS Sigma floating point simulator
Copyright (c) 2007-2008, 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.
*/
#include "sigma_defs.h"
#define UFP_V_GUARD 4
#define UFP_NORM (FP_NORM << UFP_V_GUARD)
#define UFP_CARRY (UFP_NORM << 4)
#define UFP_FRHI (UFP_CARRY|UFP_NORM|FP_M_FRHI)
#define UFP_FRLO 0xFFFFFFFF
/* Double precision fraction add/subtract/compare */
/* Note: UFP_ADD (s, r, r) will not work!!! */
#define UFP_ADD(s1,s2,d) do { \
d.l = (s1.l + s2.l) & UFP_FRLO; \
d.h = (s1.h + s2.h + (d.l < s2.l)) & UFP_FRHI; \
} while (0)
#define UFP_SUB(s1,s2,d) do { \
d.h = (s1.h - s2.h - (s1.l < s2.l)) & UFP_FRHI; \
d.l = (s1.l - s2.l) & UFP_FRLO; \
} while (0)
#define UFP_GE(s1,s2) ((s1.h > s2.h) || \
((s1.h == s2.h) && (s1.l >= s2.l)))
/* Variable and constant shifts; for constants, 0 < k < 32 */
#define UFP_RSH_V(v,s) do { \
if ((s) < 32) { \
v.l = ((v.l >> (s)) | \
( v.h << (32 - (s)))) & UFP_FRLO; \
v.h = v.h >> (s); \
} \
else if ((s) < 64) { \
v.l = v.h >> ((s) - 32); \
v.h = 0; \
} \
else v.l = v.h = 0; \
} while (0)
#define UFP_RSH_K(v,s) do { \
v.l = ((v.l >> (s)) | \
(v.h << (32 - (s)))) & UFP_FRLO; \
v.h = v.h >> (s); \
} while (0)
#define UFP_LSH_K(v,s) do { \
v.h = ((v.h << (s)) | \
(v.l >> (32 - (s)))) & UFP_FRHI; \
v.l = (v.l << (s)) & UFP_FRLO; \
} while (0)
#define UFP_RSH_KP(v,s) do { \
v->l = ((v->l >> (s)) | \
(v->h << (32 - (s)))) & UFP_FRLO; \
v->h = v->h >> (s); \
} while (0)
#define UFP_LSH_KP(v,s) do { \
v->h = ((v->h << (s)) | \
(v->l >> (32 - (s)))) & UFP_FRHI; \
v->l = (v->l << (s)) & UFP_FRLO; \
} while (0)
typedef struct {
uint32 sign;
int32 exp;
uint32 h;
uint32 l;
} ufp_t;
extern uint32 *R;
extern uint32 PSW1;
extern uint32 CC;
void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst);
t_bool fp_clnzro (ufp_t *src, t_bool abnorm);
uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap);
uint32 fp_norm (ufp_t *src);
uint32 fp (uint32 op, uint32 rn, uint32 bva)
{
uint32 rh, rl, mh, ml, i, ediff, nsh;
t_bool s1nz, s2nz;
t_bool dbl = ((op & 0x20) == 0);
ufp_t fop1, fop2, t;
ufp_t res = { 0, 0, 0, 0 };
uint32 tr;
if (dbl) { /* double prec? */
rh = R[rn]; /* get reg operands */
rl = R[rn|1];
if ((tr = ReadD (bva, &mh, &ml, VR)) != 0) /* get mem word */
return tr;
}
else { /* single precision */
rh = R[rn]; /* pad to double */
rl = 0;
if ((tr = ReadW (bva, &mh, VR)) != 0)
return tr;
ml = 0;
}
fp_unpack (rh, rl, &fop1); /* unpack, test */
fp_unpack (mh, ml, &fop2);
CC = 0;
switch (op) { /* case on opcode */
case OP_FSS: /* subtract */
case OP_FSL:
fop2.sign = fop2.sign ^ 1; /* invert mem sign */
/* fall through */
case OP_FAS: /* add */
case OP_FAL:
s1nz = fp_clnzro (&fop1, TRUE); /* test, clean op1 */
s2nz = fp_clnzro (&fop2, TRUE);
if (!s1nz) /* op1 = 0? res = op2 */
res = fop2;
else if (!s2nz) /* op2 = 0? res = op1 */
res = fop1;
else { /* both non-zero */
if (fop1.exp < fop2.exp) { /* exp1 < exp2? */
t = fop2; /* swap operands */
fop2 = fop1;
fop1 = t;
}
ediff = fop1.exp - fop2.exp; /* exp difference */
res.sign = fop1.sign; /* result sign, exp */
res.exp = fop1.exp;
if (ediff) { /* any difference? */
UFP_RSH_V (fop2, ediff * 4); /* shift frac */
if (dbl) { /* double? */
if ((PSW1 & PSW1_FR) == 0) /* rounding off? */
fop2.l &= ~0xF; /* no guard */
}
else fop2.l = 0; /* single? clr lo */
}
if (fop1.sign ^ fop2.sign) { /* eff subtract */
if (UFP_GE (fop1, fop2)) { /* fop1 >= fop2? */
UFP_SUB (fop1, fop2, res); /* sub fractions */
}
else { /* fop2 > fop1 */
UFP_SUB (fop2, fop1, res); /* rev subtract */
res.sign = fop2.sign; /* change signs */
}
} /* end subtract */
else { /* eff add */
UFP_ADD (fop1, fop2, res); /* add fractions */
if (res.h & UFP_CARRY) { /* carry out? */
UFP_RSH_K (res, 4); /* renormalize */
res.exp = res.exp + 1; /* incr exp */
}
} /* end add */
} /* end nz operands */
if (!dbl) /* single? clr lo */
res.l = 0;
if ((PSW1 & PSW1_FN) == 0) { /* postnormalize? */
if ((res.h | res.l) == 0) { /* result zero? */
CC = CC1; /* set signif flag */
if (PSW1 & PSW1_FS) /* trap enabled? */
return TR_FLT;
return fp_pack (&res, rn, dbl, FALSE); /* pack up */
}
nsh = fp_norm (&res); /* normalize */
if ((res.exp < 0) && /* underflow? */
!(PSW1 & PSW1_FZ) && /* !FN */
(PSW1 & PSW1_FS) && /* FS */
(nsh > 2)) { /* shifts > 2? */
CC = CC1 | (res.sign? CC4: CC3); /* signif CC's */
return TR_FLT; /* trap */
} /* end if underflow */
else if (nsh > 2) { /* shifts > 2? */
CC |= CC1 | (res.sign? CC4: CC3); /* set CC1 */
if (PSW1 & PSW1_FS) /* trap enabled? */
return TR_FLT;
}
} /* end if postnorm */
return fp_pack (&res, rn, dbl, TRUE); /* pack result */
case OP_FMS:
case OP_FML: /* floating multiply */
s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */
s2nz = fp_clnzro (&fop2, FALSE);
if (s1nz && s2nz) { /* both non-zero? */
fp_norm (&fop1); /* prenormalize */
fp_norm (&fop2);
UFP_RSH_K (fop2, 4); /* undo guard */
res.sign = fop1.sign ^ fop2.sign; /* result sign */
res.exp = fop1.exp + fop2.exp - FP_BIAS; /* result exp */
if (!dbl) { /* 24b x 24b? */
for (i = 0; i < 24; i++) { /* 24 iterations */
if (fop2.h & 1)
res.h = res.h + fop1.h; /* add hi only */
UFP_RSH_K (res, 1); /* shift dp res */
fop2.h = fop2.h >> 1;
}
res.l = 0; /* single prec */
}
else { /* some low 0's */
for (i = 0; i < 56; i++) { /* 56 iterations */
if (fop2.l & 1) {
UFP_ADD (res, fop1, res);
}
UFP_RSH_K (res, 1);
UFP_RSH_K (fop2, 1);
}
}
fp_norm (&res); /* normalize result */
}
return fp_pack (&res, rn, dbl, TRUE); /* pack result */
case OP_FDS:
case OP_FDL: /* floating divide */
s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */
s2nz = fp_clnzro (&fop2, FALSE);
if (!s2nz) { /* divide by zero? */
CC = CC2; /* set CC2 */
return TR_FLT; /* trap */
}
if (s1nz) { /* divd non-zero? */
fp_norm (&fop1); /* prenormalize */
fp_norm (&fop2);
res.sign = fop1.sign ^ fop2.sign; /* result sign */
res.exp = fop1.exp - fop2.exp + FP_BIAS; /* result exp */
if (!UFP_GE (fop1, fop2)) {
UFP_LSH_K (fop1, 4); /* ensure success */
}
else res.exp = res.exp + 1; /* incr exponent */
for (i = 0; i < (uint32)(dbl? 15: 7); i++) {/* 7/15 hex digits */
UFP_LSH_K (res, 4); /* shift quotient */
while (UFP_GE (fop1, fop2)) { /* while sub works */
UFP_SUB (fop1, fop2, fop1); /* decrement */
res.l = res.l + 1; /* add quo bit */
}
UFP_LSH_K (fop1, 4); /* shift divd */
} /* end hex loop */
if (!dbl) { /* single? */
res.h = res.l; /* move quotient */
res.l = 0;
}
fp_norm (&res); /* normalize result */
}
return fp_pack (&res, rn, dbl, TRUE); /* pack result */
} /* end case */
return SCPE_IERR;
}
void ShiftF (uint32 rn, uint32 stype, uint32 sc)
{
uint32 opnd, opnd1;
ufp_t src;
opnd = R[rn]; /* get operands */
opnd1 = stype? R[rn|1]: 0; /* zextend single */
fp_unpack (opnd, opnd1, &src); /* unpack */
CC = 0;
if (sc & SCSIGN) { /* right? */
sc = SHF_M_SC + 1 - sc;
while (sc > 0) { /* while count */
UFP_RSH_K (src, 4); /* shift right hex */
if (stype) /* zero guard */
src.l &= ~0xF;
else src.h &= ~0xF;
src.exp++; /* incr exp */
sc--;
if (src.exp > FP_M_EXP) { /* overflow? */
CC |= CC2; /* set CC2, stop */
break;
}
} /* end while */
if ((src.h | src.l) == 0) { /* result 0? */
if (stype) /* result is true 0 */
R[rn|1] = 0;
R[rn] = 0;
CC = 0;
return;
}
}
else { /* left */
if ((src.h | src.l) == 0) { /* fraction 0? */
if (stype) /* result is true 0 */
R[rn|1] = 0;
R[rn] = 0;
CC = CC1;
return;
}
while ((sc > 0) && ((src.h & UFP_NORM) == 0)) { /* while count & !norm */
UFP_LSH_K (src, 4); /* hex shift left */
src.exp--; /* decr exp */
sc--;
if (src.exp < 0) { /* underflow? */
CC |= CC2; /* set CC2, stop */
break;
}
} /* end while */
if (src.h & UFP_NORM) /* normalized? */
CC |= CC1; /* set CC1 */
}
fp_pack (&src, rn, stype, FALSE); /* pack result */
return;
}
void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst)
{
dst->sign = FP_GETSIGN (hi); /* get sign */
if (dst->sign) /* negative? */
NEG_D (hi, lo); /* 2's compl */
dst->h = FP_GETFRHI (hi); /* get fraction */
dst->l = FP_GETFRLO (lo);
dst->exp = FP_GETEXP (hi); /* get exp */
UFP_LSH_KP (dst, 4); /* guard result */
return;
}
/* Test for and clean a floating point zero
abnorm defines whether to allow "abnormal" zeros */
t_bool fp_clnzro (ufp_t *src, t_bool abnorm)
{
if (((src->h | src->l) == 0) && /* frac zero and */
(!abnorm || (src->exp == 0))) { /* exp zero or !ab */
src->sign = 0; /* true zero */
src->exp = 0;
return FALSE;
}
return TRUE; /* non-zero */
}
uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap)
{
static ufp_t fp_zero = { 0, 0, 0, 0};
uint32 opnd, opnd1;
if (src->h || (dbl && src->l)) { /* result != 0? */
CC |= (src->sign? CC4: CC3); /* set CC's */
if (rndtrap) { /* round, trap? */
if (PSW1 & PSW1_FR) { /* round? */
if (dbl) { /* double prec? */
src->l = (src->l + 0x8) & UFP_FRLO;
src->h = src->h + (src->l < 0x8);
}
else src->h = src->h + 0x8; /* no, single */
if (src->h & UFP_CARRY) { /* carry out? */
UFP_RSH_KP (src, 4); /* renormalize */
src->exp = src->exp + 1;
}
} /* end if round */
if (src->exp > FP_M_EXP) { /* overflow? */
CC |= CC2; /* flag */
return TR_FLT;
}
else if (src->exp < 0) { /* underflow? */
if (PSW1 & PSW1_FZ) { /* trap enabled? */
CC |= CC1 | CC2; /* flag */
return TR_FLT;
}
*src = fp_zero; /* result 0 */
CC = CC1|CC2; /* special CC's */
}
} /* end rnd trap */
UFP_RSH_KP (src, 4); /* remove guard */
if (!dbl) /* single? lose lower */
src->l = 0;
if ((src->h | src->l) == 0) /* result now 0? */
src->exp = src->sign = 0;
}
else *src = fp_zero;
opnd = ((src->exp & FP_M_EXP) << FP_V_EXP) | /* repack */
((src->h & FP_M_FRHI) << FP_V_FRHI);
opnd1 = src->l & FP_M_FRLO;
if (src->sign) /* negative? */
NEG_D (opnd, opnd1);
R[rn] = opnd; /* store result */
if (dbl && ((rn & 1) == 0))
R[rn|1] = opnd1;
return 0;
}
uint32 fp_norm (ufp_t *src)
{
uint32 nsh;
nsh = 0;
src->h &= UFP_FRHI;
if (src->h || src->l) { /* if non-zero */
while ((src->h & UFP_NORM) == 0) { /* until normalized */
UFP_LSH_KP (src, 4); /* hex shift left */
src->exp--; /* decr exponent */
nsh++; /* count shifts */
}
}
return nsh;
}

1497
sigma/sigma_io.c Normal file

File diff suppressed because it is too large Load Diff

276
sigma/sigma_io_defs.h Normal file
View File

@@ -0,0 +1,276 @@
/* sigma_io_defs.h: XDS Sigma I/O device simulator definitions
Copyright (c) 2007-2008, 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.
*/
#ifndef _SIGMA_IO_DEFS_H_
#define _SIGMA_IO_DEFS_H_ 0
#include "sim_defs.h" /* simulator defns */
#include "sigma_defs.h"
/* Channel constants */
#define CHAN_N_CHAN 8 /* max # channels */
#define CHAN_DFLT 4 /* default # chan */
#define CHAN_N_DEV 32 /* max dev per chan */
#define CHAN_V_IOPT (DEV_V_UF + 0) /* channel type */
#define CHAN_MIOP (0 << CHAN_V_IOPT)
#define CHAN_SIOP (1 << CHAN_V_IOPT)
/* I/O device definition block */
typedef struct {
uint32 dva; /* dev addr (chan+dev) */
uint32 (*disp)(uint32 op, uint32 dva, uint32 *dvst);
uint32 dio; /* dev addr (direct IO) */
uint32 (*dio_disp)(uint32 op, uint32 rn, uint32 dva);
} dib_t;
/* Channel data structure */
typedef struct {
uint32 clc[CHAN_N_DEV]; /* location counter */
uint32 ba[CHAN_N_DEV]; /* mem addr */
uint16 bc[CHAN_N_DEV]; /* byte count */
uint8 cmd[CHAN_N_DEV]; /* command */
uint8 cmf[CHAN_N_DEV]; /* command flags */
uint16 chf[CHAN_N_DEV]; /* channel flags */
uint8 chi[CHAN_N_DEV]; /* interrupts */
uint8 chsf[CHAN_N_DEV]; /* simulator flags */
uint32 (*disp[CHAN_N_DEV])(uint32 op, uint32 dva, uint32 *dvst);
} chan_t;
/* Channel command words */
#define CCW1_V_CMD 24 /* command */
#define CCW1_M_CMD 0xFF
#define CCW1_V_BA 0
#define CCW1_M_BA ((cpu_tab[cpu_model].pamask << 2) | 0x3)
#define CHBA_MASK (CCW1_M_BA << CCW1_V_BA)
#define CCW2_V_CMF 24 /* cmd flags */
#define CCW2_M_CMF 0xFF
#define CCW2_V_BC 0
#define CCW2_M_BC 0xFFFF
#define CHBC_MASK (CCW2_M_BC << CCW2_V_BC)
#define CCW1_GETCMD(x) (((x) >> CCW1_V_CMD) & CCW1_M_CMD)
#define CCW1_GETBA(x) (((x) >> CCW1_V_BA) & CCW1_M_BA)
#define CCW2_GETCMF(x) (((x) >> CCW2_V_CMF) & CCW2_M_CMF)
#define CCW2_GETBC(x) (((x) >> CCW2_V_BC) & CCW2_M_BC)
/* Channel commands */
#define CMD_TIC 0x8 /* transfer */
/* Channel command flags */
#define CMF_DCH 0x80 /* data chain */
#define CMF_IZC 0x40 /* int on zero cnt */
#define CMF_CCH 0x20 /* command chain */
#define CMF_ICE 0x10 /* int on chan end */
#define CMF_HTE 0x08 /* hlt on xmit err */
#define CMF_IUE 0x04 /* int on uend */
#define CMF_SIL 0x02 /* suppress lnt err */
#define CMF_SKP 0x01 /* skip */
/* Channel flags */
#define CHF_INP 0x8000 /* int pending */
#define CHF_UEN 0x0400 /* unusual end */
#define CHF_LNTE 0x0080 /* length error */
#define CHF_XMDE 0x0040 /* xmit data error */
#define CHF_XMME 0x0020 /* xmit mem error */
#define CHF_XMAE 0x0010 /* xmit addr error */
#define CHF_IOME 0x0008 /* IOP mem error */
#define CHF_IOCE 0x0004 /* IOP ctrl error */
#define CHF_IOHE 0x0002 /* IOP halted */
#define CHF_ALL (CHF_INP|CHF_UEN|0xFF)
/* Channel interrupts */
#define CHI_F_SHF 1 /* flag shift */
#define CHI_CTL (0x40 << CHI_F_SHF) /* ctl int (fake) */
#define CHI_ZBC (0x20 << CHI_F_SHF) /* zero by cnt int */
#define CHI_END (0x10 << CHI_F_SHF) /* channel end int */
#define CHI_UEN (0x08 << CHI_F_SHF) /* unusual end int */
#define CHI_FLAGS (CHI_ZBC|CHI_END|CHI_UEN)
#define CHI_V_UN 0
#define CHI_M_UN 0xF
#define CHI_GETUN(x) (((x) >> CHI_V_UN) & CHI_M_UN)
#define CHI_GETINT(x) (((x) & CHI_FLAGS) >> CHI_F_SHF)
/* Internal simulator flags */
#define CHSF_ACT 0x0001 /* channel active */
#define CHSF_MU 0x0002 /* multi-unit dev */
/* Dispatch routine status return value */
#define DVT_V_UN 24 /* unit addr (AIO only) */
#define DVT_M_UN 0xF
#define DVT_V_CC 16 /* cond codes */
#define DVT_M_CC 0xF
#define DVT_V_DVS 0 /* device status */
#define DVT_M_DVS 0xFF
#define DVS_V_DST 5 /* device status */
#define DVS_M_DST 0x3
#define DVS_DST (DVS_M_DST << DVS_V_DST)
#define DVS_DOFFL (0x1 << DVS_V_DST)
#define DVS_DBUSY (0x3 << DVS_V_DST)
#define DVS_AUTO 0x10 /* manual/automatic */
#define DVS_V_CST 1 /* ctrl status */
#define DVS_M_CST 0x3
#define DVS_CBUSY (0x3 << DVS_V_CST)
#define DVS_CST (DVS_M_CST << DVS_V_CST)
#define DVT_GETUN(x) (((x) >> DVT_V_UN) & DVT_M_UN)
#define DVT_GETCC(x) (((x) >> DVT_V_CC) & DVT_M_CC)
#define DVT_GETDVS(x) (((x) >> DVT_V_DVS) & DVT_M_DVS)
#define DVT_NOST (CC1 << DVT_V_CC) /* no status */
#define DVT_NODEV ((CC1|CC2) < DVT_V_CC) /* no device */
/* Read and write direct address format */
#define DIO_V_MOD 12 /* mode */
#define DIO_M_MOD 0xF
#define DIO_V_0FNC 0 /* mode 0 func */
#define DIO_M_0FNC 0xFFF
#define DIO_V_1FNC 8 /* mode 1 int func */
#define DIO_M_1FNC 0x7
#define DIO_V_1GRP 0 /* int group */
#define DIO_M_1GRP 0xF
#define DIO_GETMOD(x) (((x) >> DIO_V_MOD) & DIO_M_MOD)
#define DIO_GET0FNC(x) (((x) >> DIO_V_0FNC) & DIO_M_0FNC)
#define DIO_GET1FNC(x) (((x) >> DIO_V_1FNC) & DIO_M_1FNC)
#define DIO_GET1GRP(x) (((x) >> DIO_V_1GRP) & DIO_M_1GRP)
#define DIO_N_MOD (DIO_M_MOD + 1) /* # DIO "modes" */
/* I/O instruction address format */
#define DVA_V_CHAN 8 /* channel */
#define DVA_M_CHAN (CHAN_N_CHAN - 1)
#define DVA_CHAN (DVA_M_CHAN << DVA_V_CHAN)
#define DVA_V_DEVSU 0 /* dev, 1 unit */
#define DVA_M_DEVSU 0x7F
#define DVA_DEVSU (DVA_M_DEVSU << DVA_V_DEVSU)
#define DVA_MU 0x80 /* multi-unit flg */
#define DVA_V_DEVMU 4 /* dev, multi */
#define DVA_M_DEVMU 0x7
#define DVA_DEVMU (DVA_M_DEVMU << DVA_V_DEVMU)
#define DVA_V_UNIT 0 /* unit number */
#define DVA_M_UNIT 0xF
#define DVA_GETCHAN(x) (((x) >> DVA_V_CHAN) & DVA_M_CHAN)
#define DVA_GETDEV(x) (((x) & DVA_MU)? \
(((x) >> DVA_V_DEVMU) & DVA_M_DEVMU): \
(((x) >> DVA_V_DEVSU) & DVA_M_DEVSU))
#define DVA_GETUNIT(x) (((x) & DVA_MU)? \
(((x) >> DVA_V_UNIT) & DVA_M_UNIT): 0)
/* Default I/O device addresses */
#define DVA_TT 0x001
#define DVA_LP 0x002
#define DVA_CR 0x003
#define DVA_CP 0x004
#define DVA_PT 0x005
#define DVA_MUX 0x006
#define DIO_MUX 0x3
#define DVA_MT 0x080
#define DVA_RAD 0x180
#define DVA_DK 0x190
#define DVA_DPA 0x280
#define DVA_DPB 0x380
/* Channel routine status codes */
#define CHS_ERR 0x4000 /* any error */
#define CHS_INF 0x8000 /* information */
#define CHS_IFERR(x) (((x) != 0) && ((x) < CHS_INF))
#define CHS_INACTV (CHS_ERR + 0)
#define CHS_NXM (CHS_ERR + 1)
#define CHS_SEQ (CHS_ERR + 2)
#define CHS_ZBC (CHS_INF + 1) /* zero byte count */
#define CHS_CCH (CHS_INF + 2) /* command chain */
/* Boot ROM */
#define BOOT_SA 0x20
#define BOOT_LNT 12
#define BOOT_DEV 0x25
#define BOOT_PC 0x26
/* Internal real-time scheduler */
#define RTC_C1 0
#define RTC_C2 1
#define RTC_C3 2
#define RTC_C4 3
#define RTC_NUM_CNTRS 4
#define RTC_TTI (RTC_NUM_CNTRS + 0)
#define RTC_COC (RTC_NUM_CNTRS + 1)
#define RTC_ALARM (RTC_NUM_CNTRS + 2)
#define RTC_NUM_EVNTS (RTC_NUM_CNTRS + 3)
#define RTC_HZ_OFF 0
#define RTC_HZ_500 1
#define RTC_HZ_50 2
#define RTC_HZ_60 3
#define RTC_HZ_100 4
#define RTC_HZ_2 5
#define RTC_NUM_HZ 6
/* Function prototypes */
uint32 chan_get_cmd (uint32 dva, uint32 *cmd);
uint32 chan_set_chf (uint32 dva, uint32 fl);
t_bool chan_tst_cmf (uint32 dva, uint32 fl);
void chan_set_chi (uint32 dva, uint32 fl);
void chan_set_dvi (uint32 dva);
int32 chan_clr_chi (uint32 dva);
int32 chan_chk_chi (uint32 dva);
uint32 chan_end (uint32 dva);
uint32 chan_uen (uint32 dva);
uint32 chan_RdMemB (uint32 dva, uint32 *dat);
uint32 chan_WrMemB (uint32 dva, uint32 dat);
uint32 chan_WrMemBR (uint32 dva, uint32 dat);
uint32 chan_RdMemW (uint32 dva, uint32 *dat);
uint32 chan_WrMemW (uint32 dva, uint32 dat);
t_stat chan_reset_dev (uint32 dva);
void io_sclr_req (uint32 inum, uint32 val);
void io_sclr_arm (uint32 inum, uint32 val);
t_stat io_set_dvc (UNIT* uptr, int32 val, char *cptr, void *desc);
t_stat io_show_dvc (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat io_set_dva (UNIT* uptr, int32 val, char *cptr, void *desc);
t_stat io_show_dva (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat io_show_cst (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat io_boot (int32 u, DEVICE *dptr);
/* Internal real-time event scheduler */
t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc);
t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr);
#endif

529
sigma/sigma_lp.c Normal file
View File

@@ -0,0 +1,529 @@
/* sigma_lp.c: Sigma 7440/7450 line printer
Copyright (c) 2007-2008, 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.
lp 7440/7445 or 7450 line printer
*/
#include "sigma_io_defs.h"
/* Device definitions */
#define CCT_LNT 256 /* carriage ctl max */
#define BUF_LNT4 132 /* line lengths */
#define BUF_LNT5 128
#define LP_7440 0 /* models */
#define LP_7450 1
/* Device states */
#define LPS_INIT 0x101
#define LPS_END 0x102
#define LPS_PRI 0x1
#define LPS_FMT 0x3
#define LPS_FMTP 0x5
#define LPS_INT 0x40
/* Device status */
#define LPDV_ODD 0x40 /* odd */
#define LPDV_TOF 0x10 /* top of form */
#define LPDV_MOV 0x08 /* paper moving */
#define LPDV_V_RUN 2 /* runaway CCT */
#define LPDV_RUN (1u << LPDV_V_RUN)
#define LPDV_WT2 0x02 /* waiting for 2nd */
/* Format characters */
#define FMT_INH 0x60
#define FMT_SPC 0xC0
#define FMT_SKP 0xF0
#define FMT_MSPC4 15 /* max space cmd */
#define FMT_MSPC5 7
#define SPC_MASK ((lp_model == LP_7440)? FMT_MSPC4: FMT_MSPC5)
#define FMT_MCH4 7 /* max CCT channel */
#define FMT_MCH5 1
#define CCH_MASK ((lp_model == LP_7440)? FMT_MCH5: FMT_MCH4)
#define CH_BOF 0 /* CCT bot of form */
#define CH_TOF 1 /* CCT top of form */
#define CHP(ch,val) ((val) & (1 << (ch)))
uint32 lp_cmd = 0;
uint32 lp_stopioe = 1;
uint32 lp_cctp = 0; /* CCT position */
uint32 lp_cctl = 1; /* CCT length */
uint32 lp_lastcmd = 0; /* last command */
uint32 lp_pass = 0; /* 7450 print pass */
uint32 lp_inh = 0; /* space inhibit */
uint32 lp_run = 0; /* CCT runaway */
uint32 lp_model = LP_7440;
uint8 lp_buf[BUF_LNT4]; /* print buffer */
uint8 lp_cct[CCT_LNT] = { 0xFF }; /* carriage ctl tape */
uint8 lp_to_ascii[64] = {
' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '`', '.', '<', '(', '+', '|',
'&', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ')', ';', '~',
'-', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '^', ',', '%', '_', '>', '?',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', '#', '@', '\'', '=', '"'
};
extern uint32 chan_ctl_time;
uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 lp_tio_status (void);
uint32 lp_tdv_status (void);
t_stat lp_chan_err (uint32 st);
t_stat lp_svc (UNIT *uptr);
t_stat lp_reset (DEVICE *dptr);
t_stat lp_attach (UNIT *uptr, char *cptr);
t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc);
uint32 lp_fmt (UNIT *uptr);
uint32 lp_skip (UNIT *uptr, uint32 ch);
uint32 lp_space (UNIT *uptr, uint32 lines, t_bool skp);
uint32 lp_print (UNIT *uptr);
/* LP data structures
lp_dev LP device descriptor
lp_unit LP unit descriptors
lp_reg LP register list
lp_mod LP modifiers list
*/
dib_t lp_dib = { DVA_LP, lp_disp, 0, NULL };
UNIT lp_unit = { UDATA (&lp_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT };
REG lp_reg[] = {
{ HRDATA (CMD, lp_cmd, 9) },
{ BRDATA (BUF, lp_buf, 16, 7, BUF_LNT4) },
{ FLDATA (PASS, lp_pass, 0) },
{ FLDATA (INH, lp_inh, 0) },
{ FLDATA (RUNAWAY, lp_run, LPDV_V_RUN) },
{ BRDATA (CCT, lp_cct, 8, 8, CCT_LNT) },
{ DRDATA (CCTP, lp_cctp, 8), PV_LEFT },
{ DRDATA (CCTL, lp_cctl, 8), PV_LEFT + REG_HRO + REG_NZ },
{ DRDATA (POS, lp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, lp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lp_stopioe, 0) },
{ HRDATA (LASTC, lp_lastcmd, 8), REG_HIDDEN },
{ FLDATA (MODEL, lp_model, 0), REG_HRO },
{ HRDATA (DEVNO, lp_dib.dva, 12), REG_HRO },
{ NULL }
};
MTAB lp_mod[] = {
{ MTAB_XTD | MTAB_VDV, LP_7440, NULL, "7440",
&lp_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, LP_7450, NULL, "7450",
&lp_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
NULL, &lp_showtype, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "CCT",
&lp_load_cct, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ 0 }
};
DEVICE lp_dev = {
"LP", &lp_unit, lp_reg, lp_mod,
1, 10, 31, 1, 16, 8,
NULL, NULL, &lp_reset,
NULL, &lp_attach, NULL,
&lp_dib, 0
};
/* Line printer: IO dispatch routine */
uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst)
{
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = lp_tio_status (); /* get status */
if ((*dvst & DVS_DST) == 0) { /* idle? */
lp_cmd = LPS_INIT; /* start dev thread */
sim_activate (&lp_unit, chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = lp_tio_status (); /* return status */
break;
case OP_TDV: /* test status */
*dvst = lp_tdv_status (); /* return status */
break;
case OP_HIO: /* halt I/O */
chan_clr_chi (lp_dib.dva); /* clear int */
*dvst = lp_tio_status (); /* get status */
if ((*dvst & DVS_DST) != 0) { /* busy? */
sim_cancel (&lp_unit); /* stop dev thread */
chan_uen (lp_dib.dva); /* uend */
}
break;
case OP_AIO: /* acknowledge int */
chan_clr_chi (lp_dib.dva); /* clear int */
*dvst = lp_lastcmd & LPS_INT; /* int requested */
lp_lastcmd = 0;
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* Service routine */
t_stat lp_svc (UNIT *uptr)
{
uint32 cmd;
uint32 st;
switch (lp_cmd) { /* case on state */
case LPS_INIT: /* I/O init */
st = chan_get_cmd (lp_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
return lp_chan_err (st);
lp_inh = 0; /* clear inhibit, */
lp_run = 0; /* runaway */
lp_cmd = lp_lastcmd = cmd; /* save command */
sim_activate (uptr, chan_ctl_time); /* continue thread */
break;
case LPS_FMT:
case LPS_FMT|LPS_INT: /* format only */
sim_activate (uptr, uptr->wait); /* continue thread */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return lp_stopioe? SCPE_UNATT: SCPE_OK;
st = lp_fmt (uptr); /* format */
if (CHS_IFERR (st)) /* error? */
return lp_chan_err (st);
if ((lp_model == LP_7440) && /* 7440? lnt chk */
(st != CHS_ZBC) &&
chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */
return lp_chan_err (SCPE_OK); /* force uend */
lp_cmd = LPS_END; /* actual print */
break;
case LPS_FMTP:
case LPS_FMTP|LPS_INT: /* format and print */
sim_activate (uptr, uptr->wait); /* continue thread */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return lp_stopioe? SCPE_UNATT: SCPE_OK;
st = lp_fmt (uptr); /* format */
if (CHS_IFERR (st)) /* error? */
return lp_chan_err (st);
if (st == CHS_ZBC) { /* command done? */
if ((lp_model == LP_7440) && /* 7440? lnt err */
chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */
return lp_chan_err (SCPE_OK);
}
else { /* more to do */
st = lp_print (uptr); /* print */
if (CHS_IFERR (st)) /* error */
return lp_chan_err (st);
}
break;
case LPS_PRI:
case LPS_PRI|LPS_INT: /* print only */
sim_activate (uptr, uptr->wait); /* continue thread */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return lp_stopioe? SCPE_UNATT: SCPE_OK;
st = lp_print (uptr); /* print */
if (CHS_IFERR (st)) /* error? */
return lp_chan_err (st);
break;
case LPS_END: /* command done */
if ((lp_lastcmd & LPS_INT) && !lp_pass) /* int requested? */
chan_set_chi (lp_dib.dva, 0);
st = chan_end (lp_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
return lp_chan_err (st);
if (st == CHS_CCH) { /* command chain? */
lp_cmd = LPS_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time);
}
break;
default: /* invalid cmd */
chan_uen (lp_dib.dva); /* uend */
break;
}
return SCPE_OK;
}
/* Format routine */
uint32 lp_fmt (UNIT *uptr)
{
uint32 c, i;
uint32 st;
st = chan_RdMemB (lp_dib.dva, &c); /* get char */
if (CHS_IFERR (st)) /* channel error? */
return st; /* caller handles */
if (lp_pass) /* only on pass 1 */
return 0;
if ((c & 0x7F) == FMT_INH) /* inhibit? */
lp_inh = 1;
else if ((c & ~(((lp_model == LP_7450)? 0x20: 0) | SPC_MASK)) == FMT_SPC) {
c = c & SPC_MASK; /* space? */
for (i = 1; i <= c; i++) { /* look for BOF */
if (CHP (CH_BOF, lp_cct[(lp_cctp + i) % lp_cctl]))
return lp_skip (uptr, CH_TOF); /* found, TOF */
}
return lp_space (uptr, c, FALSE); /* space */
}
else if ((c & ~CCH_MASK) == FMT_SKP) /* skip? */
return lp_skip (uptr, c & CCH_MASK); /* skip to chan */
return 0;
}
/* Skip to channel */
uint32 lp_skip (UNIT *uptr, uint32 ch)
{
uint32 i;
for (i = 1; i < (lp_cctl + 1); i++) { /* sweep thru CCT */
if (CHP (ch, lp_cct[(lp_cctp + i) % lp_cctl])) /* channel punched? */
return lp_space (uptr, i, TRUE); /* space to chan */
}
lp_run = LPDV_RUN; /* runaway CCT */
return lp_space (uptr, lp_cctl, TRUE); /* space max */
}
/* Space routine */
uint32 lp_space (UNIT *uptr, uint32 cnt, t_bool skp)
{
uint32 i;
lp_cctp = (lp_cctp + cnt) % lp_cctl; /* adv cct, mod lnt */
if (skp && CHP (CH_TOF, lp_cct[lp_cctp])) /* skip, TOF? */
fputs ("\f", uptr->fileref); /* ff */
else { /* space */
for (i = 0; i < cnt; i++)
fputc ('\n', uptr->fileref);
}
uptr->pos = ftell (uptr->fileref); /* update position */
if (ferror (uptr->fileref)) { /* error? */
perror ("Line printer I/O error");
clearerr (uptr->fileref);
chan_set_chf (lp_dib.dva, CHF_XMDE);
return SCPE_IOERR;
}
return 0;
}
/* Print routine */
uint32 lp_print (UNIT *uptr)
{
uint32 i, bp, c;
uint32 max = (lp_model == LP_7440)? BUF_LNT4: BUF_LNT5;
uint32 st;
if (lp_pass == 0) { /* pass 1? clr buf */
for (i = 0; i < BUF_LNT4; i++) lp_buf[i] = ' ';
}
for (bp = 0, st = 0; (bp < max) && !st; bp++) { /* fill buffer */
st = chan_RdMemB (lp_dib.dva, &c); /* get char */
if (CHS_IFERR (st)) /* channel error? */
return st; /* caller handles */
if ((lp_model == LP_7440) || /* 7440 or */
((bp & 1) == lp_pass)) /* correct pass? */
lp_buf[bp] = lp_to_ascii[c & 0x3F];
}
if ((lp_model == LP_7440) || lp_pass) { /* ready to print? */
lp_pass = 0;
for (i = BUF_LNT4; (i > 0) && (lp_buf[i - 1] == ' '); i--) ; /* trim */
if (i) /* write line */
sim_fwrite (lp_buf, 1, i, uptr->fileref);
fputc (lp_inh? '\r': '\n', uptr->fileref); /* cr or nl */
uptr->pos = ftell (uptr->fileref); /* update position */
if (ferror (uptr->fileref)) { /* error? */
perror ("Line printer I/O error");
clearerr (uptr->fileref);
chan_set_chf (lp_dib.dva, CHF_XMDE);
return SCPE_IOERR;
}
if ((lp_model == LP_7440) && /* 7440? */
((bp != BUF_LNT4) || (st != CHS_ZBC)) && /* check lnt err */
chan_set_chf (lp_dib.dva, CHF_LNTE))
return CHS_INACTV; /* stop if asked */
}
else lp_pass = 1; /* 7450 pass 2 */
lp_cmd = LPS_END; /* end state */
return 0;
}
/* LP status routine */
uint32 lp_tio_status (void)
{
uint32 st;
st = (lp_unit.flags & UNIT_ATT)? DVS_AUTO: 0; /* auto? */
if (sim_is_active (&lp_unit)) /* busy? */
st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC));
return st;
}
uint32 lp_tdv_status (void)
{
uint32 st;
st = lp_run; /* runaway flag */
if ((lp_unit.flags & UNIT_ATT) == 0) /* fault? */
st |= (CC2 << DVT_V_CC);
if (lp_cmd == LPS_END) /* end state? */
st |= LPDV_MOV; /* printing */
if (lp_pass && (lp_model == LP_7450)) { /* 7450 pass 2? */
st |= LPDV_ODD; /* odd state */
if (lp_cmd == LPS_INIT) /* wait for cmd? */
st |= LPDV_WT2;
}
return st;
}
/* Channel error */
t_stat lp_chan_err (uint32 st)
{
sim_cancel (&lp_unit); /* stop dev thread */
chan_uen (lp_dib.dva); /* uend */
if (st < CHS_ERR)
return st;
return SCPE_OK;
}
/* Reset routine */
t_stat lp_reset (DEVICE *dptr)
{
sim_cancel (&lp_unit); /* stop dev thread */
lp_cmd = 0;
lp_lastcmd = 0;
lp_pass = 0;
lp_inh = 0;
lp_run = 0;
chan_reset_dev (lp_dib.dva); /* clr int, active */
return SCPE_OK;
}
/* Attach routine */
t_stat lp_attach (UNIT *uptr, char *cptr)
{
lp_cctp = 0; /* clear cct ptr */
lp_pass = 0;
return attach_unit (uptr, cptr);
}
/* Set carriage control tape */
t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 col, rpt, ptr, mask;
uint8 cctbuf[CCT_LNT];
t_stat r;
char cbuf[CBUFSIZE], gbuf[CBUFSIZE];
FILE *cfile;
if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG;
if ((cfile = fopen (cptr, "r")) == NULL)
return SCPE_OPENERR;
ptr = 0;
for ( ; (cptr = fgets (cbuf, CBUFSIZE, cfile)) != NULL; ) {
mask = 0;
if (*cptr == '(') { /* repeat count? */
cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
if (r != SCPE_OK)
return SCPE_FMT;
}
else rpt = 1;
while (*cptr != 0) { /* get col no's */
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
col = get_uint (gbuf, 10, FMT_MCH4, &r); /* column number */
if (r != SCPE_OK)
return SCPE_FMT;
mask = mask | (1 << col); /* set bit */
}
for ( ; rpt > 0; rpt--) { /* store vals */
if (ptr >= CCT_LNT)
return SCPE_FMT;
cctbuf[ptr++] = mask;
}
}
if (ptr == 0)
return SCPE_FMT;
lp_cctl = ptr;
lp_cctp = 0;
for (rpt = 0; rpt < lp_cctl; rpt++)
lp_cct[rpt] = cctbuf[rpt];
return SCPE_OK;
}
/* Set controller type */
t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
{
lp_model = val;
lp_reset (&lp_dev);
return SCPE_OK;
}
/* Show controller type */
t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
{
fprintf (st, lp_model? "7450": "7440");
return SCPE_OK;
}

591
sigma/sigma_map.c Normal file
View File

@@ -0,0 +1,591 @@
/* sigma_map.c: XDS Sigma memory access routines
Copyright (c) 2007, 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.
*/
#include "sigma_defs.h"
#define BVA_REG (RF_NUM << 2)
#define BPAMASK ((cpu_tab[cpu_model].pamask << 2) | 0x3)
#define NUM_MUNITS (MAXMEMSIZE / CPU_MUNIT_SIZE)
/* Sigma 8-9 memory status words */
#define S89_SR0_BADLMS 0x00800000 /* bad LMS */
#define S89_SR0_RD (S89_SR0_BADLMS)
#define S89_SR0_V_PORTS 12
#define S89_SR1_FIXED 0x50C40000 /* always 1 */
#define S89_SR1_M_MEMU 0xF /* mem unit */
#define S89_SR1_V_MEMU 24
#define S89_SR1_MARG 0x00F80000 /* margin write */
#define S89_SR1_MAROFF 2 /* offset to read */
/* 5X0 memory status words */
#define S5X0_SR0_FIXED 0x40000000
#define S5X0_SR0_BADLMS 0x00000004 /* bad LMS */
#define S5X0_SR0_RD (S5X0_SR0_BADLMS)
#define S5X0_SR0_V_PORTS 21
#define S5X0_SR1_FIXED 0xB0000000 /* fixed */
#define S5X0_SR1_M_MEMU 0x7 /* mem unit */
#define S5X0_SR1_V_MEMU 25
#define S5X0_SR1_V_SA 18 /* start addr */
#define S8
typedef struct {
uint32 width; /* item width */
uint32 dmask; /* data mask */
uint32 cmask; /* control start mask */
uint32 lnt; /* array length */
uint32 opt; /* option control */
} mmc_ctl_t;
uint16 mmc_rel[VA_NUM_PAG];
uint8 mmc_acc[VA_NUM_PAG];
uint8 mmc_wlk[PA_NUM_PAG];
uint32 mem_sr0[NUM_MUNITS];
uint32 mem_sr1[NUM_MUNITS];
mmc_ctl_t mmc_tab[8] = {
{ 0, 0, 0, 0 },
{ 2, 0x003, 0, MMC_L_CS1, CPUF_WLK }, /* map 1: 2b locks */
{ 2, 0x003, MMC_M_CS2, MMC_L_CS2, CPUF_MAP }, /* map 2: 2b access ctls */
{ 4, 0x00F, MMC_M_CS3, MMC_L_CS3, CPUF_WLK }, /* map 3: 4b locks */
{ 8, 0x0FF, MMC_M_CS4, MMC_L_CS4, CPUF_MAP }, /* map 4: 8b relocation */
{ 16, 0x7FF, MMC_M_CS5, MMC_L_CS5, CPUF_MAP }, /* map 5: 16b relocation */
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }
};
extern uint32 *R;
extern uint32 *M;
extern uint32 PSW1, PSW2, PSW4;
extern uint32 CC, PSW2_WLK;
extern uint32 stop_op;
extern uint32 cpu_model;
extern uint32 chan_num;
extern UNIT cpu_unit;
extern cpu_var_t cpu_tab[];
uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa);
uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr);
t_stat map_reset (DEVICE *dptr);
uint32 map_las (uint32 rn, uint32 bva);
/* Map data structures
map_dev map device descriptor
map_unit map units
map_reg map register list
*/
UNIT map_unit = { UDATA (NULL, 0, 0) };
REG map_reg[] = {
{ BRDATA (REL, mmc_rel, 16, 13, VA_NUM_PAG) },
{ BRDATA (ACC, mmc_acc, 16, 2, VA_NUM_PAG) },
{ BRDATA (WLK, mmc_wlk, 16, 4, PA_NUM_PAG) },
{ BRDATA (SR0, mem_sr0, 16, 32, NUM_MUNITS) },
{ BRDATA (SR1, mem_sr1, 16, 32, NUM_MUNITS) },
{ NULL }
};
DEVICE map_dev = {
"MAP", &map_unit, map_reg, NULL,
1, 16, 16, 1, 16, 32,
NULL, NULL, &map_reset,
NULL, NULL, NULL,
NULL, 0
};
/* Read and write virtual routines - per length */
uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc)
{
uint32 bpa, sc, tr;
sc = 24 - ((bva & 3) << 3);
if (bva < BVA_REG) /* register access */
*dat = (R[bva >> 2] >> sc) & BMASK;
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
*dat = (M[bpa >> 2] >> sc) & BMASK;
} /* end else memory */
return 0;
}
uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc)
{
uint32 bpa, tr;
if (bva < BVA_REG) { /* register access */
if (bva & 2)
*dat = R[bva >> 2] & HMASK;
else *dat = (R[bva >> 2] >> 16) & HMASK;
}
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
if (bva & 2)
*dat = M[bpa >> 2] & HMASK;
else *dat = (M[bpa >> 2] >> 16) & HMASK;
} /* end else memory */
return 0;
}
uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc)
{
uint32 bpa, tr;
if (bva < BVA_REG) /* register access */
*dat = R[bva >> 2];
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
*dat = M[bpa >> 2];
} /* end else memory */
return 0;
}
uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc)
{
uint32 bpa, tr;
if (bva < BVA_REG) { /* register access */
*dat = R[(bva >> 2) & ~1]; /* force alignment */
*dat1 = R[(bva >> 2) | 1];
}
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
*dat = M[(bpa >> 2) & ~1]; /* force alignment */
*dat1 = M[(bpa >> 2) | 1];
} /* end else memory */
return 0;
}
uint32 WriteB (uint32 bva, uint32 dat, uint32 acc)
{
uint32 bpa, sc, tr;
sc = 24 - ((bva & 3) << 3);
if (bva < BVA_REG) /* register access */
R[bva >> 2] = (R[bva >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc);
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
M[bpa >> 2] = (M[bpa >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc);
} /* end else memory */
PSW2 |= PSW2_RA; /* state altered */
return 0;
}
uint32 WriteH (uint32 bva, uint32 dat, uint32 acc)
{
uint32 bpa, tr;
if (bva < BVA_REG) { /* register access */
if (bva & 2)
R[bva >> 2] = (R[bva >> 2] & ~HMASK) | (dat & HMASK);
else R[bva >> 2] = (R[bva >> 2] & HMASK) | ((dat & HMASK) << 16);
} /* end if register */
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
if (bva & 2)
M[bpa >> 2] = (M[bpa >> 2] & ~HMASK) | (dat & HMASK);
else M[bpa >> 2] = (M[bpa >> 2] & HMASK) | ((dat & HMASK) << 16);
} /* end else memory */
PSW2 |= PSW2_RA; /* state altered */
return 0;
}
uint32 WriteW (uint32 bva, uint32 dat, uint32 acc)
{
uint32 bpa, tr;
if (bva < BVA_REG) /* register access */
R[bva >> 2] = dat & WMASK;
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
M[bpa >> 2] = dat & WMASK;
} /* end else memory */
PSW2 |= PSW2_RA; /* state altered */
return 0;
}
uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc)
{
uint32 bpa, tr;
if (bva < BVA_REG) { /* register access */
R[(bva >> 2) & ~1] = dat & WMASK; /* force alignment */
R[(bva >> 2) | 1] = dat1 & WMASK;
}
else { /* memory access */
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
M[(bpa >> 2) & ~1] = dat & WMASK; /* force alignment */
M[(bpa >> 2) | 1] = dat1 & WMASK;
} /* end else memory */
PSW2 |= PSW2_RA; /* state altered */
return 0;
}
/* General virtual read for instruction history */
uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt)
{
switch (lnt) { /* case on length */
case BY: /* byte */
return ReadB (bva, dat, acc);
case HW: /* halfword */
return ReadH (bva, dat, acc);
case WD: /* word */
return ReadW (bva, dat, acc);
case DW: /* doubleword first */
return ReadD (bva, dat, dat1, acc);
} /* end case length */
return SCPE_IERR;
}
/* Specialized virtual read and write word routines -
treats all addresses as memory addresses */
uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc)
{
uint32 bpa;
uint32 tr;
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
*dat = M[bpa >> 2] & WMASK;
return 0;
}
uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc)
{
uint32 bpa;
uint32 tr;
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */
return tr;
M[bpa >> 2] = dat & WMASK;
return 0;
}
/* Relocation routine */
uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa)
{
if ((acc != 0) && (PSW1 & PSW1_MM)) { /* virt, map on? */
uint32 vpag = BVA_GETPAG (bva); /* virt page num */
*bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK;
if (((PSW1 & PSW1_MS) || /* slave mode? */
(PSW2 & (PSW2_MA9|PSW2_MA5X0))) && /* master prot? */
(mmc_acc[vpag] >= acc)) /* access viol? */
return map_viol (bva, *bpa, TR_MPR);
}
else *bpa = bva; /* no, physical */
if ((acc == VW) && PSW2_WLK) { /* write check? */
uint32 ppag = BPA_GETPAG (*bpa); /* phys page num */
if (PSW2_WLK && mmc_wlk[ppag] && /* lock, key != 0 */
(PSW2_WLK != mmc_wlk[ppag])) /* lock != key? */
return map_viol (bva, *bpa, TR_WLK);
}
if (BPA_IS_NXM (*bpa)) /* memory exist? */
return TR_NXM; /* don't set TSF */
return 0;
}
/* Memory management error */
uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr)
{
uint32 vpag = BVA_GETPAG (bva); /* virt page num */
if (QCPU_S9) /* Sigma 9? */
PSW2 = (PSW2 & ~PSW2_TSF) | (vpag << PSW2_V_TSF); /* save address */
PSW4 = bva >> 2; /* 5X0 address */
if ((tr == TR_WLK) && !QCPU_5X0) /* wlock on S5-9? */
tr = TR_MPR; /* mem prot trap */
if (BPA_IS_NXM (bpa)) /* also check NXM */
tr |= TR_NXM; /* on MPR or WLK */
return tr;
}
/* Physical byte access routines */
uint32 ReadPB (uint32 ba, uint32 *wd)
{
uint32 sc;
ba = ba & BPAMASK;
if (BPA_IS_NXM (ba))
return TR_NXM;
sc = 24 - ((ba & 3) << 3);
*wd = (M[ba >> 2] >> sc) & BMASK;
return 0;
}
uint32 WritePB (uint32 ba, uint32 wd)
{
uint32 sc;
ba = ba & BPAMASK;
if (BPA_IS_NXM (ba))
return TR_NXM;
sc = 24 - ((ba & 3) << 3);
M[ba >> 2] = (M[ba >> 2] & ~(BMASK << sc)) | ((wd & BMASK) << sc);
return 0;
}
/* Physical word access routines */
uint32 ReadPW (uint32 pa, uint32 *wd)
{
pa = pa & cpu_tab[cpu_model].pamask;
if (MEM_IS_NXM (pa))
return TR_NXM;
*wd = M[pa];
return 0;
}
uint32 WritePW (uint32 pa, uint32 wd)
{
pa = pa & cpu_tab[cpu_model].pamask;
if (MEM_IS_NXM (pa))
return TR_NXM;
M[pa] = wd;
return 0;
}
/* LRA - load real address (extended memory systems only) */
uint32 map_lra (uint32 rn, uint32 IR)
{
uint32 lnt, bva, bpa, vpag, ppag;
uint32 tr;
lnt = CC >> 2; /* length */
CC = 0; /* clear */
if ((tr = Ea (IR, &bva, VR, lnt)) != 0) { /* get eff addr */
if (tr == TR_NXM) /* NXM trap? */
CC = CC1|CC2;
R[rn] = bva >> 2; /* fails */
}
else if (bva < BVA_REG) { /* reg ref? */
CC = CC1|CC2;
R[rn] = bva >> 2; /* fails */
}
else {
vpag = BVA_GETPAG (bva); /* virt page num */
bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK;
ppag = BPA_GETPAG (bpa); /* phys page num */
if (MEM_IS_NXM (bpa)) /* NXM? */
CC = CC1|CC2;
R[rn] = (QCPU_S9? (mmc_wlk[ppag] << 24): 0) | /* result */
(bpa >> lnt);
CC |= mmc_acc[vpag]; /* access prot */
}
return 0;
}
/* MMC - load memory map control */
uint32 map_mmc (uint32 rn, uint32 map)
{
uint32 tr;
uint32 wd, i, map_width, maps_per_word, map_cmask, cs;
map_width = mmc_tab[map].width; /* width in bits */
maps_per_word = 32 / map_width;
if (map != 1) /* maps 2-7? */
map_cmask = mmc_tab[map].cmask; /* std ctl mask */
else map_cmask = cpu_tab[cpu_model].mmc_cm_map1; /* model based */
if ((map_width == 0) || /* validate map */
((cpu_unit.flags & mmc_tab[map].opt) == 0) ||
((map == 3) && !QCPU_5X0) ||
((map == 5) && !QCPU_BIGM)) {
if (QCPU_S89_5X0) /* S89, 5X0 trap */
return TR_INVMMC;
return stop_op? STOP_ILLEG: 0;
}
do {
cs = (R[rn|1] >> MMC_V_CS) & map_cmask; /* ptr into map */
if ((tr = ReadW ((R[rn] << 2) & BVAMASK, &wd, VR)) != 0)
return tr;
for (i = 0; i < maps_per_word; i++) { /* loop thru word */
wd = ((wd << map_width) | (wd >> (32 - map_width))) & WMASK;
switch (map) {
case 1: case 3: /* write locks */
mmc_wlk[cs] = wd & mmc_tab[map].dmask;
break;
case 2: /* access ctls */
mmc_acc[cs] = wd & mmc_tab[map].dmask;
break;
case 4: case 5: /* relocation */
mmc_rel[cs] = wd & mmc_tab[map].dmask;
break;
};
cs = (cs + 1) % mmc_tab[map].lnt; /* incr mod lnt */
} /* end for */
R[rn] = (R[rn] + 1) & WMASK; /* incr mem ptr */
R[rn|1] = (R[rn|1] & ~(MMC_CNT | (map_cmask << MMC_V_CS))) |
(((MMC_GETCNT (R[rn|1]) - 1) & MMC_M_CNT) << MMC_V_CNT) |
((cs & map_cmask) << MMC_V_CS);
} while (MMC_GETCNT (R[rn|1]) != 0);
return SCPE_OK;
}
/* LAS instruction (reused by LMS), without condition code settings */
uint32 map_las (uint32 rn, uint32 bva)
{
uint32 opnd, tr;
if ((bva < (RF_NUM << 2)) && QCPU_5X0) /* on 5X0, reg */
ReadW (bva, &opnd, VR); /* refs ignored */
else { /* go to mem */
if ((tr = ReadMemVW (bva, &opnd, VR)) != 0) /* read word */
return tr;
if ((tr = WriteMemVW (bva, opnd | WSIGN, VW)) != 0) /* set bit */
return tr;
}
R[rn] = opnd; /* store */
return 0;
}
/* Load memory status */
uint32 map_lms (uint32 rn, uint32 bva)
{
uint32 tr, wd, low, ppag;
uint32 memu = (bva >> 2) / CPU_MUNIT_SIZE;
if (CC == 0) /* LAS */
return map_las (rn, bva);
if (CC == 1) { /* read no par */
if ((tr = ReadW (bva, &wd, PH)) != 0)
return tr;
R[rn] = wd;
for (CC = CC3; wd != 0; CC ^= CC3) { /* calc odd par */
low = wd & -((int32) wd);
wd = wd & ~low;
}
return 0;
}
ppag = BPA_GETPAG (bva); /* phys page num */
wd = mem_sr0[memu]; /* save sr0 */
if (QCPU_S89)
switch (CC) { /* Sigma 8-9 */
case 0x2: /* read bad par */
if ((tr = ReadW (bva, &wd, VR)) != 0)
return tr;
R[rn] = wd;
break;
case 0x7: /* set margins */
mem_sr1[memu] = S89_SR1_FIXED |
((memu & S89_SR1_M_MEMU) << S89_SR1_V_MEMU) |
((R[rn] & S89_SR1_MARG) >> S89_SR1_MAROFF);
break;
case 0xB: /* read sr0, clr */
mem_sr0[memu] = mem_sr1[memu] = 0;
case 0x8: /* read sr0 */
R[rn] = (wd & S89_SR0_RD) |
(((1u << (chan_num + 1)) - 1) << (S89_SR0_V_PORTS - (chan_num + 1)));
break;
case 0x9: /* read sr1 */
R[rn] = mem_sr1[memu];
break;
case 0xA: case 0xE: /* read sr2 */
R[rn] = 0;
break;
case 0xF: /* clear word */
return WriteW (bva, 0, VW);
break;
default:
mem_sr0[memu] |= S89_SR0_BADLMS;
break;
}
else switch (CC) { /* 5X0 */
case 0x2: /* clear word */
return WriteW (bva, 0, VW);
case 0x6: /* read wlk */
R[rn] = (mmc_wlk[ppag & ~1] << 4) | mmc_wlk[ppag | 1];
break;
case 0x7: /* write wlk */
mmc_wlk[ppag & ~1] = (R[rn] >> 4) & 0xF;
mmc_wlk[ppag | 1] = R[rn] & 0xF;
break;
case 0xC: /* read sr0, clr */
mem_sr0[memu] = 0;
case 0x8: /* read sr0 */
R[rn] = S5X0_SR0_FIXED | (wd & S5X0_SR0_RD) |
(((1u << (chan_num + 1)) - 1) << (S5X0_SR0_V_PORTS - (chan_num + 1)));
break;
case 0xA: /* read sr1 */
R[rn] = S5X0_SR1_FIXED |
((memu & S5X0_SR1_M_MEMU) << S5X0_SR1_V_MEMU) |
(memu << S5X0_SR1_V_SA);
break;
case 0xE: /* trash mem */
return WriteW (bva, R[rn] & ~0xFF, VW);
default:
mem_sr0[memu] |= S5X0_SR0_BADLMS;
break;
}
return 0;
}
/* Device reset */
t_stat map_reset (DEVICE *dptr)
{
uint32 i;
for (i = 0; i < VA_NUM_PAG; i++) { /* clear mmc arrays */
mmc_rel[i] = 0;
mmc_acc[i] = 0;
}
for (i = 0; i < PA_NUM_PAG; i++)
mmc_wlk[i] = 0;
return SCPE_OK;
}

645
sigma/sigma_mt.c Normal file
View File

@@ -0,0 +1,645 @@
/* sigma_mt.c: Sigma 732X 9-track magnetic tape
Copyright (c) 2007-2008, 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.
mt 7320 and 7322/7323 magnetic tape
Magnetic tapes are represented as a series of variable records
of the form:
32b byte count
byte 0
byte 1
:
byte n-2
byte n-1
32 byte count
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
*/
#include "sigma_io_defs.h"
#include "sim_tape.h"
/* Device definitions */
#define MT_NUMDR 8 /* #drives */
#define MT_REW (MT_NUMDR) /* rewind threads */
#define UST u3 /* unit status */
#define UCMD u4 /* unit command */
#define MT_MAXFR (1 << 16) /* max record lnt */
/* Unit commands */
#define MCM_INIT 0x100
#define MCM_END 0x101
#define MCM_WRITE 0x01
#define MCM_READ 0x02
#define MCM_SETC 0x03
#define MCM_SENSE 0x04
#define MCM_RDBK 0x0C
#define MCM_RWI 0x13
#define MCM_RWU 0x23
#define MCM_REW 0x33
#define MCM_SFWR 0x43
#define MCM_SBKR 0x4B
#define MCM_SFWF 0x53
#define MCM_SBKF 0x5B
#define MCM_ERS 0x63
#define MCM_WTM 0x73
/* Command flags */
#define O_ATT 0x01 /* req attached */
#define O_WRE 0x02 /* req write enb */
#define O_REV 0x04 /* reverse oper */
#define O_NMT 0x10 /* no motion */
/* Device status in UST, ^ = dynamic */
#define MTDV_OVR 0x80 /* overrun - NI */
#define MTDV_WRE 0x40 /* write enabled^ */
#define MTDV_WLE 0x20 /* write lock err */
#define MTDV_EOF 0x10 /* end of file */
#define MTDV_DTE 0x08 /* data error */
#define MTDV_BOT 0x04 /* begin of tape */
#define MTDV_EOT 0x02 /* end of tape^ */
#define MTDV_REW 0x01 /* rewinding^ */
#define MTAI_MASK (MTDV_OVR|MTDV_WLE|MTDV_EOF|MTDV_DTE)
#define MTAI_V_INT 6
#define MTAI_INT (1u << MTAI_V_INT)
uint32 mt_stopioe = 1;
int32 mt_rwtime = 10000; /* rewind latency */
int32 mt_ctime = 100; /* command latency */
int32 mt_time = 10; /* record latency */
uint32 mt_rwi = 0; /* rewind interrupts */
t_mtrlnt mt_bptr;
t_mtrlnt mt_blim;
uint8 mt_xb[MT_MAXFR]; /* transfer buffer */
uint8 mt_op[128] = {
0, O_ATT|O_WRE, O_ATT, O_NMT, O_NMT, 0, 0, 0, /* wr, rd, set, sense */
0, 0, 0, 0, O_ATT|O_REV, 0, 0, 0, /* rd rev */
0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind & int */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind offline */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd rec */
0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk rec */
0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd file */
0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk file */
0, 0, 0, O_NMT, 0, 0, 0, 0, /* set erase */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, O_ATT|O_WRE, 0, 0, 0, 0, /* write tmk */
0, 0, 0, 0, 0, 0, 0, 0
};
extern uint32 chan_ctl_time;
extern uint8 ascii_to_ebcdic[128];
extern uint8 ebcdic_to_ascii[256];
uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 mt_tio_status (uint32 un);
uint32 mt_tdv_status (uint32 un);
t_stat mt_chan_err (uint32 st);
t_stat mtu_svc (UNIT *uptr);
t_stat mtr_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_detach (UNIT *uptr);
t_stat mt_flush_buf (uptr);
t_stat mt_map_err (UNIT *uptr, t_stat r);
int32 mt_clr_int (uint32 dva);
void mt_set_rwi (uint32 un);
void mt_clr_rwi (uint32 un);
/* MT data structures
mt_dev MT device descriptor
mt_unit MT unit descriptors
mt_reg MT register list
mt_mod MT modifiers list
*/
dib_t mt_dib = { DVA_MT, mt_disp };
/* First 'n' units are tape drives; second 'n' are rewind threads */
UNIT mt_unit[] = {
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) },
{ UDATA (&mtr_svc, UNIT_DIS, 0) }
};
REG mt_reg[] = {
{ BRDATA (BUF, mt_xb, 16, 8, MT_MAXFR) },
{ DRDATA (BPTR, mt_bptr, 17) },
{ DRDATA (BLNT, mt_blim, 17) },
{ HRDATA (RWINT, mt_rwi, MT_NUMDR) },
{ DRDATA (TIME, mt_time, 24), PV_LEFT+REG_NZ },
{ DRDATA (CTIME, mt_ctime, 24), PV_LEFT+REG_NZ },
{ DRDATA (RWTIME, mt_rwtime, 24), PV_LEFT+REG_NZ },
{ URDATA (UST, mt_unit[0].UST, 16, 8, 0, MT_NUMDR, 0) },
{ URDATA (UCMD, mt_unit[0].UCMD, 16, 8, 0, 2 * MT_NUMDR, 0) },
{ URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR, PV_LEFT | REG_RO) },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ HRDATA (DEVNO, mt_dib.dva, 12), REG_HRO },
{ NULL }
};
MTAB mt_mod[] = {
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",
&sim_tape_set_capac, &sim_tape_show_capac, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ 0 }
};
DEVICE mt_dev = {
"MT", mt_unit, mt_reg, mt_mod,
MT_NUMDR * 2, 10, T_ADDR_W, 1, 16, 8,
NULL, NULL, &mt_reset,
&io_boot, &mt_attach, &mt_detach,
&mt_dib, DEV_DISABLE
};
/* Magtape: IO dispatch routine */
uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst)
{
uint32 un = DVA_GETUNIT (dva);
UNIT *uptr = &mt_unit[un];
if ((un >= MT_NUMDR) || /* inv unit num? */
(uptr-> flags & UNIT_DIS)) /* disabled unit? */
return DVT_NODEV;
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = mt_tio_status (un); /* get status */
if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */
uptr->UCMD = MCM_INIT; /* start dev thread */
sim_activate (uptr, chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = mt_tio_status (un); /* return status */
break;
case OP_TDV: /* test status */
*dvst = mt_tdv_status (un); /* return status */
break;
case OP_HIO: /* halt I/O */
*dvst = mt_tio_status (un); /* get status */
if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */
chan_clr_chi (dva); /* clear ctlr int */
if (sim_is_active (uptr)) { /* chan active? */
sim_cancel (uptr); /* stop unit */
chan_uen (dva); /* uend */
}
mt_clr_rwi (un); /* clear rewind int */
sim_cancel (uptr + MT_REW); /* cancel rewind */
break;
case OP_AIO: /* acknowledge int */
un = mt_clr_int (mt_dib.dva); /* clr int, get unit */
*dvst = (mt_tdv_status (un) & MTAI_MASK) | /* device status */
(un & MTAI_INT) | /* device int flag */
((un & DVA_M_UNIT) << DVT_V_UN); /* unit number */
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* Unit service */
t_stat mtu_svc (UNIT *uptr)
{
uint32 cmd = uptr->UCMD;
uint32 un = uptr - mt_unit;
uint32 c;
uint32 st;
int32 t;
t_mtrlnt tbc;
t_stat r;
if (cmd == MCM_INIT) { /* init state */
if ((t = sim_is_active (uptr + MT_REW)) != 0) { /* rewinding? */
sim_activate (uptr, t); /* retry later */
return SCPE_OK;
}
st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
return mt_chan_err (st);
if ((cmd & 0x80) || /* invalid cmd? */
(mt_op[cmd] == 0)) {
uptr->UCMD = MCM_END; /* end state */
sim_activate (uptr, chan_ctl_time); /* resched ctlr */
return SCPE_OK;
}
else { /* valid cmd */
if ((mt_op[cmd] & O_REV) && /* reverse op */
(mt_unit[un].UST & MTDV_BOT)) { /* at load point? */
chan_uen (mt_dib.dva); /* channel end */
return SCPE_OK;
}
uptr->UCMD = cmd; /* unit state */
if (!(mt_op[cmd] & O_NMT)) /* motion? */
uptr->UST = 0; /* clear status */
}
mt_blim = 0; /* no buffer yet */
sim_activate (uptr, chan_ctl_time); /* continue thread */
return SCPE_OK; /* done */
}
if (cmd == MCM_END) { /* end state */
st = chan_end (mt_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
return mt_chan_err (st);
if (st == CHS_CCH) { /* command chain? */
uptr->UCMD = MCM_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time);
}
else uptr->UCMD = 0; /* ctlr idle */
return SCPE_OK; /* done */
}
if ((mt_op[cmd] & O_ATT) && /* op req att and */
((uptr->flags & UNIT_ATT) == 0)) { /* not attached? */
sim_activate (uptr, mt_ctime); /* retry */
return mt_stopioe? SCPE_UNATT: SCPE_OK;
}
if ((mt_op[cmd] & O_WRE) && /* write op and */
sim_tape_wrp (uptr)) { /* write protected? */
uptr->UST |= MTDV_WLE; /* set status */
chan_uen (mt_dib.dva); /* unusual end */
return SCPE_OK;
}
r = SCPE_OK;
switch (cmd) { /* case on command */
case MCM_SFWR: /* space forward */
if (r = sim_tape_sprecf (uptr, &tbc)) /* spc rec fwd, err? */
r = mt_map_err (uptr, r); /* map error */
break;
case MCM_SBKR: /* space reverse */
if (r = sim_tape_sprecr (uptr, &tbc)) /* spc rec rev, err? */
r = mt_map_err (uptr, r); /* map error */
break;
case MCM_SFWF: /* space fwd file */
while ((r = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
if (r != MTSE_TMK) /* stopped by tmk? */
r = mt_map_err (uptr, r); /* no, map error */
else r = SCPE_OK;
break;
case MCM_SBKF: /* space rev file */
while ((r = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
if (r != MTSE_TMK) /* stopped by tmk? */
r = mt_map_err (uptr, r); /* no, map error */
else r = SCPE_OK;
break;
case MCM_WTM: /* write eof */
if (r = sim_tape_wrtmk (uptr)) /* write tmk, err? */
r = mt_map_err (uptr, r); /* map error */
uptr->UST |= MTDV_EOF; /* set eof */
break;
case MCM_RWU: /* rewind unload */
r = detach_unit (uptr);
break;
case MCM_REW: /* rewind */
case MCM_RWI: /* rewind and int */
if (r = sim_tape_rewind (uptr)) /* rewind */
r = mt_map_err (uptr, r); /* map error */
mt_unit[un + MT_REW].UCMD = uptr->UCMD; /* copy command */
sim_activate (uptr + MT_REW, mt_rwtime); /* sched compl */
break;
case MCM_READ: /* read */
if (mt_blim == 0) { /* first read? */
r = sim_tape_rdrecf (uptr, mt_xb, &mt_blim, MT_MAXFR);
if (r != MTSE_OK) { /* tape error? */
r = mt_map_err (uptr, r); /* map error */
break;
}
mt_bptr = 0; /* init rec ptr */
}
c = mt_xb[mt_bptr++]; /* get char */
st = chan_WrMemB (mt_dib.dva, c); /* write to memory */
if (CHS_IFERR (st)) /* channel error? */
return mt_chan_err (st);
if ((st != CHS_ZBC) && (mt_bptr != mt_blim)) { /* not done? */
sim_activate (uptr, mt_time); /* continue thread */
return SCPE_OK;
}
if (((st == CHS_ZBC) ^ (mt_bptr == mt_blim)) && /* length err? */
chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */
return SCPE_OK; /* finished */
break; /* normal end */
case MCM_RDBK: /* read reverse */
if (mt_blim == 0) { /* first read? */
r = sim_tape_rdrecr (uptr, mt_xb, &mt_blim, MT_MAXFR);
if (r != MTSE_OK) { /* tape error? */
r = mt_map_err (uptr, r); /* map error */
break;
}
mt_bptr = mt_blim; /* init rec ptr */
}
c = mt_xb[--mt_bptr]; /* get char */
st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */
if (CHS_IFERR (st)) /* channel error? */
return mt_chan_err (st);
if ((st != CHS_ZBC) && (mt_bptr != 0)) { /* not done? */
sim_activate (uptr, mt_time); /* continue thread */
return SCPE_OK;
}
if (((st == CHS_ZBC) ^ (mt_bptr == 0)) && /* length err? */
chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */
return SCPE_OK; /* finished */
break; /* normal end */
case MCM_WRITE: /* write */
st = chan_RdMemB (mt_dib.dva, &c); /* read char */
if (CHS_IFERR (st)) { /* channel error? */
mt_flush_buf (uptr); /* flush buffer */
return mt_chan_err (st);
}
mt_xb[mt_blim++] = c; /* store in buffer */
if (st != CHS_ZBC) { /* end record? */
sim_activate (uptr, mt_time); /* continue thread */
return SCPE_OK;
}
r = mt_flush_buf (uptr); /* flush buffer */
break;
}
if (r != SCPE_OK) /* error? abort */
return CHS_IFERR(r)? SCPE_OK: r;
uptr->UCMD = MCM_END; /* end state */
sim_activate (uptr, mt_ctime); /* sched ctlr */
return SCPE_OK;
}
/* Rewind completion - set BOT, interrupt if desired */
t_stat mtr_svc (UNIT *uptr)
{
uint32 un = uptr - mt_unit - MT_REW;
mt_unit[un].UST |= MTDV_BOT; /* set BOT */
if (uptr->UCMD == MCM_RWI) /* int wanted? */
mt_set_rwi (un); /* interrupt */
return SCPE_OK;
}
t_stat mt_flush_buf (UNIT *uptr)
{
t_stat st;
if (mt_blim == 0) /* any output? */
return SCPE_OK;
if (st = sim_tape_wrrecf (uptr, mt_xb, mt_blim)) /* write, err? */
return mt_map_err (uptr, st); /* map error */
return SCPE_OK;
}
/* Map tape error status - returns chan error or SCP status */
t_stat mt_map_err (UNIT *uptr, t_stat st)
{
int32 u = uptr - mt_dev.units;
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* not attached */
case MTSE_WRP: /* write protect */
chan_set_chf (mt_dib.dva, CHF_XMME);
case MTSE_OK: /* no error */
chan_uen (mt_dib.dva); /* uend */
return SCPE_IERR;
case MTSE_TMK: /* end of file */
uptr->UST |= MTDV_EOF; /* set eof flag */
chan_uen (mt_dib.dva); /* uend */
return CHS_INACTV;
case MTSE_IOERR: /* IO error */
uptr->UST |= MTDV_DTE; /* set DTE flag */
chan_set_chf (mt_dib.dva, CHF_XMDE);
chan_uen (mt_dib.dva); /* force uend */
return SCPE_IOERR;
case MTSE_INVRL: /* invalid rec lnt */
uptr->UST |= MTDV_DTE; /* set DTE flag */
chan_set_chf (mt_dib.dva, CHF_XMDE);
chan_uen (mt_dib.dva); /* force uend */
return SCPE_MTRLNT;
case MTSE_RECE: /* record in error */
case MTSE_EOM: /* end of medium */
uptr->UST |= MTDV_DTE; /* set DTE flag */
return chan_set_chf (mt_dib.dva, CHF_XMDE); /* possible error */
case MTSE_BOT: /* reverse into BOT */
uptr->UST |= MTDV_BOT; /* set BOT */
chan_uen (mt_dib.dva); /* uend */
return CHS_INACTV;
} /* end switch */
return SCPE_OK;
}
/* MT status routine */
uint32 mt_tio_status (uint32 un)
{
uint32 i, st;
UNIT *uptr = &mt_unit[un];
st = (uptr->flags & UNIT_ATT)? DVS_AUTO: 0; /* AUTO */
if (sim_is_active (uptr) || /* unit busy */
sim_is_active (uptr + MT_REW)) /* or rewinding? */
st |= DVS_DBUSY;
for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */
if (sim_is_active (&mt_unit[i])) { /* active? */
st |= (DVS_CBUSY | (CC2 << DVT_V_CC)); /* ctrl is busy */
}
}
return st;
}
uint32 mt_tdv_status (uint32 un)
{
uint32 st;
UNIT *uptr = &mt_unit[un];
if (uptr->flags & UNIT_ATT) { /* attached? */
st = uptr->UST; /* unit stat */
if (sim_tape_eot (uptr)) /* at EOT? */
st |= MTDV_EOT;
if (!sim_tape_wrp (uptr)) /* not wlock? */
st |= MTDV_WRE;
}
else st = (CC2 << DVT_V_CC);
if (sim_is_active (uptr + MT_REW)) /* unit rewinding? */
st |= (MTDV_REW | (CC2 << DVT_V_CC));
return st;
}
/* Channel error */
t_stat mt_chan_err (uint32 st)
{
chan_uen (mt_dib.dva); /* uend */
if (st < CHS_ERR)
return st;
return SCPE_OK;
}
/* Clear controller/device interrupt, return active unit */
int32 mt_clr_int (uint32 dva)
{
int32 iu;
if ((iu = chan_clr_chi (dva)) >= 0) { /* chan int? clear */
if (mt_rwi != 0) /* dev ints? */
chan_set_dvi (dva); /* set them */
return iu;
}
for (iu = 0; iu < MT_NUMDR; iu++) { /* rewind int? */
if (mt_rwi & (1u << iu)) {
mt_clr_rwi ((uint32) iu);
return (iu | MTAI_INT);
}
}
return 0;
}
/* Set rewind interrupt */
void mt_set_rwi (uint32 un)
{
mt_rwi |= (1u << un);
chan_set_dvi (mt_dib.dva); /* set INP */
return;
}
/* Clear rewind interrupt */
void mt_clr_rwi (uint32 un)
{
mt_rwi &= ~(1u << un); /* clear */
if (mt_rwi != 0) /* more? */
chan_set_dvi (mt_dib.dva);
else if (chan_chk_chi (mt_dib.dva) < 0) /* any int? */
chan_clr_chi (mt_dib.dva); /* clr INP */
return;
}
/* Reset routine */
t_stat mt_reset (DEVICE *dptr)
{
uint32 i;
for (i = 0; i < MT_NUMDR; i++) {
sim_cancel (&mt_unit[i]); /* stop unit */
sim_cancel (&mt_unit[i + MT_REW]); /* stop rewind */
mt_unit[i].UST = 0;
mt_unit[i].UCMD = 0;
}
mt_rwi = 0;
mt_bptr = 0;
mt_blim = 0;
chan_reset_dev (mt_dib.dva); /* clr int, active */
for (i = 0; i < MT_MAXFR; i++)
mt_xb[i] = 0;
return SCPE_OK;
}
/* Attach routine */
t_stat mt_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK) return r;
uptr->UST = MTDV_BOT;
return r;
}
/* Detach routine */
t_stat mt_detach (UNIT* uptr)
{
uint32 un = uptr - mt_dev.units;
uptr->UST = 0;
sim_cancel (uptr + MT_REW);
return sim_tape_detach (uptr);
}

297
sigma/sigma_pt.c Normal file
View File

@@ -0,0 +1,297 @@
/* sigma_pt.c: Sigma 7060 paper tape reader/punch
Copyright (c) 2007-2008, 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.
pt 7060 paper-tape reader/punch
*/
#include "sigma_io_defs.h"
/* Device definitions */
#define PTR 0
#define PTP 1
/* Device states */
#define PTS_INIT 0x101
#define PTS_END 0x102
#define PTS_WRITE 0x1
#define PTS_READ 0x2
#define PTS_READI 0x82
/* Device status */
#define PTDV_PMAN 0x20
#define PTDV_RMAN 0x10
uint32 pt_cmd = 0;
uint32 ptr_nzc = 0;
uint32 ptr_stopioe = 1;
uint32 ptp_stopioe = 1;
extern uint32 chan_ctl_time;
extern uint8 ascii_to_ebcdic[128];
extern uint8 ebcdic_to_ascii[256];
uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 pt_tio_status (void);
uint32 pt_tdv_status (void);
t_stat pt_chan_err (uint32 st);
t_stat pt_svc (UNIT *uptr);
t_stat pt_reset (DEVICE *dptr);
t_stat pt_attach (UNIT *uptr, char *cptr);
/* PT data structures
pt_dev PT device descriptor
pt_unit PT unit descriptors
pt_reg PT register list
pt_mod PT modifiers list
*/
dib_t pt_dib = { DVA_PT, pt_disp };
UNIT pt_unit[] = {
{ UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE, 0), SERIAL_IN_WAIT },
{ UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT }
};
REG pt_reg[] = {
{ HRDATA (CMD, pt_cmd, 9) },
{ FLDATA (NZC, ptr_nzc,0) },
{ DRDATA (RPOS, pt_unit[PTR].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (RTIME, pt_unit[PTR].wait, 24), PV_LEFT },
{ FLDATA (RSTOP_IOE, ptr_stopioe, 0) },
{ DRDATA (PPOS, pt_unit[PTP].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (PTIME, pt_unit[PTP].wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (PSTOP_IOE, ptp_stopioe, 0) },
{ HRDATA (DEVNO, pt_dib.dva, 12), REG_HRO },
{ NULL }
};
MTAB pt_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ 0 }
};
DEVICE pt_dev = {
"PT", pt_unit, pt_reg, pt_mod,
2, 10, 31, 1, 16, 8,
NULL, NULL, &pt_reset,
&io_boot, &pt_attach, NULL,
&pt_dib, DEV_DISABLE
};
/* Reader/punch: IO dispatch routine */
uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst)
{
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = pt_tio_status (); /* get status */
if ((*dvst & DVS_DST) == 0) { /* idle? */
pt_cmd = PTS_INIT; /* start dev thread */
sim_activate (&pt_unit[PTR], chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = pt_tio_status (); /* return status */
break;
case OP_TDV: /* test status */
*dvst = pt_tdv_status (); /* return status */
break;
case OP_HIO: /* halt I/O */
chan_clr_chi (pt_dib.dva); /* clr int*/
*dvst = pt_tio_status (); /* get status */
if ((*dvst & DVS_DST) != 0) { /* busy? */
sim_cancel (&pt_unit[PTR]); /* stop dev thread */
chan_uen (pt_dib.dva); /* uend */
}
break;
case OP_AIO: /* acknowledge int */
chan_clr_chi (pt_dib.dva); /* clr int*/
*dvst = 0; /* no status */
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* Service routine */
t_stat pt_svc (UNIT *uptr)
{
int32 c;
uint32 cmd;
uint32 st;
switch (pt_cmd) { /* case on state */
case PTS_INIT: /* I/O init */
st = chan_get_cmd (pt_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
return pt_chan_err (st);
if ((cmd == PTS_WRITE) || /* valid command? */
((cmd & 0x7F) == PTS_READ))
pt_cmd = cmd; /* next state */
else pt_cmd = PTS_END; /* no, end state */
sim_activate (uptr, chan_ctl_time); /* continue thread */
break;
case PTS_READ:
case PTS_READI:
sim_activate (uptr, uptr->wait); /* continue thread */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return ptr_stopioe? SCPE_UNATT: SCPE_OK;
if ((c = getc (uptr->fileref)) == EOF) { /* read char */
if (feof (uptr->fileref)) { /* end of file? */
chan_set_chf (pt_dib.dva, CHF_LNTE); /* length error */
pt_cmd = PTS_END; /* end state */
break;
}
else { /* real error */
perror ("PTR I/O error");
clearerr (uptr->fileref);
chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */
return pt_chan_err (SCPE_IOERR); /* force uend */
}
}
uptr->pos = uptr->pos + 1;
if (c != 0) /* leader done? */
ptr_nzc = 1; /* set flag */
if ((pt_cmd == PTS_READI) || ptr_nzc) {
st = chan_WrMemB (pt_dib.dva, c); /* write to memory */
if (CHS_IFERR (st)) /* channel error? */
return pt_chan_err (st);
if (st == CHS_ZBC) /* bc == 0? */
pt_cmd = PTS_END; /* end state */
}
break;
case PTS_WRITE: /* write */
sim_activate (uptr, pt_unit[PTP].wait); /* continue thread */
if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* not attached? */
return ptp_stopioe? SCPE_UNATT: SCPE_OK;
st = chan_RdMemB (pt_dib.dva, &c); /* read from channel */
if (CHS_IFERR (st)) /* channel error? */
return pt_chan_err (st);
if (putc (c, pt_unit[PTP].fileref) == EOF) {
perror ("PTP I/O error");
clearerr (pt_unit[PTP].fileref);
chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */
return pt_chan_err (SCPE_IOERR); /* force uend */
}
pt_unit[PTP].pos = pt_unit[PTP].pos + 1;
if (st == CHS_ZBC) /* bc == 0? */
pt_cmd = PTS_END; /* end state */
break;
case PTS_END: /* command done */
st = chan_end (pt_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
return pt_chan_err (st);
if (st == CHS_CCH) { /* command chain? */
pt_cmd = PTS_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time);
}
break;
}
return SCPE_OK;
}
/* PT status routine */
uint32 pt_tio_status (void)
{
uint32 st;
if (((pt_unit[PTR].flags & UNIT_ATT) == 0) || /* rdr not att? */
((pt_unit[PTP].flags & UNIT_ATT) == 0)) /* pun not att? */
st = 0;
else st = DVS_AUTO; /* otherwise ok */
if (sim_is_active (&pt_unit[PTR])) /* dev busy? */
st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC));
return st;
}
uint32 pt_tdv_status (void)
{
uint32 st;
st = 0;
if ((pt_unit[PTR].flags & UNIT_ATT) == 0) /* rdr not att? */
st |= PTDV_RMAN;
if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* pun not att? */
st |= PTDV_PMAN;
return st;
}
/* Channel error */
t_stat pt_chan_err (uint32 st)
{
sim_cancel (&pt_unit[PTR]); /* stop dev thread */
chan_uen (pt_dib.dva); /* uend */
if (st < CHS_ERR)
return st;
return SCPE_OK;
}
/* Reset routine */
t_stat pt_reset (DEVICE *dptr)
{
sim_cancel (&pt_unit[PTR]); /* stop dev thread */
pt_cmd = 0;
chan_reset_dev (pt_dib.dva); /* clr int, active */
return SCPE_OK;
}
/* Attach routine */
t_stat pt_attach (UNIT *uptr, char *cptr)
{
t_stat st;
st = attach_unit (uptr, cptr);
if ((uptr == &pt_unit[PTR]) && (st == SCPE_OK))
ptr_nzc = 0;
return st;
}

532
sigma/sigma_rad.c Normal file
View File

@@ -0,0 +1,532 @@
/* sigma_rad.c: Sigma 7211/7212 or 7231/7232 fixed head disk simulator
Copyright (c) 2007-2008, 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.
rad 7211/7212 or 7231/7232 fixed head disk
The RAD is a head-per-track disk. To minimize overhead, the entire RAD
is buffered in memory.
Transfers are always done a sector at a time.
*/
#include "sigma_io_defs.h"
#include <math.h>
/* Constants */
#define RAD_7212 0 /* ctlr type */
#define RAD_7232 1
#define RAD_NUMDR 4 /* drives/ctlr */
#define RAD_WDSC 256 /* words/sector */
#define RAD_WDMASK (RAD_WDSC - 1)
#define RAD_SCTK1 82 /* sectors/track */
#define RAD_SCTK3 12
#define RAD_TKUN1 64 /* tracks/unit */
#define RAD_TKUN3 512
#define RAD_WDUNDF (RAD_WDSC*RAD_SCTK1*RAD_TKUN1) /* dflt words/unit */
#define RAD_WDUN (RAD_WDSC*rad_tab[rad_model].sctk*rad_tab[rad_model].tkun)
#define RAD_N_WLK 16 /* num wlk switches */
/* Address bytes */
#define RADA_V_TK1 7 /* track offset */
#define RADA_M_TK1 0xFF
#define RADA_V_SC1 0 /* sector offset */
#define RADA_M_SC1 0x7F
#define RADA_V_TK3 4
#define RADA_M_TK3 0x3FF
#define RADA_V_SC3 0
#define RADA_M_SC3 0xF
#define RADA_GETTK(x) (((x) >> rad_tab[rad_model].tk_v) & rad_tab[rad_model].tk_m)
#define RADA_GETSC(x) (((x) >> rad_tab[rad_model].sc_v) & rad_tab[rad_model].sc_m)
/* Address bad flag */
#define RADA_INV 0x80
/* Status byte 3 is current sector */
/* Status byte 4 (7212 only) is failing sector */
#define RADS_NBY1 4 /* num status bytes */
#define RADS_NBY3 3
/* Device state */
#define RADS_INIT 0x101
#define RADS_END 0x102
#define RADS_WRITE 0x01
#define RADS_READ 0x02
#define RADS_SEEK 0x03
#define RADS_SENSE 0x04
#define RADS_CHECK 0x05
#define RADS_RDEES 0x12
/* Device status */
#define RADV_OVR 0x80 /* overrun - NI */
#define RADV_BADS 0x20 /* bad sector */
#define RADV_WPE 0x10
#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * RAD_WDSC)), \
((double) rad_tab[rad_model].sctk)))
/* Model table */
typedef struct {
uint32 tk_v; /* track extract */
uint32 tk_m;
uint32 sc_v; /* sector extract */
uint32 sc_m;
uint32 sctk; /* sectors/track */
uint32 tkun; /* tracks/unit */
uint32 nbys; /* bytes of status */
} rad_t;
static rad_t rad_tab[] = {
{ RADA_V_TK1, RADA_M_TK1, RADA_V_SC1, RADA_M_SC1, RAD_SCTK1, RAD_TKUN1, RADS_NBY1 },
{ RADA_V_TK3, RADA_M_TK3, RADA_V_SC3, RADA_M_SC3, RAD_SCTK3, RAD_TKUN3, RADS_NBY3 }
};
uint32 rad_model = RAD_7212; /* model */
uint32 rad_cmd = 0; /* state */
uint32 rad_flags = 0; /* status flags */
uint32 rad_ad = 0; /* rad address */
uint32 rad_wlk = 0; /* write lock */
uint32 rad_time = 2; /* inter-word time */
extern uint32 chan_ctl_time;
uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 rad_tio_status (uint32 un);
uint32 rad_tdv_status (uint32 un);
t_stat rad_chan_err (uint32 st);
t_stat rad_svc (UNIT *uptr);
t_stat rad_reset (DEVICE *dptr);
t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
t_bool rad_inv_ad (uint32 *da);
t_bool rad_inc_ad (void);
t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st);
/* RAD data structures
rad_dev RAD device descriptor
rad_unit RAD unit descriptor
rad_reg RAD register list
*/
dib_t rad_dib = { DVA_RAD, &rad_disp };
UNIT rad_unit[] = {
{ UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE, RAD_WDUNDF) },
{ UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) },
{ UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) },
{ UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) }
};
REG rad_reg[] = {
{ HRDATA (CMD, rad_cmd, 9) },
{ HRDATA (FLAGS, rad_flags, 8) },
{ HRDATA (ADDR, rad_ad, 15) },
{ HRDATA (WLK, rad_wlk, RAD_N_WLK) },
{ DRDATA (TIME, rad_time, 24), PV_LEFT },
{ FLDATA (MODEL, rad_model, 0), REG_HRO },
{ HRDATA (DEVNO, rad_dib.dva, 12), REG_HRO },
{ NULL }
};
MTAB rad_mod[] = {
{ MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7211",
&rad_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7212",
&rad_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7231",
&rad_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7232",
&rad_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
NULL, &rad_showtype, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ 0 }
};
DEVICE rad_dev = {
"RAD", rad_unit, rad_reg, rad_mod,
RAD_NUMDR, 16, 21, 1, 16, 32,
NULL, NULL, &rad_reset,
&io_boot, NULL, NULL,
&rad_dib, DEV_DISABLE
};
/* RAD: IO dispatch routine */
uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst)
{
uint32 i;
uint32 un = DVA_GETUNIT (dva);
UNIT *uptr;
if ((un >= RAD_NUMDR) || /* inv unit num? */
(rad_unit[un].flags & UNIT_DIS)) /* disabled unit? */
return DVT_NODEV;
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = rad_tio_status (un); /* get status */
if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */
rad_cmd = RADS_INIT; /* start dev thread */
sim_activate (&rad_unit[un], chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = rad_tio_status (un); /* return status */
break;
case OP_TDV: /* test status */
*dvst = rad_tdv_status (un); /* return status */
break;
case OP_HIO: /* halt I/O */
chan_clr_chi (rad_dib.dva); /* clr int*/
*dvst = rad_tio_status (un); /* get status */
if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */
for (i = 0; i < RAD_NUMDR; i++) { /* find busy unit */
uptr = &rad_unit[i];
if (sim_is_active (uptr)) { /* active? */
sim_cancel (uptr); /* stop */
chan_uen (rad_dib.dva); /* uend */
} /* end if active */
} /* end for */
}
break;
case OP_AIO: /* acknowledge int */
chan_clr_chi (rad_dib.dva); /* clr int */
*dvst = rad_tdv_status (0); /* status like TDV */
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* Unit service - this code assumes the entire disk is buffered */
t_stat rad_svc (UNIT *uptr)
{
uint32 i, sc, da, cmd, wd, wd1, c[4], gp;
uint32 *fbuf = (uint32 *) uptr->filebuf;
uint32 st;
int32 t;
switch (rad_cmd) {
case RADS_INIT: /* init state */
st = chan_get_cmd (rad_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
return rad_chan_err (st);
if ((cmd == 0) || /* invalid cmd? */
((cmd > RADS_CHECK) && (cmd != RADS_RDEES))) {
chan_uen (rad_dib.dva); /* uend */
return SCPE_OK;
}
rad_flags = 0; /* clear status */
rad_cmd = cmd & 0x7; /* next state */
if ((cmd == RADS_SEEK) || (cmd == RADS_SENSE)) /* seek or sense? */
sim_activate (uptr, chan_ctl_time); /* schedule soon */
else { /* data transfer */
sc = RADA_GETSC (rad_ad); /* new sector */
t = sc - GET_PSC (rad_time); /* delta to new */
if (t < 0) /* wrap around? */
t = t + rad_tab[rad_model].sctk;
sim_activate (uptr, t * rad_time * RAD_WDSC); /* schedule op */
}
return SCPE_OK;
case RADS_END: /* end state */
st = chan_end (rad_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
return rad_chan_err (st);
if (st == CHS_CCH) { /* command chain? */
rad_cmd = RADS_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time);
}
return SCPE_OK; /* done */
case RADS_SEEK: /* seek */
c[0] = c[1] = 0;
for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) {
st = chan_RdMemB (rad_dib.dva, &c[i]); /* get byte */
if (CHS_IFERR (st)) /* channel error? */
return rad_chan_err (st);
}
rad_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */
if (((i != 2) || (st != CHS_ZBC)) && /* length error? */
chan_set_chf (rad_dib.dva, CHF_LNTE)) /* care? */
return SCPE_OK;
break;
case RADS_SENSE: /* sense */
c[0] = ((rad_ad >> 8) & 0x7F) | (rad_inv_ad (NULL)? RADA_INV: 0);
c[1] = rad_ad & 0xFF; /* address */
c[2] = GET_PSC (rad_time); /* curr sector */
c[3] = 0;
for (i = 0, st = 0; (i < rad_tab[rad_model].nbys) && (st != CHS_ZBC); i++) {
st = chan_WrMemB (rad_dib.dva, c[i]); /* store char */
if (CHS_IFERR (st)) /* channel error? */
return rad_chan_err (st);
}
if (((i != rad_tab[rad_model].nbys) || (st != CHS_ZBC)) &&
chan_set_chf (rad_dib.dva, CHF_LNTE)) /* length error? */
return SCPE_OK;
break;
case RADS_WRITE: /* write */
gp = (RADA_GETSC (rad_ad) * RAD_N_WLK) / /* write lock group */
rad_tab[rad_model].tkun;
if ((rad_wlk >> gp) & 1) { /* write lock set? */
rad_flags |= RADV_WPE; /* set status */
chan_uen (rad_dib.dva); /* uend */
return SCPE_OK;
} /* fall through */
if (rad_inv_ad (&da)) { /* invalid addr? */
chan_uen (rad_dib.dva); /* uend */
return SCPE_OK;
}
for (i = 0, st = 0; i < RAD_WDSC; da++, i++) { /* write */
if (st != CHS_ZBC) { /* chan active? */
st = chan_RdMemW (rad_dib.dva, &wd); /* get data */
if (CHS_IFERR (st)) { /* channel error? */
rad_inc_ad (); /* da increments */
return rad_chan_err (st);
}
}
else wd = 0;
fbuf[da] = wd; /* store in buffer */
if (da >= uptr->hwmark) /* update length */
uptr->hwmark = da + 1;
}
if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */
return SCPE_OK;
break;
/* Must be done by bytes to get precise miscompare */
case RADS_CHECK: /* write check */
if (rad_inv_ad (&da)) { /* invalid addr? */
chan_uen (rad_dib.dva); /* uend */
return SCPE_OK;
}
for (i = 0, st = 0; (i < (RAD_WDSC * 4)) && (st != CHS_ZBC); ) {
st = chan_RdMemB (rad_dib.dva, &wd); /* read sector */
if (CHS_IFERR (st)) { /* channel error? */
rad_inc_ad (); /* da increments */
return rad_chan_err (st);
}
wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */
if (wd != wd1) { /* check error? */
rad_inc_ad (); /* da increments */
chan_set_chf (rad_dib.dva, CHF_XMDE); /* set xmt err flag */
chan_uen (rad_dib.dva); /* force uend */
return SCPE_OK;
}
da = da + ((++i % 4) == 0); /* every 4th byte */
}
if (rad_end_sec (uptr, i, RAD_WDSC * 4, st)) /* transfer done? */
return SCPE_OK;
break;
case RADS_READ: /* read */
if (rad_inv_ad (&da)) { /* invalid addr? */
chan_uen (rad_dib.dva); /* uend */
return SCPE_OK;
}
for (i = 0, st = 0; (i < RAD_WDSC) && (st != CHS_ZBC); da++, i++) {
st = chan_WrMemW (rad_dib.dva, fbuf[da]); /* store in mem */
if (CHS_IFERR (st)) { /* channel error? */
rad_inc_ad (); /* da increments */
return rad_chan_err (st);
}
}
if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */
return SCPE_OK;
break;
}
rad_cmd = RADS_END; /* op done, next state */
sim_activate (uptr, chan_ctl_time);
return SCPE_OK;
}
/* Common read/write sector end routine
case 1 - more to transfer, not end disk - reschedule, return TRUE
case 2 - more to transfer, end disk - uend, return TRUE
case 3 - transfer done, length error - uend, return TRUE
case 4 - transfer done, no length error - return FALSE (sched end state)
*/
t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st)
{
if (st != CHS_ZBC) { /* end record? */
if (rad_inc_ad ()) /* inc addr, ovf? */
chan_uen (rad_dib.dva); /* uend */
else sim_activate (uptr, rad_time * 16); /* no, next sector */
return TRUE;
}
rad_inc_ad (); /* just incr addr */
if ((lnt != exp) && /* length error? */
chan_set_chf (rad_dib.dva, CHF_LNTE)) /* do we care? */
return TRUE;
return FALSE; /* cmd done */
}
/* RAD status routine */
uint32 rad_tio_status (uint32 un)
{
uint32 i, st;
st = DVS_AUTO; /* flags */
if (sim_is_active (&rad_unit[un])) /* active => busy */
st |= DVS_DBUSY;
else if ((rad_unit[un].flags & UNIT_ATT) == 0) /* not att => offl */
st |= DVS_DOFFL;
for (i = 0; i < RAD_NUMDR; i++) { /* loop thru units */
if (sim_is_active (&rad_unit[i])) { /* active? */
st |= (DVS_CBUSY |(CC2 << DVT_V_CC)); /* ctrl is busy */
return st;
}
}
return st;
}
uint32 rad_tdv_status (uint32 un)
{
uint32 st;
st = rad_flags;
if (rad_inv_ad (NULL)) /* bad address? */
st |= RADV_BADS;
return st;
}
/* Validate disk address */
t_bool rad_inv_ad (uint32 *da)
{
uint32 tk = RADA_GETTK (rad_ad);
uint32 sc = RADA_GETSC (rad_ad);
if ((tk >= rad_tab[rad_model].tkun) || /* bad sec or trk? */
(sc >= rad_tab[rad_model].sctk)) {
return TRUE;
}
if (da) /* return word addr */
*da = ((tk * rad_tab[rad_model].sctk) + sc) * RAD_WDSC;
return FALSE;
}
/* Increment disk address */
t_bool rad_inc_ad (void)
{
uint32 tk = RADA_GETTK (rad_ad);
uint32 sc = RADA_GETSC (rad_ad);
sc = sc + 1; /* sector++ */
if (sc >= rad_tab[rad_model].sctk) { /* overflow? */
sc = 0; /* wrap sector */
tk = tk + 1; /* track++ */
}
rad_ad = ((tk << rad_tab[rad_model].tk_v) | /* rebuild rad_ad */
(sc << rad_tab[rad_model].sc_v));
if (tk >= rad_tab[rad_model].tkun) /* overflow? */
return TRUE;
return FALSE;
}
/* Channel error */
t_stat rad_chan_err (uint32 st)
{
chan_uen (rad_dib.dva); /* uend */
if (st < CHS_ERR)
return st;
return SCPE_OK;
}
/* Reset routine */
t_stat rad_reset (DEVICE *dptr)
{
uint32 i;
for (i = 0; i < RAD_NUMDR; i++)
sim_cancel (&rad_unit[i]); /* stop dev thread */
rad_cmd = 0;
rad_flags = 0;
rad_ad = 0;
chan_reset_dev (rad_dib.dva); /* clr int, active */
return SCPE_OK;
}
/* Set controller type */
t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i;
for (i = 0; i < RAD_NUMDR; i++) { /* all units unatt? */
if (rad_unit[i].flags & UNIT_ATT)
return SCPE_ALATT;
}
rad_model = val; /* update model */
rad_reset (&rad_dev); /* reset */
for (i = 0; i < RAD_NUMDR; i++) /* update capacity */
rad_unit[i].capac = RAD_WDUN;
return SCPE_OK;
}
/* Show controller type */
t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
{
fprintf (st, (rad_model == RAD_7212)? "7211/7212": "7231/7232");
return SCPE_OK;
}

267
sigma/sigma_rtc.c Normal file
View File

@@ -0,0 +1,267 @@
/* sigma_rtc.c: Sigma clocks
Copyright (c) 2007, 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.
rtc clocks
The real-time clock includes an internal scheduler for events which need to
be driven at multiples of the clock frequency, such as console and multiplexor
polling. Other devices can "register" with the clock module to receive service
callbacks at a timed interval. This replaces the standard SimH event queue
mechanism for real-time synchronous events.
*/
#include "sigma_io_defs.h"
#define RTC_HZ_BASE 500
#define RTC_TICKS_DFLT 500
/* Timed events data structures */
uint8 rtc_indx[RTC_NUM_EVNTS]; /* index into rtc_tab */
uint8 rtc_cntr[RTC_NUM_EVNTS]; /* timer ticks left */
uint8 rtc_xtra[RTC_NUM_EVNTS]; /* extra counter */
UNIT *rtc_usrv[RTC_NUM_EVNTS]; /* unit servers */
/* Real-time clock counter frequencies */
uint16 rtc_tps[RTC_NUM_CNTRS] = {
RTC_HZ_OFF, RTC_HZ_OFF, RTC_HZ_500, RTC_HZ_500
};
/* Frequency descriptors. The base clock runs at 500Hz. To get submultiples,
an event uses a tick counter. If the frequency is not an even submultiple, the
event can specify an "extra" counter. Every "extra" ticks of the event counter,
the event counter is increased by one. Thus, 60Hz counts as 8-8-9, providing
3 clock ticks for every 25 base timer ticks. */
typedef struct {
uint32 hz;
uint32 cntr_reset;
uint32 xtra_reset;
} rtcdef_t;
static rtcdef_t rtc_tab[RTC_NUM_HZ] = {
{ 0, 0, 0 },
{ 500, 1, 0 },
{ 50, 10, 0 },
{ 60, 8, 3 },
{ 100, 5, 0 },
{ 2, 250, 0 },
};
t_stat rtc_svc (UNIT *uptr);
t_stat rtc_cntr_svc (UNIT *uptr);
t_stat rtc_reset (DEVICE *dptr);
t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc);
/* Clock data structures
rtc_dev RTC device descriptor
rtc_unit RTC unit
rtc_reg RTC register list
*/
UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), RTC_TICKS_DFLT };
UNIT rtc_cntr_unit[RTC_NUM_CNTRS] = {
{ UDATA (&rtc_cntr_svc, 0, 0) },
{ UDATA (&rtc_cntr_svc, 0, 0) },
{ UDATA (&rtc_cntr_svc, 0, 0) },
{ UDATA (&rtc_cntr_svc, 0, 0) }
};
REG rtc_reg[] = {
{ BRDATA (TPS, rtc_tps, 10, 10, RTC_NUM_CNTRS), REG_HRO },
{ BRDATA (INDX, rtc_indx, 10, 4, RTC_NUM_EVNTS), REG_HRO },
{ BRDATA (CNTR, rtc_cntr, 10, 6, RTC_NUM_EVNTS), REG_HRO },
{ BRDATA (XTRA, rtc_xtra, 10, 6, RTC_NUM_EVNTS), REG_HRO },
{ NULL }
};
MTAB rtc_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C1, "C1", "C1",
&rtc_set_tps, &rtc_show_tps, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C2, "C2", "C2",
&rtc_set_tps, &rtc_show_tps, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C3, "C3", "C3",
&rtc_set_tps, &rtc_show_tps, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C4, "C4", NULL,
NULL, &rtc_show_tps, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "EVENTS", NULL,
NULL, &rtc_show_events, NULL },
{ 0 }
};
DEVICE rtc_dev = {
"RTC", &rtc_unit, rtc_reg, rtc_mod,
1, 16, 8, 1, 16, 8,
NULL, NULL, &rtc_reset,
NULL, NULL, NULL
};
/* Master timer service routine */
t_stat rtc_svc (UNIT *uptr)
{
uint32 i, idx;
int32 t;
t_stat st;
t = sim_rtcn_calb (RTC_HZ_BASE, TMR_RTC); /* calibrate clock */
sim_activate (uptr, t); /* reactivate unit */
for (i = 0; i < RTC_NUM_EVNTS; i++) { /* loop thru events */
if (rtc_cntr[i] != 0) { /* event active? */
rtc_cntr[i] = rtc_cntr[i] - 1; /* decrement */
if (rtc_cntr[i] == 0) { /* expired? */
idx = rtc_indx[i];
rtc_cntr[i] = rtc_tab[idx].cntr_reset; /* reset counter */
if (rtc_xtra[i] != 0) { /* fudge factor? */
rtc_xtra[i] = rtc_xtra[i] - 1; /* decr fudge cntr */
if (rtc_xtra[i] == 0) { /* expired? */
rtc_cntr[i]++; /* extra tick */
rtc_xtra[i] = rtc_tab[idx].xtra_reset; /* reset fudge cntr */
} /* end fudge = 0 */
} /* end fudge active */
if ((rtc_usrv[i] == NULL) || /* registered? */
(rtc_usrv[i]->action == NULL))
return SCPE_IERR; /* should be */
st = rtc_usrv[i]->action (rtc_usrv[i]); /* callback */
if (st != SCPE_OK) /* error */
return st;
} /* end cntr = 0 */
} /* end event active */
} /* end event loop */
return SCPE_OK;
}
/* Callback for a system timer */
t_stat rtc_cntr_svc (UNIT *uptr)
{
uint32 cn = uptr - rtc_cntr_unit;
io_sclr_req (INTV (INTG_OVR, cn), 1); /* set cntr intr */
return SCPE_OK;
}
/* Register a timer */
t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr)
{
if ((tm >= RTC_NUM_EVNTS) || /* validate params */
(idx >= RTC_NUM_HZ) ||
(uptr == NULL) ||
(uptr->action == NULL))
return SCPE_IERR;
rtc_usrv[tm] = uptr;
rtc_indx[tm] = idx;
rtc_cntr[tm] = rtc_tab[idx].cntr_reset; /* init event */
rtc_xtra[tm] = rtc_tab[idx].xtra_reset;
return SCPE_OK;
}
/* Set timer ticks */
t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 newval, i;
t_stat r;
if (val >= RTC_NUM_EVNTS) /* validate params */
return SCPE_IERR;
if (cptr == NULL) /* must have arg */
return SCPE_ARG;
newval = get_uint (cptr, 10, 10000, &r);
if ((r != SCPE_OK) || /* error? */
((newval == 0) && (val >= 2))) /* can't turn off 3,4 */
return SCPE_ARG;
for (i = 0; i < RTC_NUM_HZ; i++) { /* loop thru freqs */
if (newval == rtc_tab[i].hz) { /* found freq? */
rtc_tps[val] = i;
rtc_indx[val] = i; /* save event vals */
rtc_cntr[val] = rtc_tab[i].cntr_reset;
rtc_xtra[val] = rtc_tab[i].xtra_reset;
return SCPE_OK;
}
}
return SCPE_ARG;
}
/* Show timer ticks */
t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc)
{
uint32 idx;
if (val >= RTC_NUM_EVNTS)
return SCPE_IERR;
idx = rtc_tps[val]; /* ptr to clk defs */
if (rtc_tab[idx].hz == 0)
fprintf (of, "off\n");
else fprintf (of, "%dHz\n", rtc_tab[idx].hz);
return SCPE_OK;
}
/* Reset routine */
t_stat rtc_reset (DEVICE *dptr)
{
uint32 i;
sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* init base clock */
sim_activate_abs (&rtc_unit, rtc_unit.wait); /* activate unit */
for (i = 0; i < RTC_NUM_EVNTS; i++) { /* clear counters */
if (i < RTC_NUM_CNTRS) {
rtc_cntr[i] = 0;
rtc_xtra[i] = 0;
rtc_indx[i] = 0;
rtc_usrv[i] = NULL;
if (rtc_register (i, rtc_tps[i], &rtc_cntr_unit[i]) != SCPE_OK)
return SCPE_IERR;
}
else if ((rtc_usrv[i] != NULL) &&
(rtc_register (i, rtc_indx[i], rtc_usrv[i]) != SCPE_OK))
return SCPE_IERR;
}
return SCPE_OK;
}
/* Show events */
t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc)
{
uint32 i;
fprintf (of, "Event Status Frequency Ticks Extra\n");
for (i = 0; i < RTC_NUM_EVNTS; i++) {
if (rtc_cntr[i])
fprintf (of, " %d on %3dHz %3d %d\n",
i, rtc_tab[rtc_indx[i]].hz, rtc_cntr[i], rtc_xtra[i]);
else fprintf (of, " %d off\n", i);
}
return SCPE_OK;
}

613
sigma/sigma_sys.c Normal file
View File

@@ -0,0 +1,613 @@
/* sigma_sys.c: Sigma system interface
Copyright (c) 2007-2008, 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.
*/
#include "sigma_defs.h"
#include <ctype.h>
#define FMTASC(x) ((x) < 0x20)? "<%02X>": "%c", (x)
extern DEVICE cpu_dev;
extern DEVICE map_dev;
extern DEVICE int_dev;
extern DEVICE chan_dev[];
extern DEVICE rtc_dev;
extern DEVICE tt_dev;
extern DEVICE pt_dev;
extern DEVICE lp_dev;
extern DEVICE rad_dev;
extern DEVICE dk_dev;
extern DEVICE dp_dev[];
extern DEVICE mt_dev;
extern DEVICE mux_dev, muxl_dev;
extern REG cpu_reg[];
extern uint32 *M;
extern UNIT cpu_unit;
t_stat fprint_sym_m (FILE *of, uint32 inst);
t_stat parse_sym_m (char *cptr, t_value *val);
void fprint_ebcdic (FILE *of, uint32 c);
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "XDS Sigma";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&map_dev,
&int_dev,
&chan_dev[0],
&chan_dev[1],
&chan_dev[2],
&chan_dev[3],
&chan_dev[4],
&chan_dev[5],
&chan_dev[6],
&chan_dev[7],
&rtc_dev, /* must be first */
&tt_dev,
&pt_dev,
&lp_dev,
&mt_dev,
&rad_dev,
&dk_dev,
&dp_dev[0],
&dp_dev[1],
&mux_dev,
&muxl_dev,
NULL
};
const char *sim_stop_messages[] = {
"Unknown error",
"Invalid I/O configuration",
"Breakpoint",
"Address stop",
"Wait, interrupts off",
"Invalid PSD",
"Nested EXU's exceed limit",
"Undefined instruction",
"Illegal trap or interrupt instruction",
"Invalid interrupt vector",
"Nested traps",
};
/* Character conversion tables (from Sigma 7 manual) */
uint8 ascii_to_ebcdic[128] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */
0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 3F */
0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 5F */
0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xB4, 0xB1, 0xB5, 0x6A, 0x6D,
0x4A, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60- 7F */
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xB2, 0x4F, 0xB3, 0x5F, 0xFF
};
uint8 ebcdic_to_ascii[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */
0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 - 3F */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 - 5F */
0x00, 0x00, '`', '.', '<', '(', '+', '|',
'&', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, '!', '$', '*', ')', ';', '~',
'-', '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 - 7F */
0x00, 0x00, '^', ',', '%', '_', '>', '?',
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, ':', '#', '@', '\'', '=', '"',
0x00, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 80 - 9F */
'h', 'i', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 's', 't', 'u', 'v', 'w', 'x', /* A0 - BF */
'y', 'z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, '\\', '{', '}', '[', ']', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* C0 - DF */
'H', 'I', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 'S', 'T', 'U', 'V', 'W', 'X', /* E0 - FF */
'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
};
/* Binary loader */
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
return SCPE_NOFNC;
}
/* Symbol and format tables */
#define IC_V_CL 17 /* class */
#define IC_M_CL 0x1F
#define IC_V_RN 16 /* takes rn */
#define IC_RN (1u << IC_V_RN)
#define IC_V_IND 15 /* takes ind */
#define IC_IND (1u << IC_V_IND)
#define IC_V_XR 13 /* takes xr */
#define IC_M_XR 0x3
#define IC_NONE 0
#define IC_XR 1
#define IC_CTL 2
#define IC_V_AW 7 /* addr width */
#define IC_M_AW 0x3F
#define IC_V_AP 2 /* addr position */
#define IC_M_AP 0x1F
#define IC_V_SGN 1 /* sign allowed */
#define IC_SGN (1u << IC_V_SGN)
#define IC_V_AOP 0 /* addr optional */
#define IC_AOP (1u << IC_V_AOP)
#define ID1_07 0 /* decode 1-7 */
#define ID1_11 1 /* decode 1-11 */
#define IDSHFT 2 /* shift */
#define IDSHFF 3 /* shift floating */
#define IDMMCX 4 /* MMC ext */
#define I_C(c,r,i,w,s,x,sn,ao) \
(((c) << IC_V_CL) | ((r) << IC_V_RN) | ((i) << IC_V_IND)|\
((w) << IC_V_AW) | ((s) << IC_V_AP) | ((x) << IC_V_XR) |\
((sn) << IC_V_SGN) | ((ao) << IC_V_AOP))
/* decode R I wd ps x sn ao */
#define IC_MRF I_C(ID1_07,1,1,17, 0,1, 0, 0) /* mem ref */
#define IC_IMM I_C(ID1_07,1,0,20, 0,0, 1, 0) /* immediate */
#define IC_LCFI I_C(ID1_07,0,0, 8, 0,2, 0, 0) /* LCFI */
#define IC_LFI I_C(ID1_11,0,0, 4, 0,0, 0, 0) /* LFI */
#define IC_LCI I_C(ID1_11,0,0, 4, 4,0, 0, 0) /* LCI */
#define IC_SHFT I_C(IDSHFT,1,0, 7, 0,1, 1, 0) /* shift */
#define IC_SHFF I_C(IDSHFF,1,0, 7, 0,1, 1, 0) /* floating shift */
#define IC_MNOR I_C(ID1_07,0,1,17, 0,1, 0, 0) /* mem ref, no reg */
#define IC_MNOX I_C(ID1_11,0,1,17, 0,1, 0, 0) /* mef ref ext */
#define IC_NOP I_C(ID1_07,1,0, 0, 0,0, 0, 0) /* no operand */
#define IC_NOPX I_C(ID1_11,1,0, 0, 0,0, 0, 0) /* no operand ext */
#define IC_MMC I_C(ID1_07,1,1, 3,17,0, 0, 0) /* MMC */
#define IC_MMCX I_C(IDMMCX,1,0, 0, 0,0, 0, 0) /* MMC extended */
#define IC_MNRI I_C(ID1_11,0,0, 0, 0,0, 0, 0) /* no operands */
#define IC_MNRO I_C(ID1_07,0,1,17, 0,1, 0, 1) /* mem ref, addr opt */
#define IC_GETCL(x) (((x) >> IC_V_CL) & IC_M_CL)
#define IC_GETXR(x) (((x) >> IC_V_XR) & IC_M_XR)
#define IC_GETAW(x) (((x) >> IC_V_AW) & IC_M_AW)
#define IC_GETAP(x) (((x) >> IC_V_AP) & IC_M_AP)
static const uint32 masks[] = {
0x7F000000, 0x7FF00000, 0x7F000700, 0x7F000100,
0x7F0E0000
};
/* Opcode tables - extended mnemonics must precede standard mnemonics */
static const uint32 opc_val[] = {
0x02100000, IC_LFI, 0x02200000, IC_LCI, 0x70100000, IC_MNOX, 0x70200000, IC_MNOX,
0x25000000, IC_SHFT, 0x25000100, IC_SHFT, 0x25000200, IC_SHFT, 0x25000000, IC_SHFT,
0x25000400, IC_SHFT, 0x25000500, IC_SHFT, 0x25000600, IC_SHFT, 0x25000700, IC_SHFT,
0x24000000, IC_SHFT, 0x24000100, IC_SHFT,
0x68000000, IC_MNOX, 0x68100000, IC_MNOX, 0x68200000, IC_MNOX, 0x68300000, IC_MNOX,
0x68400000, IC_MNOX, 0x68800000, IC_MNOX,
0x69000000, IC_MNOX, 0x69100000, IC_MNOX, 0x69200000, IC_MNOX, 0x69300000, IC_MNOX,
0x69400000, IC_MNOX, 0x69800000, IC_MNOX,
0x6F020000, IC_MMCX, 0x6F040000, IC_MMCX, 0x6F060000, IC_MMCX, 0x6F080000, IC_MMCX,
0x6F080000, IC_MMCX, 0x02000000, IC_MNRI,
0x02000000, IC_LCFI,
0x04000000, IC_MRF, 0x05000000, IC_MRF, 0x06000000, IC_MRF, 0x07000000, IC_MRF,
0x08000000, IC_MRF, 0x09000000, IC_MRF, 0x0A000000, IC_MRF, 0x0B000000, IC_MRF,
0x0C000000, IC_MRF, 0x0D000000, IC_NOP, 0x0E000000, IC_MRF, 0x0F000000, IC_MRF,
0x10000000, IC_MRF, 0x11000000, IC_MRF, 0x12000000, IC_MRF, 0x13000000, IC_MRF,
0x15000000, IC_MRF,
0x18000000, IC_MRF, 0x19000000, IC_MRF, 0x1A000000, IC_MRF, 0x1B000000, IC_MRF,
0x1C000000, IC_MRF, 0x1D000000, IC_MRF, 0x1E000000, IC_MRF, 0x1F000000, IC_MRF,
0x20000000, IC_IMM, 0x21000000, IC_IMM, 0x22000000, IC_IMM, 0x23000000, IC_IMM,
0x24000000, IC_MRF, 0x25000000, IC_MRF, 0x26000000, IC_MRF,
0x28000000, IC_MRF, 0x29000000, IC_MRF, 0x2A000000, IC_MRF, 0x2B000000, IC_MRF,
0x2C000000, IC_MRF, 0x2D000000, IC_MRF, 0x2E000000, IC_MNRO, 0x2F000000, IC_MRF,
0x30000000, IC_MRF, 0x31000000, IC_MRF, 0x32000000, IC_MRF, 0x33000000, IC_MRF,
0x34000000, IC_MRF, 0x35000000, IC_MRF, 0x36000000, IC_MRF, 0x37000000, IC_MRF,
0x38000000, IC_MRF, 0x39000000, IC_MRF, 0x3A000000, IC_MRF, 0x3B000000, IC_MRF,
0x3C000000, IC_MRF, 0x3D000000, IC_MRF, 0x3E000000, IC_MRF, 0x3F000000, IC_MRF,
0x40000000, IC_IMM, 0x41000000, IC_IMM,
0x44000000, IC_MRF, 0x45000000, IC_MRF, 0x46000000, IC_MRF, 0x47000000, IC_MRF,
0x48000000, IC_MRF, 0x49000000, IC_MRF, 0x4A000000, IC_MRF, 0x4B000000, IC_MRF,
0x4C000000, IC_MRF, 0x4D000000, IC_MRF, 0x4E000000, IC_MRF, 0x4F000000, IC_MRF,
0x50000000, IC_MRF, 0x51000000, IC_MRF, 0x52000000, IC_MRF, 0x53000000, IC_MRF,
0x55000000, IC_MRF, 0x56000000, IC_MRF, 0x57000000, IC_MRF,
0x58000000, IC_MRF, 0x5A000000, IC_MRF, 0x5B000000, IC_MRF,
0x60000000, IC_IMM, 0x61000000, IC_IMM, 0x63000000, IC_IMM,
0x64000000, IC_MRF, 0x65000000, IC_MRF, 0x66000000, IC_MRF, 0x67000000, IC_MNOR,
0x68000000, IC_MRF, 0x69000000, IC_MRF, 0x6A000000, IC_MRF, 0x6B000000, IC_MRF,
0x6C000000, IC_MRF, 0x6D000000, IC_MRF, 0x6E000000, IC_MRF, 0x6F000000, IC_MMC,
0x70000000, IC_MRF, 0x71000000, IC_MRF, 0x72000000, IC_MRF, 0x73000000, IC_MRF,
0x74000000, IC_MNOR, 0x75000000, IC_MRF, 0x76000000, IC_MRF, 0x77000000, IC_MRF,
0x78000000, IC_MRF, 0x79000000, IC_MRF, 0x7A000000, IC_MRF, 0x7B000000, IC_MRF,
0x7C000000, IC_MNOR, 0x7D000000, IC_MRF, 0x7E000000, IC_MRF, 0x7F000000, IC_MRF,
0xFFFFFFFF, 0
};
static const char *opcode[] = {
"LFI", "LCI", "LF", "LC", /* extended mmenomics */
"SLS", "SLD", "SCS", "SCD",
"SAS", "SAD", "SSS", "SSD",
"SFS", "SFL",
"B", "BGE", "BLE", "BE",
"BNOV", "BNC",
"BNVR", "BL", "BG", "BNE",
"BOV", "BC",
"LLOCKS", "LPC", "LLOCKSE", "LMAP",
"LMAPRE", "NOP",
"LCFI", /* 00 */
"CAL1", "CAL2", "CAL3", "CAL4",
"PLW", "PSW", "PLM", "PSM",
"PLS", "PSS", "LPSD", "XPSD",
"AD", "CD", "LD", "MSP", /* 10 */
"STD",
"SD", "CLM", "LCD", "LAD",
"FSL", "FAL", "FDL", "FML",
"AI", "CI", "LI", "MI", /* 20 */
"SF", "S", "LAS",
"CVS", "CVA", "LM", "STM",
"LRA", "LMS", "WAIT", "LRP",
"AW", "CW", "LW", "MTW", /* 30 */
"LVAW", "STW", "DW", "MW",
"SW", "CLR", "LCW", "LAW",
"FSS", "FAS", "FDS", "FMS",
"TTBS", "TBS", /* 40 */
"ANLZ", "CS", "XW", "STS",
"EOR", "OR", "LS", "AND",
"SIO", "TIO", "TDV", "HIO",
"AH", "CH", "LH", "MTH", /* 50 */
"STH", "DH", "MH",
"SH", "LCH", "LAH",
"CBS", "MBS", "EBS", /* 60 */
"BDR", "BIR", "AWM", "EXU",
"BCR", "BCS", "BAL", "INT",
"RD", "WD", "AIO", "MMC",
"LCF", "CB", "LB", "MTB", /* 70 */
"STCF", "STB", "PACK", "UNPK",
"DS", "DA", "DD", "DM",
"DSA", "DC", "DL", "DST",
NULL
};
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
*/
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
uint32 inst, sc, rdx, c;
DEVICE *dptr;
inst = val[0]; /* get inst */
if (uptr == NULL) /* anon = CPU */
uptr = &cpu_unit;
else if (uptr != &cpu_unit) /* CPU only */
return SCPE_ARG;
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL)
return SCPE_IERR;
if (sw & SWMASK ('D')) /* get radix */
rdx = 10;
else if (sw & SWMASK ('O'))
rdx = 8;
else if (sw & SWMASK ('X'))
rdx = 16;
else rdx = dptr->dradix;
if (sw & SWMASK ('C')) { /* char format? */
for (sc = 0; sc < 32; sc = sc + 8) { /* print string */
c = (inst >> (24 - sc)) & BMASK;
if (sw & SWMASK ('A'))
fprintf (of, FMTASC (c & 0x7F));
else fprint_ebcdic (of, c);
}
return 0; /* return # chars */
}
if (sw & SWMASK ('A')) { /* ASCII? */
sc = 24 - ((addr & 0x3) * 8); /* shift count */
c = (inst >> sc) & 0x7F;
fprintf (of, "%c", FMTASC (c));
return 0;
}
if (sw & SWMASK ('E')) { /* EBCDIC? */
sc = 24 - ((addr & 0x3) * 8); /* shift count */
c = (inst >> sc) & BMASK;
fprint_ebcdic (of, c);
return 0;
}
if (sw & SWMASK ('B')) { /* byte? */
sc = 24 - ((addr & 0x3) * 8); /* shift count */
c = (inst >> sc) & BMASK;
fprintf (of, "%02X", c);
return 0;
}
if (sw & SWMASK ('H')) { /* halfword? */
c = ((addr & 1)? inst: inst >> 16) & HMASK;
fprintf (of, "%04X", c);
return 0;
}
if ((sw & SWMASK ('M')) && /* inst format? */
!fprint_sym_m (of, inst)) /* decode inst */
return 0;
fprint_val (of, inst, rdx, 32, PV_RZRO);
return 0;
}
/* Instruction decode */
t_stat fprint_sym_m (FILE *of, uint32 inst)
{
uint32 i, j;
for (i = 0; opc_val[i] < 0xFFFFFFFF; i = i + 2) { /* loop thru ops */
j = IC_GETCL (opc_val[i + 1]); /* get class */
if (opc_val[i] == (inst & masks[j])) { /* match? */
uint32 fl = opc_val[i + 1]; /* get format */
uint32 aw = IC_GETAW (fl);
uint32 ap = IC_GETAP (fl);
uint32 xr = IC_GETXR (fl);
uint32 rn = I_GETRN (inst); /* get fields */
uint32 xn = I_GETXR (inst);
uint32 mask = (1u << aw) - 1;
uint32 ad = (inst >> ap) & mask;
fprintf (of, "%s", opcode[i >> 1]); /* opcode */
if (fl & IC_RN) /* rn? */
fprintf (of, ",%d", rn);
if (TST_IND (inst) || aw || xr) { /* anything else? */
fputs (TST_IND (inst)? " *": " ", of); /* space{*} */
if (aw) { /* any value? */
if ((fl & IC_SGN) && /* signed and */
(ad & (1u << (aw - 1)))) /* negative? */
fprintf (of, "-%X", (mask + 1) - ad);
else fprintf (of, "%X", ad);
if ((xr == IC_XR) && xn) /* any index? */
fprintf (of, ",%d", xn);
else if (xr == IC_CTL) /* or control? */
fprintf (of, ",%X", rn);
}
}
return SCPE_OK;
}
}
return SCPE_ARG;
}
void fprint_ebcdic (FILE *of, uint32 c)
{
uint32 cv = ebcdic_to_ascii[c];
if ((cv < 0040) || (cv >= 0177))
fprintf (of, "<%02X>", c);
else fputc (cv, of);
return;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
t_value num;
uint32 i, sc, rdx, c;
t_stat r;
DEVICE *dptr;
if (uptr == NULL) /* anon = CPU */
uptr = &cpu_unit;
else if (uptr != &cpu_unit) /* CPU only */
return SCPE_ARG;
dptr = find_dev_from_unit (uptr); /* find dev */
if (dptr == NULL)
return SCPE_IERR;
if (sw & SWMASK ('D')) /* get radix */
rdx = 10;
else if (sw & SWMASK ('O'))
rdx = 8;
else if (sw & SWMASK ('X'))
rdx = 16;
else rdx = dptr->dradix;
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* chars? */
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;
for (i = 0; i < 4; i++) {
if (cptr[i] == 0)
break;
sc = 24 - (i * 8);
c = (sw & SWMASK ('A'))?
cptr[i] & 0x7F:
ascii_to_ebcdic[cptr[i]];
val[0] = (val[0] & ~(BMASK << sc)) | (c << sc);
}
return 0;
}
if ((sw & SWMASK ('A')) || ((*cptr == '#') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;
sc = 24 - (addr & 0x3) * 8; /* shift count */
val[0] = (val[0] & ~(BMASK << sc)) | (cptr[0] << sc);
return 0;
}
if ((sw & SWMASK ('E')) || ((*cptr == '\'') && cptr++)) { /* EBCDIC char? */
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;
sc = 24 - (addr & 0x3) * 8; /* shift count */
val[0] = (val[0] & ~(BMASK << sc)) | (ascii_to_ebcdic[cptr[0]] << sc);
return 0;
}
if (sw & SWMASK ('B')) { /* byte? */
num = get_uint (cptr, rdx, BMASK, &r); /* get byte */
if (r != SCPE_OK)
return SCPE_ARG;
sc = 24 - (addr & 0x3) * 8; /* shift count */
val[0] = (val[0] & ~(BMASK << sc)) | (num << sc);
return 0;
}
if (sw & SWMASK ('H')) { /* halfword? */
num = get_uint (cptr, rdx, HMASK, &r); /* get half word */
if (r != SCPE_OK)
return SCPE_ARG;
sc = addr & 1? 0: 16;
val[0] = (val[0] & ~(HMASK << sc)) | (num << sc);
return 0;
}
if (!parse_sym_m (cptr, val))
return 0;
val[0] = get_uint (cptr, rdx, WMASK, &r); /* get number */
if (r != SCPE_OK)
return r;
return 0;
}
t_stat parse_sym_m (char *cptr, t_value *val)
{
uint32 i, sgn;
t_stat r;
char *sep;
char gbuf[CBUFSIZE];
cptr = get_glyph (cptr, gbuf, 0); /* get opcode+reg*/
if (sep = strchr (gbuf, ',')) /* , in middle? */
*sep++ = 0; /* split strings */
for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */
if (strcmp (opcode[i], gbuf) == 0) { /* string match? */
uint32 rn, xn, ad;
uint32 k = i << 1; /* index to opval */
uint32 fl = opc_val[k + 1];
uint32 aw = IC_GETAW (fl);
uint32 ap = IC_GETAP (fl);
uint32 xr = IC_GETXR (fl);
uint32 mask = (1u << aw) - 1;
val[0] = opc_val[k];
if (fl & IC_RN) { /* need rn? */
if (sep == NULL)
return SCPE_ARG;
rn = get_uint (sep, 10, INST_M_RN, &r);
if (r != SCPE_OK)
return SCPE_ARG;
val[0] |= rn << INST_V_RN;
}
else if (sep) /* rn & not wanted */
return SCPE_ARG;
if (aw) { /* more? */
if (*cptr == 0)
return (fl & IC_AOP)? SCPE_OK: SCPE_ARG;
if ((fl & IC_IND) && (*cptr == '*')) { /* indirect? */
val[0] |= INST_IND;
cptr++;
}
if ((fl & IC_SGN) && /* signed val? */
strchr ("+-", *cptr) && /* with sign? */
(*cptr++ == '-')) /* and minus? */
sgn = 1;
else sgn = 0; /* else + */
cptr = get_glyph (cptr, gbuf, 0); /* get rest */
if (sep = strchr (gbuf, ',')) /* , in middle? */
*sep++ = 0; /* split strings */
ad = get_uint (gbuf, 16, mask, &r);
if (r != SCPE_OK)
return r;
if (sgn && ad) /* negative, nz? */
ad = (mask + 1) - ad; /* complement */
val[0] |= (ad << ap);
if ((xr == IC_XR) && sep) { /* index? */
xn = get_uint (sep, 10, 7, &r);
if (r != SCPE_OK)
return r;
val[0] |= (xn << INST_V_XR);
}
else if (xr == IC_CTL) { /* control? */
if (sep == NULL)
return SCPE_ARG;
xn = get_uint (gbuf, 16, INST_M_RN, &r);
if (r != SCPE_OK)
return r;
val[0] |= (xn << INST_V_RN);
}
else if (sep)
return SCPE_ARG;
}
if (*cptr != 0)
return SCPE_ARG;
return SCPE_OK;
}
}
return SCPE_ARG;
}

331
sigma/sigma_tt.c Normal file
View File

@@ -0,0 +1,331 @@
/* sigma_tt.c: Sigma 7012 console teletype
Copyright (c) 2007-2008, 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.
tt 7012 console
The 7012 has the following special cases on input and output:
CR input, mapped to NEWLINE and echoes CR-LF
^H input, mapped to EOM and not echoed
HT input or output, simulates tabbing with fixed 8 character stops
*/
#include "sigma_io_defs.h"
#include <ctype.h>
/* Device definitions */
#define TTI 0
#define TTO 1
/* Device states */
#define TTS_IDLE 0x0
#define TTS_INIT 0x1
#define TTS_END 0x2
#define TTS_WRITE 0x5
#define TTS_READ 0x6
#define TTS_READS 0x86
/* EBCDIC special characters for input */
#define E_EOM 0x08 /* end of medium */
#define E_HT 0x05 /* tab */
#define E_NL 0x15 /* new line */
uint32 tt_cmd = TTS_IDLE;
uint32 tti_tps = RTC_HZ_100;
uint32 tti_panel = 020; /* panel int char */
uint32 tto_pos = 0; /* char position */
extern uint32 chan_ctl_time;
extern uint8 ascii_to_ebcdic[128];
extern uint8 ebcdic_to_ascii[256];
uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 tt_tio_status (void);
t_stat tt_chan_err (uint32 st);
t_stat tti_rtc_svc (uint32 tm);
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tt_reset (DEVICE *dptr);
t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
void tto_echo (int32 c);
extern t_stat io_set_pint (void);
/* TT data structures
tt_dev TT device descriptor
tt_unit TT unit descriptors
tt_reg TT register list
tt_mod TT modifiers list
*/
dib_t tt_dib = { DVA_TT, tt_disp };
UNIT tt_unit[] = {
{ UDATA (&tti_svc, TT_MODE_UC, 0), 0 },
{ UDATA (&tto_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }
};
REG tt_reg[] = {
{ HRDATA (CMD, tt_cmd, 9) },
{ DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (KTPS, tti_tps, 8), REG_HRO },
{ DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
{ HRDATA (PANEL, tti_panel, 8) },
{ HRDATA (DEVNO, tt_dib.dva, 12), REG_HRO },
{ NULL }
};
MTAB tt_mod[] = {
{ TT_MODE, TT_MODE_UC, "UC", "UC", &tt_set_mode },
{ TT_MODE, TT_MODE_7P, "7p", "7P", &tt_set_mode },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_TTI, "POLL", "POLL",
&rtc_set_tps, &rtc_show_tps, (void *) &tti_tps },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ 0 }
};
DEVICE tt_dev = {
"TT", tt_unit, tt_reg, tt_mod,
2, 10, 31, 1, 16, 8,
NULL, NULL, &tt_reset,
NULL, NULL, NULL,
&tt_dib, 0
};
/* Terminal: IO dispatch routine */
uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst)
{
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = tt_tio_status (); /* get status */
if ((*dvst & DVS_DST) == 0) { /* idle? */
tt_cmd = TTS_INIT; /* start dev thread */
sim_activate (&tt_unit[TTO], chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = tt_tio_status (); /* return status */
break;
case OP_HIO: /* halt I/O */
chan_clr_chi (tt_dib.dva); /* clr int*/
*dvst = tt_tio_status (); /* get status */
if ((*dvst & DVS_DST) != 0) { /* busy? */
sim_cancel (&tt_unit[TTO]); /* stop dev thread */
tt_cmd = TTS_IDLE;
chan_uen (tt_dib.dva); /* uend */
}
break;
case OP_AIO: /* acknowledge int */
chan_clr_chi (tt_dib.dva); /* clr int*/
case OP_TDV: /* test status */
*dvst = 0; /* no status */
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* Timed input service routine - runs continuously
Only accepts input in TTS_READx state */
t_stat tti_svc (UNIT *uptr)
{
int32 c, ebcdic;
uint32 st;
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or err? */
return c;
if (c & SCPE_BREAK) { /* break? */
if (tt_cmd == TTS_WRITE) { /* during write? */
tt_cmd = TTS_IDLE;
sim_cancel (&tt_unit[TTO]); /* cancel write */
chan_uen (tt_dib.dva); /* uend */
}
return SCPE_OK;
}
c = c & 0x7F;
if (c == tti_panel) /* panel interrupt? */
return io_set_pint ();
uptr->pos = uptr->pos + 1; /* incr count */
if (c == '\r') /* map CR to NL */
c = '\n';
if (c == 0x7F) /* map ^H back */
c = 0x08;
c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); /* input conversion */
ebcdic = ascii_to_ebcdic[c]; /* then to EBCDIC */
tto_echo (c); /* echo character */
if ((tt_cmd & 0x7F) == TTS_READ) { /* waiting for input? */
st = chan_WrMemB (tt_dib.dva, ebcdic); /* write to memory */
if (CHS_IFERR (st)) /* channel error? */
return tt_chan_err (st);
if ((st == CHS_ZBC) || (ebcdic == E_EOM) || /* channel end? */
((tt_cmd == TTS_READS) && ((ebcdic == E_HT) || (ebcdic == E_NL)))) {
tt_cmd = TTS_END; /* new state */
sim_activate (&tt_unit[TTO], chan_ctl_time); /* start dev thread */
}
}
return SCPE_OK;
}
/* Output service routine - also acts as overall device thread
Because of possible retry, channel status and converted character
must be preserved across calls. */
t_stat tto_svc (UNIT *uptr)
{
int32 c, cmd;
uint32 st;
switch (tt_cmd) { /* case on state */
case TTS_INIT: /* I/O init */
st = chan_get_cmd (tt_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
return tt_chan_err (st);
if ((cmd == TTS_WRITE) || /* valid command? */
((cmd & 0x7F) == TTS_READ))
tt_cmd = cmd; /* next state */
else tt_cmd = TTS_END; /* no, end state */
sim_activate (uptr, chan_ctl_time); /* continue thread */
break;
case TTS_WRITE: /* char output */
st = chan_RdMemB (tt_dib.dva, &c); /* get char */
if (CHS_IFERR (st)) /* channel error? */
return tt_chan_err (st);
c = ebcdic_to_ascii[c & 0xFF]; /* convert to ASCII */
tto_echo (c); /* echo character */
sim_activate (uptr, uptr->wait); /* continue thread */
if (st == CHS_ZBC) /* st = zbc? */
tt_cmd = TTS_END; /* next is end */
else tt_cmd = TTS_WRITE; /* next is write */
break;
case TTS_END: /* command done */
st = chan_end (tt_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
return tt_chan_err (st);
if (st == CHS_CCH) { /* command chain? */
tt_cmd = TTS_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time);
}
else tt_cmd = TTS_IDLE; /* all done */
break;
}
return SCPE_OK;
}
/* Actual tty output routines; simulates horizontal tabs */
void tto_echo (int32 c)
{
uint32 cnt;
cnt = 1;
if (c == '\r')
tto_pos = 0;
else if (c == '\n') {
tto_pos = 0;
sim_putchar ('\r');
tt_unit[TTO].pos = tt_unit[TTO].pos + 1;
}
else if (c == '\t') {
c = ' ';
cnt = 8 - (tto_pos % 8);
}
else c = sim_tt_outcvt (c, TT_GET_MODE (tt_unit[TTO].flags));
if (c >= 0) {
while (cnt-- > 0) {
sim_putchar (c);
tto_pos++;
tt_unit[TTO].pos = tt_unit[TTO].pos + 1;
}
}
return;
}
/* TTY status routine */
uint32 tt_tio_status (void)
{
if (tt_cmd == TTS_IDLE)
return DVS_AUTO;
return (CC2 << DVT_V_CC) | DVS_DBUSY | DVS_CBUSY | DVS_AUTO;
}
/* Channel error */
t_stat tt_chan_err (uint32 st)
{
tt_cmd = TTS_IDLE;
sim_cancel (&tt_unit[TTO]); /* stop dev thread */
chan_uen (tt_dib.dva); /* uend */
if (st < CHS_ERR)
return st;
return SCPE_OK;
}
/* Reset routine */
t_stat tt_reset (DEVICE *dptr)
{
rtc_register (RTC_TTI, tti_tps, &tt_unit[TTI]); /* register timer */
sim_cancel (&tt_unit[TTO]); /* stop dev thread */
tt_cmd = TTS_IDLE; /* idle */
chan_reset_dev (tt_dib.dva); /* clr int, active */
tto_pos = 0;
return SCPE_OK;
}
/* Make mode flags uniform */
t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
{
tt_unit[TTO].flags = (tt_unit[TTO].flags & ~TT_MODE) | val;
if (val == TT_MODE_7P)
val = TT_MODE_7B;
tt_unit[TTI].flags = (tt_unit[TTI].flags & ~TT_MODE) | val;
return SCPE_OK;
}