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:
BIN
sigma/Design Notes on the Sigma 7.doc
Normal file
BIN
sigma/Design Notes on the Sigma 7.doc
Normal file
Binary file not shown.
149
sigma/sigma_bugs.txt
Normal file
149
sigma/sigma_bugs.txt
Normal 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
990
sigma/sigma_cis.c
Normal 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
620
sigma/sigma_coc.c
Normal 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
2848
sigma/sigma_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
478
sigma/sigma_defs.h
Normal file
478
sigma/sigma_defs.h
Normal 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
470
sigma/sigma_dk.c
Normal 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
BIN
sigma/sigma_doc.doc
Normal file
Binary file not shown.
1278
sigma/sigma_dp.c
Normal file
1278
sigma/sigma_dp.c
Normal file
File diff suppressed because it is too large
Load Diff
421
sigma/sigma_fp.c
Normal file
421
sigma/sigma_fp.c
Normal 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
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
276
sigma/sigma_io_defs.h
Normal 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
529
sigma/sigma_lp.c
Normal 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
591
sigma/sigma_map.c
Normal 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
645
sigma/sigma_mt.c
Normal 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
297
sigma/sigma_pt.c
Normal 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
532
sigma/sigma_rad.c
Normal 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
267
sigma/sigma_rtc.c
Normal 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
613
sigma/sigma_sys.c
Normal 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
331
sigma/sigma_tt.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user