1
0
mirror of https://github.com/open-simh/simh.git synced 2026-04-27 12:39:13 +00:00

Notes For V3.6-0

The save/restore format has been updated to improve its reliability.
As a result, save files prior to release 3.0 are no longer supported.

The text documentation files are obsolete and are no longer included
with the distribution.  Up-to-date PDF documentation files are
available on the SimH web site.

1. New Features

1.1 3.6-0

1.1.1 Most magnetic tapes

- Added support for limiting tape capacity to a particular size in MB

1.1.2 IBM 7090/7094

- First release

1.1.3 VAX-11/780

- Added FLOAD command, loads system file from console floppy disk

1.1.4 VAX, VAX-11/780, and PDP-11

- Added card reader support (from John Dundas)

1.1.5 PDP-11

- Added instruction history

2. Bugs Fixed

Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.
This commit is contained in:
Bob Supnik
2006-05-27 11:34:00 -07:00
committed by Mark Pizzolato
parent a12e4a1c39
commit dc871fa631
106 changed files with 15439 additions and 17517 deletions

72
I7094/i7094_bugs.txt Normal file
View File

@@ -0,0 +1,72 @@
Bugs found
1. CPU: MPY tested sign of AC instead of sign of MQ.
2. CPU: VLM, VDP, VDH need alternate opcode decode points for large counts.
3. CPU: STL not in decode table.
4. CPU: Partial stores lacked initial read in decode table.
5. CPU: PXD, PCD needed (t_uint64) cast.
6. CPU: SXD, SCD needed (t_uint64) cast.
7. CPU: SBM at wrong case offset.
8. CPU: All transfers used IR<21:35> instead of calculated effective address.
9. CPU: HPR, TRA need alternate negative opcodes.
10. CPU: STT missing final write to memory.
11. IO: Channel output process model incorrect, extensive revision required.
12. IO: Channel connect test should not test channel state, only connection.
13. IO: Channel opcode with nostore doesn't increment channel address.
14. CDR: Card reader missing activate at end of state 2.
15. SYS: Zero operand instructions printed with trailing space.
16. CPU: Convert class count bit field start definition incorrect.
17. CPU: CAQ cut and paste error from CVR.
18. CPU: Shift count is 8b wide, not 9b.
19. SYS: Mnemonic is LDQ not LMQ.
20. SYS: RQL opcode incorrect in symbolic decode table.
21. CPU: Multi-tag mode stores OR'd value of tags on any index read except
normal effective address.
22. CPU: Floating point trap does not write location 0 if trap suppressed.
23. SYS: TRA instructions should have symbolic class MXN not MXR.
24. CPU: Floating add instructions test for zero result only if normalization enabled.
25. CPU: Floating add with unlike signs and equal magnitudes, result sign is sign
of SR rather than sign of AC.
26. CPU: Floating multiply does not test spill prior to normalization step.
27. CPU: Channel activity proceeds under HALT.
28. MT: Any read error should stop the channel and the tape controller.
29. MT: EOR write flag cleared before testing.
39. IO: EOR write flag set after data sent to device.
40. IO: EOR write flag incorrect set on IOCP, IOCT, IOSP, IOST.
41. MT: End of file errors not masked on backspace operations.
42. CPU: LCHx, RCHx miscoded in decode table.
43. IO: Only 7607 error completions (IOxT without new command) set trap.
44. CPU: 7067 channel trap flags misdefined with extraneous decrement shift.
45. CPU: pcq array misdeclared as uint32 instead of uint16.
46. IO: SDC and SCD tested chan_flags instead of chan_dev.flags.
47. SYS: 7907 opcodes defined incorrectly.
48. SYS: TCH not decoding bit<19>.
49. IO: CTL not clearing EOR after device end.
50. DSK: Format code not incrementing track in writing all tracks in cylinder.
51. DSK: THA mode overwrites record structure of first record.
52. DSK: Write doesn't set channel request for initial word.
53. DSK: Saved record number was command digits 3..8 instead of 5..10.
54. CLK: Compute 60th's from location 5, so Chrono clock is in sync with interval clock.
55. CPU: Enable Chronolog clock if CTSS.
56. CPU: Read/write protection error not setting protection trap.
57. CPU: SCHx not setting protection trap in user mode.
58: CPU: Protection trap overwriting wrong location.
59. CPU: Stop message reporting physical, not virtual, PC.
60. IO: Test for "request another cycle" in channel processor was inverted.
61. IO: Valid bit handling incorrect across multiple transfers.
62. IO: BSR doesn't set EOF indicator.
63. IO: 7607 channel modeled incorrectly, could stall.
64. IO: All 7607 "effective NOP" conditions must be tested when a new command is
decoded (wc == 0 for IOCx and IOSx, EOR set for IOSx and IORx).

495
I7094/i7094_cd.c Normal file
View File

@@ -0,0 +1,495 @@
/* i7094_cd.c: IBM 711/721 card reader/punch
Copyright (c) 2003-2006, 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.
cdr 711 card reader
cdp 721 card punch
Cards are represented as ASCII text streams terminated by newlines.
This allows cards to be created and edited as normal files. Two
formats are supported:
column binary each character represents 6b of a 12b column
text each character represents all 12b of a column
Internally, the 7094 works only with column binary and is limited
to 72 columns of data. Each row of the card is represented by 72b
of data (two 36b words). A complete card image consists of 12 rows
(24 36b words).
*/
#include "i7094_defs.h"
#define CD_BINLNT 24 /* bin buf length */
#define CD_CHRLNT 80 /* char buf length */
#define CDS_INIT 0 /* card in motion */
#define CDS_DATA 1 /* data transfer */
#define CDS_END 2 /* card complete */
#define UNIT_V_CBN (UNIT_V_UF + 0) /* column binary file */
#define UNIT_V_PCA (UNIT_V_UF + 1) /* A vs H punch flag */
#define UNIT_CBN (1 << UNIT_V_CBN)
#define UNIT_PCA (1 << UNIT_V_PCA)
uint32 cdr_sta = 0; /* state */
uint32 cdr_bptr = 0; /* buffer ptr */
uint32 cdr_tstart = 27500; /* timing */
uint32 cdr_tstop = 27500;
uint32 cdr_tleft = 150;
uint32 cdr_tright = 4000;
t_uint64 cdr_bbuf[CD_BINLNT]; /* col binary buf */
uint32 cdp_sta = 0; /* state */
uint32 cdp_bptr = 0; /* buffer ptr */
uint32 cdp_tstart = 35000; /* timing */
uint32 cdp_tstop = 35000;
uint32 cdp_tleft = 150;
uint32 cdp_tright = 15500;
t_uint64 cdp_chob = 0;
uint32 cdp_chob_v = 0;
t_uint64 cdp_bbuf[CD_BINLNT]; /* col binary buf */
t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit);
t_stat cdr_reset (DEVICE *dptr);
t_stat cdr_svc (UNIT *uptr);
t_stat cdr_boot (int32 unitno, DEVICE *dptr);
t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit);
t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 flags);
t_stat cdp_reset (DEVICE *dptr);
t_stat cdp_svc (UNIT *uptr);
t_stat cdp_card_end (UNIT *uptr);
t_stat cd_attach (UNIT *uptr, char *cptr);
t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
char colbin_to_bcd (uint32 cb);
extern uint32 sim_switches;
extern uint32 PC;
extern uint32 ind_ioc;
extern char bcd_to_ascii_a[64];
extern char bcd_to_ascii_h[64];
extern uint32 bcd_to_colbin[64];
extern char ascii_to_bcd[128];
extern t_uint64 bit_masks[36];
extern uint32 col_masks[12];
/* Card reader data structures
cdr_dev CDR descriptor
cdr_unit CDR unit descriptor
cdr_reg CDR register list
*/
DIB cdr_dib = { &cdr_chsel, NULL };
UNIT cdr_unit = {
UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0)
};
REG cdr_reg[] = {
{ ORDATA (STATE, cdr_sta, 2) },
{ DRDATA (BPTR, cdr_bptr, 5), PV_LEFT },
{ BRDATA (BUF, cdr_bbuf, 8, 36, CD_BINLNT) },
{ DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TSTART, cdr_tstart, 24), PV_LEFT + REG_NZ },
{ DRDATA (TSTOP, cdr_tstop, 24), PV_LEFT + REG_NZ },
{ DRDATA (TLEFT, cdr_tleft, 24), PV_LEFT + REG_NZ },
{ DRDATA (TRIGHT, cdr_tright, 24), PV_LEFT + REG_NZ },
{ NULL } };
MTAB cdr_mod[] = {
{ UNIT_CBN, UNIT_CBN, "column binary", "BINARY", &cd_set_mode },
{ UNIT_CBN, UNIT_CBN, "text", "TEXT", &cd_set_mode },
{ 0 }
};
DEVICE cdr_dev = {
"CDR", &cdr_unit, cdr_reg, cdr_mod,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cdr_reset,
&cdr_boot, &cd_attach, NULL,
&cdr_dib, DEV_DISABLE
};
/* CDP data structures
cdp_dev CDP device descriptor
cdp_unit CDP unit descriptor
cdp_reg CDP register list
*/
DIB cdp_dib = { &cdp_chsel, &cdp_chwr };
UNIT cdp_unit = {
UDATA (&cdp_svc, UNIT_SEQ+UNIT_ATTABLE, 0)
};
REG cdp_reg[] = {
{ ORDATA (STATE, cdp_sta, 2) },
{ ORDATA (CHOB, cdp_chob, 36) },
{ FLDATA (CHOBV, cdp_chob_v, 0) },
{ DRDATA (BPTR, cdp_bptr, 5), PV_LEFT },
{ BRDATA (BUF, cdp_bbuf, 8, 36, CD_BINLNT) },
{ DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TSTART, cdp_tstart, 24), PV_LEFT + REG_NZ },
{ DRDATA (TSTOP, cdp_tstop, 24), PV_LEFT + REG_NZ },
{ DRDATA (TLEFT, cdp_tleft, 24), PV_LEFT + REG_NZ },
{ DRDATA (TRIGHT, cdp_tright, 24), PV_LEFT + REG_NZ },
{ NULL }
};
MTAB cdp_mod[] = {
{ UNIT_CBN, UNIT_CBN, "column binary", "BINARY", &cd_set_mode },
{ UNIT_CBN, UNIT_CBN, "text", "TEXT", &cd_set_mode },
{ UNIT_PCA, UNIT_PCA, "business set", "BUSINESS", NULL },
{ UNIT_PCA, 0, "Fortran set", "FORTRAN", NULL },
{ 0 }
};
DEVICE cdp_dev = {
"CDP", &cdp_unit, cdp_reg, cdp_mod,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cdp_reset,
NULL, &cd_attach, NULL,
&cdp_dib, DEV_DISABLE
};
/* Card reader select */
t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit)
{
if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */
switch (sel) { /* case on data sel */
case CHSL_RDS: /* read */
if ((cdr_unit.flags & UNIT_ATT) == 0) /* not attached? */
return SCPE_UNATT;
if (sim_is_active (&cdr_unit)) /* busy? */
return ERR_STALL;
cdr_sta = CDS_INIT; /* initial state */
sim_activate (&cdr_unit, cdp_tstart); /* start reader */
break;
default: /* other */
return STOP_ILLIOP; /* not allowed */
}
return SCPE_OK;
}
/* Unit timeout */
t_stat cdr_svc (UNIT *uptr)
{
uint32 i, col, row, bufw, colbin;
char cdr_cbuf[2 * CD_CHRLNT + 1];
t_uint64 dat = 0;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* not attached? */
switch (cdr_sta) { /* case on state */
case CDS_INIT: /* initial state */
for (i = 0; i < CD_BINLNT; i++) /* clear bin buf */
cdr_bbuf[i] = 0;
for (i = 0; i < ((2 * CD_CHRLNT) + 1); i++) /* clear char buf */
cdr_cbuf[i] = ' ';
cdr_sta = CDS_DATA; /* data state */
cdr_bptr = 0; /* init buf ptr */
fgets (cdr_cbuf, (uptr->flags & UNIT_CBN)? (2 * CD_CHRLNT): CD_CHRLNT,
uptr->fileref); /* read card */
if (feof (uptr->fileref)) /* eof? */
return ch6_err_disc (CH_A, U_CDR, CHF_EOF); /* set EOF, disc */
if (ferror (uptr->fileref)) { /* error? */
perror ("CDR I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; /* stop */
}
uptr->pos = ftell (uptr->fileref); /* update position */
for (i = 0; i < (2 * CD_CHRLNT); i++) /* convert to BCD */
cdr_cbuf[i] = ascii_to_bcd[cdr_cbuf[i] & 0177] & 077;
for (col = 0; col < 72; col++) { /* process 72 columns */
if (uptr->flags & UNIT_CBN) /* column binary? */
colbin = (((uint32) cdr_cbuf[2 * col]) << 6) |
((uint32) cdr_cbuf[(2 * col) + 1]); /* 2 chars -> col bin */
else colbin = bcd_to_colbin[cdr_cbuf[col]]; /* cvt to col binary */
dat = bit_masks[35 - (col % 36)]; /* mask for column */
for (row = 0; row < 12; row++) { /* rows 9..0, 11, 12 */
bufw = (row * 2) + (col / 36); /* index to buffer */
if (colbin & col_masks[row]) /* row bit set? */
cdr_bbuf[bufw] |= dat;
}
}
case CDS_DATA: /* data state */
dat = cdr_bbuf[cdr_bptr++]; /* get next word */
if (cdr_bptr >= CD_BINLNT) { /* last word? */
cdr_sta = CDS_END; /* end state */
ch6_req_rd (CH_A, U_CDR, dat, CH6DF_EOR); /* req chan, dat, EOR */
sim_activate (uptr, cdr_tstop);
}
else {
ch6_req_rd (CH_A, U_CDR, dat, 0); /* req chan, dat */
sim_activate (uptr, (cdr_bptr & 1)? cdr_tleft: cdr_tright);
}
break;
case CDS_END: /* end state */
if (ch6_qconn (CH_A, U_CDR)) { /* if cdr still conn */
cdr_sta = CDS_INIT; /* return to init */
sim_activate (uptr, 1); /* next card */
}
break;
}
return SCPE_OK;
}
/* Card reader reset */
t_stat cdr_reset (DEVICE *dptr)
{
uint32 i;
for (i = 0; i < CD_BINLNT; i++) cdr_bbuf[i] = 0; /* clear buffer */
cdr_sta = 0; /* clear state */
cdr_bptr = 0; /* clear buf ptr */
sim_cancel (&cdr_unit); /* stop reader */
return SCPE_OK;
}
/* Card reader bootstrap */
#define BOOT_START 01000
#define BOOT_SIZE (sizeof (boot_rom) / sizeof (t_uint64))
static const t_uint64 boot_rom[] = {
00762000001000 + U_CDR, /* RDSA CDR */
00544000000000 + BOOT_START + 4, /* LCHA *+3 */
00544000000000, /* LCHA 0 */
00021000000001, /* TTR 1 */
05000030000000, /* IOCT 3,,0 */
};
t_stat cdr_boot (int32 unitno, DEVICE *dptr)
{
uint32 i;
extern t_uint64 *M;
for (i = 0; i < BOOT_SIZE; i++)
WriteP (BOOT_START + i, boot_rom[i]);
PC = BOOT_START;
return SCPE_OK;
}
/* Reader/punch attach */
t_stat cd_attach (UNIT *uptr, char *cptr)
{
t_stat r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r; /* attach */
if (sim_switches & SWMASK ('T')) /* text? */
uptr->flags = uptr->flags & ~UNIT_CBN;
else if (sim_switches & SWMASK ('C')) /* column binary? */
uptr->flags = uptr->flags | UNIT_CBN;
else if (match_ext (cptr, "TXT")) /* .txt? */
uptr->flags = uptr->flags & ~UNIT_CBN;
else if (match_ext (cptr, "CBN")) /* .cbn? */
uptr->flags = uptr->flags | UNIT_CBN;
return SCPE_OK;
}
/* Reader/punch set mode - valid only if not attached */
t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
{
return (uptr->flags & UNIT_ATT)? SCPE_NOFNC: SCPE_OK;
}
/* Card punch select */
t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit)
{
if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */
switch (sel) { /* case on cmd */
case CHSL_WRS: /* write */
if ((cdp_unit.flags & UNIT_ATT) == 0) /* not attached? */
return SCPE_UNATT;
if (sim_is_active (&cdp_unit)) /* busy? */
return ERR_STALL;
cdp_sta = CDS_INIT; /* initial state */
sim_activate (&cdp_unit, cdp_tstart); /* start punch */
break;
default: /* other */
return STOP_ILLIOP; /* not allowed */
}
return SCPE_OK;
}
/* Channel write routine - write word to buffer, write card when full */
t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 eorfl)
{
cdp_chob = val & DMASK; /* store data */
cdp_chob_v = 1; /* buffer valid */
if (cdp_sta == CDS_DATA) {
cdp_bbuf[cdp_bptr++] = cdp_chob; /* store data */
if ((cdp_bptr >= CD_BINLNT) || eorfl) { /* end card or end rec? */
ch6_set_flags (CH_A, U_CDP, CHF_EOR); /* set eor */
return cdp_card_end (&cdp_unit); /* write card */
}
return SCPE_OK;
}
return SCPE_IERR;
}
/* Unit timeout */
t_stat cdp_svc (UNIT *uptr)
{
uint32 i;
switch (cdp_sta) { /* case on state */
case CDS_INIT: /* initial state */
for (i = 0; i < CD_BINLNT; i++) /* clear bin buffer */
cdp_bbuf[i] = 0;
cdp_sta = CDS_DATA; /* data state */
cdp_bptr = 0; /* init pointer */
ch6_req_wr (CH_A, U_CDP); /* request channel */
cdp_chob = 0; /* clr, inval buffer */
cdp_chob_v = 0;
sim_activate (uptr, cdp_tleft); /* go again */
break;
case CDS_DATA: /* data state */
if (!ch6_qconn (CH_A, U_CDP)) /* chan disconnect? */
return cdp_card_end (uptr); /* write card */
if (cdp_chob_v) cdp_chob_v = 0; /* valid? clear */
else ind_ioc = 1; /* no, io check */
ch6_req_wr (CH_A, U_CDP); /* req channel */
sim_activate (uptr, (cdp_bptr & 1)? cdp_tleft: cdp_tright);
break;
case CDS_END: /* end state */
if (ch6_qconn (CH_A, U_CDP)) { /* if cdp still conn */
cdp_sta = CDS_INIT; /* return to init */
sim_activate (uptr, 1); /* next card */
}
break;
}
return SCPE_OK;
}
/* Card end - write card image to file, transition to end state */
t_stat cdp_card_end (UNIT *uptr)
{
uint32 i, col, row, bufw, colbin;
char *pch, bcd, cdp_cbuf[(2 * CD_CHRLNT) + 1];
t_uint64 dat;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* not attached? */
if (uptr->flags & UNIT_PCA) pch = bcd_to_ascii_a;
else pch = bcd_to_ascii_h;
for (col = 0; col < ((2 * CD_CHRLNT) + 1); col++)
cdp_cbuf[col] = ' '; /* clear char buf */
for (col = 0; col < 72; col++) { /* process 72 columns */
colbin = 0;
dat = bit_masks[35 - (col % 36)]; /* mask for column */
for (row = 0; row < 12; row++) { /* proc 12 rows */
bufw = (row * 2) + (col / 36); /* index to buffer */
if (cdp_bbuf[bufw] & dat) colbin |= col_masks[row];
}
if (cdp_unit.flags & UNIT_CBN) { /* column binary? */
cdp_cbuf[2 * col] = pch[(colbin >> 6) & 077];
cdp_cbuf[(2 * col) + 1] = pch[colbin & 077];
}
else { /* text */
bcd = colbin_to_bcd (colbin); /* column bin -> BCD */
cdp_cbuf[col] = pch[bcd]; /* -> ASCII */
}
}
for (i = ((2 * CD_CHRLNT) + 1); (i > 0) &&
(cdp_cbuf[i - 1] == ' '); --i) ; /* trim spaces */
cdp_cbuf[i++] = '\n'; /* append nl */
fxwrite (cdp_cbuf, 1, i, uptr->fileref); /* write card */
if (ferror (uptr->fileref)) { /* error? */
perror ("CDP I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR;
}
uptr->pos = ftell (uptr->fileref); /* update position */
cdp_sta = CDS_END; /* end state */
sim_cancel (uptr); /* cancel current */
sim_activate (uptr, cdp_tstop); /* long timer */
return SCPE_OK;
}
/* Card punch reset */
t_stat cdp_reset (DEVICE *dptr)
{
uint32 i;
for (i = 0; i < 24; i++) cdp_bbuf[i] = 0; /* clear buffer */
cdp_sta = 0; /* clear state */
cdp_bptr = 0; /* clear buf ptr */
cdp_chob = 0;
cdp_chob_v = 0;
sim_cancel (&cdp_unit); /* stop punch */
return SCPE_OK;
}
/* Column binary to BCD
This is based on documentation in the IBM 1620 manual and may not be
accurate for the 7094. Each row (12,11,0,1..9) is interpreted as a bit
pattern, and the appropriate bits are set. (Double punches inclusive
OR, eg, 1,8,9 is 9.) On the 1620, double punch errors are detected;
since the 7094 only reads column binary, double punches are ignored.
Bit order, left to right, is 12, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
The for loop works right to left, so the table is reversed. */
static const char row_val[12] = {
011, 010, 007, 006, 005, 004,
003, 002, 001, 020, 040, 060
};
char colbin_to_bcd (uint32 cb)
{
uint32 i;
char bcd;
for (i = 0, bcd = 0; i < 12; i++) { /* 'sum' rows */
if (cb & (1 << i)) bcd |= row_val[i];
}
return bcd;
}

124
I7094/i7094_clk.c Normal file
View File

@@ -0,0 +1,124 @@
/* i7094_clk.c: IBM 7094 clock
Copyright (c) 2003-2006, 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.
clk RPQ F89349 interval timer
Chronolog calendar clock
*/
#include "i7094_defs.h"
#include <time.h>
uint32 chtr_clk = 0;
extern t_uint64 *M;
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
uint8 bcd_2d (uint32 n, uint8 *b2);
/* CLK data structures
clk_dev CLK device descriptor
clk_unit CLK unit
clk_reg CLK register list
*/
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
{ FLDATA (TRAP, chtr_clk, 0) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL }
};
DEVICE clk_dev = {
"CLK", &clk_unit, clk_reg, NULL,
1, 0, 0, 0, 0, 0,
NULL, NULL, &clk_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE+DEV_DIS
};
/* Clock unit service */
t_stat clk_svc (UNIT *uptr)
{
t_uint64 ctr;
if ((clk_dev.flags & DEV_DIS) == 0) { /* clock enabled? */
ctr = ReadP (CLK_CTR);
ctr = (ctr + 1) & DMASK; /* increment */
WriteP (CLK_CTR, ctr);
if ((ctr & MMASK) == 0) chtr_clk = 1; /* overflow? req trap */
sim_activate (uptr, sim_rtcn_calb (CLK_TPS, TMR_CLK)); /* reactivate unit */
}
return SCPE_OK;
}
/* Chronolog clock */
uint32 chrono_rd (uint8 *buf, uint32 bufsiz)
{
time_t curtim;
t_uint64 ctr;
struct tm *tptr;
if (bufsiz < 12) return 0;
curtim = time (NULL); /* get time */
tptr = localtime (&curtim); /* decompose */
if (tptr == NULL) return 0; /* error? */
buf[0] = bcd_2d (tptr->tm_mon + 1, buf + 1);
buf[2] = bcd_2d (tptr->tm_mday, buf + 3);
buf[4] = bcd_2d (tptr->tm_hour, buf + 5);
buf[6] = bcd_2d (tptr->tm_min, buf + 7);
buf[8] = bcd_2d (tptr->tm_sec, buf + 9);
ctr = ReadP (CLK_CTR);
buf[10] = bcd_2d ((uint32) (ctr % 60), buf + 11);
return 12;
}
/* Convert number (0-99) to BCD */
uint8 bcd_2d (uint32 n, uint8 *b2)
{
uint8 d1, d2;
d1 = n / 10;
d2 = n % 10;
if (d1 == 0) d1 = BCD_ZERO;
if (d2 == 0) d2 = BCD_ZERO;
if (b2 != NULL) *b2 = d2;
return d1;
}
/* Reset routine */
t_stat clk_reset (DEVICE *dptr)
{
chtr_clk = 0;
if (clk_dev.flags & DEV_DIS) sim_cancel (&clk_unit);
else sim_activate (&clk_unit, sim_rtcn_init (clk_unit.wait, TMR_CLK));
return SCPE_OK;
}

1149
I7094/i7094_com.c Normal file

File diff suppressed because it is too large Load Diff

2239
I7094/i7094_cpu.c Normal file

File diff suppressed because it is too large Load Diff

837
I7094/i7094_cpu1.c Normal file
View File

@@ -0,0 +1,837 @@
/* i7094_cpu1.c: IBM 7094 CPU complex instructions
Copyright (c) 2003-2006, 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 "i7094_defs.h"
#define FP_HIFRAC(x) ((uint32) ((x) >> FP_N_FR) & FP_FMASK)
#define FP_LOFRAC(x) ((uint32) (x) & FP_FMASK)
#define FP_PACK38(s,e,f) (((s)? AC_S: 0) | ((t_uint64) (f)) | \
(((t_uint64) ((e) & FP_M_ACCH)) << FP_V_CH))
#define FP_PACK36(s,e,f) (((s)? SIGN: 0) | ((t_uint64) (f)) | \
(((t_uint64) ((e) & FP_M_CH)) << FP_V_CH))
extern t_uint64 AC, MQ, SI, KEYS;
extern uint32 PC;
extern uint32 SLT, SSW;
extern uint32 cpu_model, stop_illop;
extern uint32 ind_ovf, ind_dvc, ind_ioc, ind_mqo;
extern uint32 mode_ttrap, mode_strap, mode_ctrap, mode_ftrap;
extern uint32 mode_storn, mode_multi;
extern uint32 chtr_pend, chtr_inht, chtr_inhi;
extern uint32 ch_flags[NUM_CHAN];
typedef struct { /* unpacked fp */
uint32 s; /* sign: 0 +, 1 - */
int32 ch; /* exponent */
t_uint64 fr; /* fraction (54b) */
} UFP;
uint32 op_frnd (void);
t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem);
void fp_norm (UFP *op);
void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op);
uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch);
extern t_bool fp_trap (uint32 spill);
extern t_bool sel_trap (uint32 va);
extern t_stat ch_op_reset (uint32 ch, t_bool ch7909);
/* Integer add
Sherman: "As the result of an addition or subtraction, if the C(AC) is
zero, the sign of AC is unchanged." */
void op_add (t_uint64 op)
{
t_uint64 mac = AC & AC_MMASK; /* get magnitudes */
t_uint64 mop = op & MMASK;
AC = AC & AC_S; /* isolate AC sign */
if ((AC? 1: 0) ^ ((op & SIGN)? 1: 0)) { /* signs diff? sub */
if (mac >= mop) AC = AC | (mac - mop); /* AC >= MQ */
else AC = (AC ^ AC_S) | (mop - mac); /* <, sign change */
}
else {
AC = AC | ((mac + mop) & AC_MMASK); /* signs same, add */
if ((AC ^ mac) & AC_P) ind_ovf = 1; /* P change? overflow */
}
return;
}
/* Multiply */
void op_mpy (t_uint64 ac, t_uint64 sr, uint32 sc)
{
uint32 sign;
if (sc == 0) return; /* sc = 0? nop */
sign = ((MQ & SIGN)? 1: 0) ^ ((sr & SIGN)? 1: 0); /* result sign */
ac = ac & AC_MMASK; /* clear AC sign */
sr = sr & MMASK; /* mpy magnitude */
MQ = MQ & MMASK; /* MQ magnitude */
if (sr && MQ) { /* mpy != 0? */
while (sc--) { /* for sc */
if (MQ & 1) ac = (ac + sr) & AC_MMASK; /* MQ35? AC += mpy */
MQ = (MQ >> 1) | ((ac & 1) << 34); /* AC'MQ >> 1 */
ac = ac >> 1;
}
}
else ac = MQ = 0; /* result = 0 */
if (sign) { /* negative? */
ac = ac | AC_S; /* insert signs */
MQ = MQ | SIGN;
}
AC = ac; /* update AC */
return;
}
/* Divide */
t_bool op_div (t_uint64 sr, uint32 sc)
{
uint32 signa, signm;
if (sc == 0) return FALSE; /* sc = 0? nop */
signa = (AC & AC_S)? 1: 0; /* get signs */
signm = (sr & SIGN)? 1: 0;
sr = sr & MMASK; /* get dvr magn */
if ((AC & AC_MMASK) >= sr) return TRUE; /* |AC| >= |sr|? */
AC = AC & AC_MMASK; /* AC, MQ magn */
MQ = MQ & MMASK;
while (sc--) { /* for sc */
AC = ((AC << 1) & AC_MMASK) | (MQ >> 34); /* AC'MQ << 1 */
MQ = (MQ << 1) & MMASK;
if (AC >= sr) { /* AC >= dvr? */
AC = AC - sr; /* AC -= dvr */
MQ = MQ | 1; /* set quo bit */
}
}
if (signa ^ signm) MQ = MQ | SIGN; /* quo neg? */
if (signa) AC = AC | AC_S; /* rem neg? */
return FALSE; /* div ok */
}
/* Shifts */
void op_als (uint32 addr)
{
uint32 sc = addr & SCMASK;
if ((sc >= 35)? /* shift >= 35? */
((AC & MMASK) != 0): /* test all bits for ovf */
(((AC & MMASK) >> (35 - sc)) != 0)) /* test only 35-sc bits */
ind_ovf = 1;
if (sc >= 37) AC = AC & AC_S; /* sc >= 37? result 0 */
else AC = (AC & AC_S) | ((AC << sc) & AC_MMASK); /* shift, save sign */
return;
}
void op_ars (uint32 addr)
{
uint32 sc = addr & SCMASK;
if (sc >= 37) AC = AC & AC_S; /* sc >= 37? result 0 */
else AC = (AC & AC_S) | ((AC & AC_MMASK) >> sc); /* shift, save sign */
return;
}
void op_lls (uint32 addr)
{
uint32 sc; /* get sc */
AC = AC & AC_MMASK; /* clear AC sign */
for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */
AC = ((AC << 1) & AC_MMASK) | ((MQ >> 34) & 1); /* AC'MQ << 1 */
MQ = (MQ & SIGN) | ((MQ << 1) & MMASK); /* preserve MQ sign */
if (AC & AC_P) ind_ovf = 1; /* if P, overflow */
}
if (MQ & SIGN) AC = AC | AC_S; /* set ACS from MQS */
return;
}
void op_lrs (uint32 addr)
{
uint32 sc = addr & SCMASK;
t_uint64 mac;
MQ = MQ & MMASK; /* get MQ magnitude */
if (sc != 0) {
mac = AC & AC_MMASK; /* get AC magnitude, */
AC = AC & AC_S; /* sign */
if (sc < 35) { /* sc [1,34]? */
MQ = ((MQ >> sc) | (mac << (35 - sc))) & MMASK; /* MQ has AC'MQ */
AC = AC | (mac >> sc); /* AC has AC only */
}
else if (sc < 37) { /* sc [35:36]? */
MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */
AC = AC | (mac >> sc); /* AC has <QP> */
}
else if (sc < 72) /* sc [37:71]? */
MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */
else MQ = 0; /* >72? MQ = 0 */
}
if (AC & AC_S) MQ = MQ | SIGN; /* set MQS from ACS */
return;
}
void op_lgl (uint32 addr)
{
uint32 sc; /* get sc */
for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */
AC = (AC & AC_S) | ((AC << 1) & AC_MMASK) | /* AC'MQ << 1 */
((MQ >> 35) & 1); /* preserve AC sign */
MQ = (MQ << 1) & DMASK;
if (AC & AC_P) ind_ovf = 1; /* if P, overflow */
}
return;
}
void op_lgr (uint32 addr)
{
uint32 sc = addr & SCMASK;
t_uint64 mac;
if (sc != 0) {
mac = AC & AC_MMASK; /* get AC magnitude, */
AC = AC & AC_S; /* sign */
if (sc < 36) { /* sc [1,35]? */
MQ = ((MQ >> sc) | (mac << (36 - sc))) & DMASK; /* MQ has AC'MQ */
AC = AC | (mac >> sc); /* AC has AC only */
}
else if (sc == 36) { /* sc [36]? */
MQ = mac & DMASK; /* MQ = AC<P,1:35> */
AC = AC | (mac >> 36); /* AC = AC<Q> */
}
else if (sc < 73) /* sc [37, 72]? */
MQ = (mac >> (sc - 36)) & DMASK; /* MQ has AC only */
else MQ = 0; /* >72, AC,MQ = 0 */
}
return;
}
/* Plus sense - undefined operations are NOPs */
t_stat op_pse (uint32 addr)
{
uint32 ch, spill;
switch (addr) {
case 00000: /* CLM */
if (cpu_model & I_9X) AC = AC & AC_S; /* 709X only */
break;
case 00001: /* LBT */
if ((AC & 1) != 0) PC = (PC + 1) & AMASK;
break;
case 00002: /* CHS */
AC = AC ^ AC_S;
break;
case 00003: /* SSP */
AC = AC & ~AC_S;
break;
case 00004: /* ENK */
MQ = KEYS;
break;
case 00005: /* IOT */
if (ind_ioc) ind_ioc = 0;
else PC = (PC + 1) & AMASK;
break;
case 00006: /* COM */
AC = AC ^ AC_MMASK;
break;
case 00007: /* ETM */
if (cpu_model & I_9X) mode_ttrap = 1; /* 709X only */
break;
case 00010: /* RND */
if ((cpu_model & I_9X) && (MQ & B1)) /* 709X only, MQ1 set? */
op_add ((t_uint64) 1); /* incr AC */
break;
case 00011: /* FRN */
if (cpu_model & I_9X) { /* 709X only */
spill = op_frnd ();
if (spill) fp_trap (spill);
}
break;
case 00012: /* DCT */
if (ind_dvc) ind_dvc = 0;
else PC = (PC + 1) & AMASK;
break;
case 00014: /* RCT */
chtr_inhi = 1; /* 1 cycle delay */
chtr_inht = 0; /* clr inhibit trap */
chtr_pend = 0; /* no trap now */
break;
case 00016: /* LMTM */
if (cpu_model & I_94) mode_multi = 0; /* 709X only */
break;
case 00140: /* SLF */
if (cpu_model & I_9X) SLT = 0; /* 709X only */
break;
case 00141: case 00142: case 00143: case 00144: /* SLN */
if (cpu_model & I_9X) /* 709X only */
SLT = SLT | (1u << (00144 - addr));
break;
case 00161: case 00162: case 00163: /* SWT */
case 00164: case 00165: case 00166:
if ((SSW & (1u << (00166 - addr))) != 0)
PC = (PC + 1) & AMASK;
break;
case 01000: case 02000: case 03000: case 04000: /* BTT */
case 05000: case 06000: case 07000: case 10000:
if (cpu_model & I_9X) { /* 709X only */
if (sel_trap (PC)) break; /* sel trap? */
ch = GET_U_CH (addr); /* get channel */
if (ch_flags[ch] & CHF_BOT) /* BOT? */
ch_flags[ch] &= ~CHF_BOT; /* clear */
else PC = (PC + 1) & AMASK; /* else skip */
}
break;
case 001350: case 002350: case 003350: case 004350: /* RICx */
case 005350: case 006350: case 007350: case 010350:
ch = GET_U_CH (addr); /* get channel */
return ch_op_reset (ch, 1);
case 001352: case 002352: case 003352: case 004352: /* RDCx */
case 005352: case 006352: case 007352: case 010352:
ch = GET_U_CH (addr); /* get channel */
return ch_op_reset (ch, 0);
} /* end case */
return SCPE_OK;
}
/* Minus sense */
t_stat op_mse (uint32 addr)
{
uint32 t, ch;
switch (addr) {
case 00000: /* CLM */
if (cpu_model & I_9X) AC = AC & AC_S; /* 709X only */
break;
case 00001: /* PBT */
if ((AC & AC_P) != 0) PC = (PC + 1) & AMASK;
break;
case 00002: /* EFTM */
if (cpu_model & I_9X) { /* 709X only */
mode_ftrap = 1;
ind_mqo = 0; /* clears MQ ovf */
}
break;
case 00003: /* SSM */
if (cpu_model & I_9X) AC = AC | AC_S; /* 709X only */
break;
case 00004: /* LFTM */
if (cpu_model & I_9X) mode_ftrap = 0; /* 709X only */
break;
case 00005: /* ESTM */
if (cpu_model & I_9X) mode_strap = 1; /* 709X only */
break;
case 00006: /* ECTM */
if (cpu_model & I_9X) mode_ctrap = 1; /* 709X only */
break;
case 00007: /* LTM */
if (cpu_model & I_9X) mode_ttrap = 0; /* 709X only */
break;
case 00010: /* LSNM */
if (cpu_model & I_9X) mode_storn = 0; /* 709X only */
break;
case 00012: /* RTT (704) */
if (cpu_model & I_9X) sel_trap (PC); /* 709X only */
break;
case 00016: /* EMTM */
mode_multi = 1;
break;
case 00140: /* SLF */
if (cpu_model & I_9X) SLT = 0; /* 709X only */
break;
case 00141: case 00142: case 00143: case 00144: /* SLT */
if (cpu_model & I_9X) { /* 709X only */
t = SLT & (1u << (00144 - addr));
SLT = SLT & ~t;
if (t != 0) PC = (PC + 1) & AMASK;
}
break;
case 00161: case 00162: case 00163: /* SWT */
case 00164: case 00165: case 00166:
if ((cpu_model & I_9X) && /* 709X only */
((SSW & (1u << (00166 - addr))) != 0))
PC = (PC + 1) & AMASK;
break;
case 001000: case 002000: case 003000: case 004000: /* ETT */
case 005000: case 006000: case 007000: case 010000:
if (sel_trap (PC)) break; /* sel trap? */
ch = GET_U_CH (addr); /* get channel */
if (ch_flags[ch] & CHF_EOT) /* EOT? */
ch_flags[ch] = ch_flags[ch] & ~CHF_EOT; /* clear */
else PC = (PC + 1) & AMASK; /* else skip */
break;
}
return SCPE_OK;
}
/* Floating add
Notes:
- AC<Q,P> enter into the initial exponent comparison. If either is set,
the numbers are always swapped. AC<P> gets OR'd into AC<S> during the
swap, and AC<Q,P> are cleared afterwards
- The early end test is actually > 077 if AC <= SR and > 100 if
AC > SR. However, any shift >= 54 will produce a zero fraction,
so the difference can be ignored */
uint32 op_fad (t_uint64 sr, t_bool norm)
{
UFP op1, op2, t;
int32 mqch, diff;
MQ = 0; /* clear MQ */
fp_unpack (AC, 0, 1, &op1); /* unpack AC */
fp_unpack (sr, 0, 0, &op2); /* unpack sr */
if (op1.ch > op2.ch) { /* AC exp > SR exp? */
if (AC & AC_P) op1.s = 1; /* AC P or's with S */
t = op1; /* swap operands */
op1 = op2;
op2 = t;
op2.ch = op2.ch & FP_M_CH; /* clear P,Q */
}
diff = op2.ch - op1.ch; /* exp diff */
if (diff) { /* any shift? */
if ((diff < 0) || (diff > 077)) op1.fr = 0; /* diff > 63? */
else op1.fr = op1.fr >> diff; /* no, denormalize */
}
if (op1.s ^ op2.s) { /* subtract? */
if (op1.fr >= op2.fr) { /* op1 > op2? */
op2.fr = op1.fr - op2.fr; /* op1 - op2 */
op2.s = op1.s; /* op2 sign is result */
}
else op2.fr = op2.fr - op1.fr; /* else op2 - op1 */
}
else {
op2.fr = op2.fr + op1.fr; /* op2 + op1 */
if (op2.fr & FP_FCRY) { /* carry? */
op2.fr = op2.fr >> 1; /* renormalize */
op2.ch++; /* incr exp */
}
}
if (norm) { /* normalize? */
if (op2.fr) { /* non-zero frac? */
fp_norm (&op2);
mqch = op2.ch - FP_N_FR;
}
else op2.ch = mqch = 0; /* else true zero */
}
else mqch = op2.ch - FP_N_FR;
return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */
}
/* Floating multiply */
uint32 op_fmp (t_uint64 sr, t_bool norm)
{
UFP op1, op2;
int32 mqch;
uint32 f1h, f2h;
fp_unpack (MQ, 0, 0, &op1); /* unpack MQ */
fp_unpack (sr, 0, 0, &op2); /* unpack sr */
op1.s = op1.s ^ op2.s; /* result sign */
if ((op2.ch == 0) && (op2.fr == 0)) { /* sr a normal 0? */
AC = op1.s? AC_S: 0; /* result is 0 */
MQ = op1.s? SIGN: 0;
return 0;
}
f1h = FP_HIFRAC (op1.fr); /* get hi fracs */
f2h = FP_HIFRAC (op2.fr);
op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* f1h * f2h */
op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */
if (norm) { /* normalize? */
if (!(op1.fr & FP_FNORM)) { /* not normalized? */
op1.fr = op1.fr << 1; /* shift frac left 1 */
op1.ch--; /* decr exp */
}
if (FP_HIFRAC (op1.fr)) /* hi result non-zero? */
mqch = op1.ch - FP_N_FR; /* set MQ exp */
else op1.ch = mqch = 0; /* clear AC, MQ exp */
}
else mqch = op1.ch - FP_N_FR; /* set MQ exp */
return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */
}
/* Floating divide */
uint32 op_fdv (t_uint64 sr)
{
UFP op1, op2;
int32 mqch;
uint32 spill, quos;
t_uint64 rem;
fp_unpack (AC, 0, 1, &op1); /* unpack AC */
fp_unpack (sr, 0, 0, &op2); /* unpack sr */
quos = op1.s ^ op2.s; /* quotient sign */
if (op1.fr >= (2 * op2.fr)) { /* |AC| >= 2*|sr|? */
MQ = quos? SIGN: 0; /* MQ = sign only */
return TRAP_F_DVC; /* divide check */
}
if (op1.fr == 0) { /* |AC| == 0? */
MQ = quos? SIGN: 0; /* MQ = sign only */
AC = 0; /* AC = +0 */
return 0; /* done */
}
op1.ch = op1.ch & FP_M_CH; /* remove AC<Q,P> */
if (op1.fr >= op2.fr) { /* |AC| >= |sr|? */
op1.fr = op1.fr >> 1; /* denorm AC */
op1.ch++;
}
op1.fr = fp_fracdiv (op1.fr, op2.fr, &rem); /* fraction divide */
op1.fr = op1.fr | (rem << FP_N_FR); /* rem'quo */
mqch = op1.ch - op2.ch + FP_BIAS; /* quotient exp */
op1.ch = op1.ch - FP_N_FR; /* remainder exp */
spill = fp_pack (&op1, quos, mqch); /* pack up */
return (spill? (spill | TRAP_F_SGL): 0); /* if spill, set SGL */
}
/* Double floating add
Notes:
- AC<Q,P> enter into the initial exponent comparison. If either is set,
the numbers are always swapped. AC<P> gets OR'd into AC<S> during the
swap, and AC<Q,P> are cleared afterwards
- For most cases, SI ends up with the high order part of the larger number
- The 'early end' cases (smaller number is shifted away) must be tracked
exactly for SI impacts. The early end cases are:
(a) AC > SR, diff > 0100, and AC normalized
(b) AC <= SR, diff > 077, and SR normalized
In case (a), SI is unchanged. In case (b), SI ends up with the SR sign
and characteristic but the MQ (!) fraction */
uint32 op_dfad (t_uint64 sr, t_uint64 sr1, t_bool norm)
{
UFP op1, op2, t;
int32 mqch, diff;
fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */
fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */
if (op1.ch > op2.ch) { /* AC exp > SR exp? */
if (((op1.ch - op2.ch) > 0100) && (AC & B9)) ; /* early out */
else SI = FP_PACK36 (op1.s, op1.ch, FP_HIFRAC (op1.fr));
if (AC & AC_P) op1.s = 1; /* AC P or's with S */
t = op1; /* swap operands */
op1 = op2;
op2 = t;
op2.ch = op2.ch & FP_M_CH; /* clear P,Q */
}
else { /* AC <= SR */
if (((op2.ch - op1.ch) > 077) && (sr & B9)) /* early out */
SI = FP_PACK36 (op2.s, op2.ch, FP_LOFRAC (MQ));
else SI = FP_PACK36 (op2.s, op2.ch, FP_HIFRAC (op2.fr));
}
diff = op2.ch - op1.ch; /* exp diff */
if (diff) { /* any shift? */
if ((diff < 0) || (diff > 077)) op1.fr = 0; /* diff > 63? */
else op1.fr = op1.fr >> diff; /* no, denormalize */
}
if (op1.s ^ op2.s) { /* subtract? */
if (op1.fr >= op2.fr) { /* op1 > op2? */
op2.fr = op1.fr - op2.fr; /* op1 - op2 */
op2.s = op1.s; /* op2 sign is result */
}
else op2.fr = op2.fr - op1.fr; /* op2 - op1 */
}
else {
op2.fr = op2.fr + op1.fr; /* op2 + op1 */
if (op2.fr & FP_FCRY) { /* carry? */
op2.fr = op2.fr >> 1; /* renormalize */
op2.ch++; /* incr exp */
}
}
if (norm) { /* normalize? */
if (op2.fr) { /* non-zero frac? */
fp_norm (&op2);
mqch = op2.ch - FP_N_FR;
}
else op2.ch = mqch = 0; /* else true zero */
}
else mqch = op2.ch - FP_N_FR;
return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */
}
/* Double floating multiply
Notes (notation is A+B' * C+D', where ' denotes 2^-27):
- The instruction returns 0 if A and C are both zero, because B*D is never
done as part of the algorithm
- For most cases, SI ends up with B*C, with a zero sign and exponent
- For the A+B' both zero 'early end' case SI ends up with A or C,
depending on whether the operation is normalized or not */
uint32 op_dfmp (t_uint64 sr, t_uint64 sr1, t_bool norm)
{
UFP op1, op2;
int32 mqch;
uint32 f1h, f2h, f1l, f2l;
t_uint64 tx;
fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */
fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */
op1.s = op1.s ^ op2.s; /* result sign */
f1h = FP_HIFRAC (op1.fr); /* A */
f1l = FP_LOFRAC (op1.fr); /* B */
f2h = FP_HIFRAC (op2.fr); /* C */
f2l = FP_LOFRAC (op2.fr); /* D */
if (((op1.ch == 0) && (op1.fr == 0)) || /* AC'MQ normal 0? */
((op2.ch == 0) && (op2.fr == 0)) || /* sr'sr1 normal 0? */
((f1h == 0) && (f2h == 0))) { /* both hi frac zero? */
AC = op1.s? AC_S: 0; /* result is 0 */
MQ = op1.s? SIGN: 0;
SI = sr; /* SI has C */
return 0;
}
op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */
if (op1.fr) { /* A'B != 0? */
op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* A * C */
tx = ((t_uint64) f1h) * ((t_uint64) f2l); /* A * D */
op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */
tx = ((t_uint64) f1l) * ((t_uint64) f2h); /* B * C */
op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */
SI = tx >> FP_N_FR; /* SI keeps B * C */
}
else {
if (norm) SI = sr; /* early out */
else SI = FP_PACK36 (op2.s, op2.ch, 0);
}
if (norm) { /* normalize? */
if (!(op1.fr & FP_FNORM)) { /* not normalized? */
op1.fr = op1.fr << 1; /* shift frac left 1 */
op1.ch--; /* decr exp */
}
if (FP_HIFRAC (op1.fr)) { /* non-zero? */
mqch = op1.ch - FP_N_FR; /* set MQ exp */
}
else op1.ch = mqch = 0; /* clear AC, MQ exp */
}
else mqch = op1.ch - FP_N_FR; /* set MQ exp */
return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */
}
/* Double floating divide
Notes:
- This is a Taylor series expansion (where ' denotes >> 27):
(A+B') * (C+D')^-1 = (A+B') * C^-1 - (A+B') * D'* C^-2 +...
to two terms, which can be rewritten as terms Q1, Q2:
Q1 = (A+B')/C
Q2' = (R - Q1*D)'/C
- Tracking the sign of Q2' is complicated:
Q1 has the sign of the quotient, s_AC ^ s_SR
D has the sign of the divisor, s_SR
R has the sign of the dividend, s_AC
Q1*D sign is s_AC ^ s_SR ^ s^SR = s^AC
Therefore, R and Q1*D have the same sign, s_AC
Q2' sign is s^AC ^ s_SR, which is the sign of the quotient
- For first divide check, SI is 0
- For other cases, including second divide check, SI ends up with Q1
- R-Q1*D is only calculated to the high 27b; using the full 54b
throws off the result
- The second divide must check for divd >= divr, otherwise an extra
bit of quotient would be devloped, throwing off the result
- A late ECO added full post-normalization; single precision divide
does no normalization */
uint32 op_dfdv (t_uint64 sr, t_uint64 sr1)
{
UFP op1, op2;
int32 mqch;
uint32 csign, ac_s;
t_uint64 f1h, f2h, tr, tq1, tq1d, trmq1d, tq2;
fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */
fp_unpack (sr, 0, 0, &op2); /* unpack sr only */
ac_s = op1.s; /* save AC sign */
op1.s = op1.s ^ op2.s; /* sign of result */
f1h = FP_HIFRAC (op1.fr);
f2h = FP_HIFRAC (op2.fr);
if (f1h >= (2 * f2h)) { /* |A| >= 2*|C|? */
SI = 0; /* clear SI */
return TRAP_F_DVC; /* divide check */
}
if (f1h == 0) { /* |AC| == 0? */
SI = MQ = op1.s? SIGN: 0; /* MQ, SI = sign only */
AC = op1.s? AC_S: 0; /* AC = sign only */
return 0; /* done */
}
op1.ch = op1.ch & FP_M_CH; /* remove AC<Q,P> */
if (f1h >= f2h) { /* |A| >= |C|? */
op1.fr = op1.fr >> 1; /* denorm AC */
op1.ch++;
}
op1.ch = op1.ch - op2.ch + FP_BIAS; /* exp of quotient */
tq1 = fp_fracdiv (op1.fr, op2.fr, &tr); /* |A+B| / |C| */
tr = tr << FP_N_FR; /* R << 27 */
tq1d = (tq1 * ((t_uint64) FP_LOFRAC (sr1))) & /* Q1 * D */
~((t_uint64) FP_FMASK); /* top 27 bits */
csign = (tr < tq1d); /* correction sign */
if (csign) trmq1d = tq1d - tr; /* |R|<|Q1*D|? compl */
else trmq1d = tr - tq1d; /* no, subtr ok */
SI = FP_PACK36 (op1.s, op1.ch, tq1); /* SI has Q1 */
if (trmq1d >= (2 * op2.fr)) { /* |R-Q1*D| >= 2*|C|? */
AC = FP_PACK38 (csign ^ ac_s, 0, FP_HIFRAC (trmq1d)); /* AC has R-Q1*D */
MQ = (csign ^ ac_s)? SIGN: 0; /* MQ = sign only */
return TRAP_F_DVC; /* divide check */
}
tq2 = fp_fracdiv (trmq1d, op2.fr, NULL); /* |R-Q1*D| / |C| */
if (trmq1d >= op2.fr) tq2 &= ~((t_uint64) 1); /* can only gen 27b quo */
op1.fr = tq1 << FP_N_FR; /* shift Q1 into place */
if (csign) op1.fr = op1.fr - tq2; /* sub or add Q2 */
else op1.fr = op1.fr + tq2;
fp_norm (&op1); /* normalize */
if (op1.fr) mqch = op1.ch - FP_N_FR; /* non-zero? */
else op1.ch = mqch = 0; /* clear AC, MQ exp */
return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */
}
/* Floating round */
uint32 op_frnd (void)
{
UFP op;
uint32 spill;
spill = 0; /* no error */
if (MQ & B9) { /* MQ9 set? */
fp_unpack (AC, 0, 1, &op); /* unpack AC */
op.fr = op.fr + ((t_uint64) (1 << FP_N_FR)); /* round up */
if (op.fr & FP_FCRY) { /* carry out? */
op.fr = op.fr >> 1; /* renormalize */
op.ch++; /* incr exp */
if (op.ch == (FP_M_CH + 1)) /* ovf with QP = 0? */
spill = TRAP_F_OVF | TRAP_F_AC;
}
AC = FP_PACK38 (op.s, op.ch, FP_HIFRAC (op.fr)); /* pack AC */
}
return spill;
}
/* Fraction divide - 54/27'0 yielding quotient and remainder */
t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem)
{
dvr = dvr >> FP_N_FR;
if (rem) *rem = dvd % dvr;
return (dvd / dvr);
}
/* Floating point normalize */
void fp_norm (UFP *op)
{
op->fr = op->fr & FP_DFMASK; /* mask fraction */
if (op->fr == 0) return; /* zero? */
while ((op->fr & FP_FNORM) == 0) { /* until norm */
op->fr = op->fr << 1; /* lsh 1 */
op->ch--; /* decr exp */
}
return;
}
/* Floating point unpack */
void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op)
{
if (q_ac) { /* AC? */
op->s = (h & AC_S)? 1: 0; /* get sign */
op->ch = (uint32) ((h >> FP_V_CH) & FP_M_ACCH); /* get exp */
}
else {
op->s = (h & SIGN)? 1: 0; /* no, mem */
op->ch = (uint32) ((h >> FP_V_CH) & FP_M_CH);
}
op->fr = (((t_uint64) FP_LOFRAC (h)) << FP_N_FR) | /* get frac hi */
((t_uint64) FP_LOFRAC (l)); /* get frac lo */
return;
}
/* Floating point pack */
uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch)
{
uint32 spill;
AC = FP_PACK38 (op->s, op->ch, FP_HIFRAC (op->fr)); /* pack AC */
MQ = FP_PACK36 (mqs, mqch, FP_LOFRAC (op->fr)); /* pack MQ */
if (op->ch > FP_M_CH) spill = TRAP_F_OVF | TRAP_F_AC; /* check AC exp */
else if (op->ch < 0) spill = TRAP_F_AC;
else spill = 0;
if (mqch > FP_M_CH) spill |= (TRAP_F_OVF | TRAP_F_MQ); /* check MQ exp */
else if (mqch < 0) spill |= TRAP_F_MQ;
return spill;
}

152
I7094/i7094_dat.h Normal file
View File

@@ -0,0 +1,152 @@
/* i7094_dat.h: IBM 7094 data conversion tables
Copyright (c) 2003-2006, 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.
*/
/* Nine-code to ASCII conversion */
const char nine_to_ascii_a[64] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '^', '#', '@', ':', '>', '{',
'&', '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', '|', ',', '%', '~', '\\', '"',
};
const char nine_to_ascii_h[64] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '^', '=', '\'', ':', '>', '{',
'+', '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', '|', ',', '(', '~', '\\', '"',
};
/* ASCII to nine-code conversion */
const char ascii_to_nine[128] = {
060, 060, 060, 060, 060, 060, 060, 060, /* 000 - 037 */
060, 060, 060, 060, 060, 060, 060, 060,
060, 060, 060, 060, 060, 060, 060, 060,
060, 060, 060, 060, 060, 060, 060, 060,
060, 052, 077, 013, 053, 074, 020, 014, /* 040 - 077 */
074, 034, 054, 020, 073, 040, 033, 061,
000, 001, 002, 003, 004, 005, 006, 007,
010, 011, 015, 056, 036, 013, 016, 032,
014, 021, 022, 023, 024, 025, 026, 027, /* 100 - 137 */
030, 031, 041, 042, 043, 044, 045, 046,
047, 050, 051, 062, 063, 064, 065, 066,
067, 070, 071, 035, 076, 055, 012, 057,
060, 021, 022, 023, 024, 025, 026, 027, /* 140 - 177 */
030, 031, 041, 042, 043, 044, 045, 046,
047, 050, 051, 062, 063, 064, 065, 066,
067, 070, 071, 017, 072, 037, 075, 060
};
/* ASCII to BCD conversion */
const char ascii_to_bcd[128] = {
000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */
000, 000, 000, 000, 000, 000, 000, 000,
000, 000, 000, 000, 000, 000, 000, 000,
000, 000, 000, 000, 000, 000, 000, 000,
000, 052, 037, 013, 053, 074, 060, 014, /* 040 - 077 */
034, 074, 054, 060, 033, 040, 073, 021,
020, 001, 002, 003, 004, 005, 006, 007,
010, 011, 015, 056, 076, 013, 016, 072,
014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */
070, 071, 041, 042, 043, 044, 045, 046,
047, 050, 051, 022, 023, 024, 025, 026,
027, 030, 031, 075, 036, 055, 012, 057,
000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */
070, 071, 041, 042, 043, 044, 045, 046,
047, 050, 051, 022, 023, 024, 025, 026,
027, 030, 031, 017, 032, 077, 035, 000
};
/* BCD to ASCII conversion */
const char bcd_to_ascii_a[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '^', '#', '@', ':', '>', '{',
'0', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '|', ',', '%', '~', '\\', '"',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '_',
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '?', '.', ')', '[', '<', '}'
};
const char bcd_to_ascii_h[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '^', '=', '\'', ':', '>', '{',
'0', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '|', ',', '(', '~', '\\', '"',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '_',
'+', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '?', '.', ')', '[', '<', '}'
};
/* BCD to ASCII 48 character print chains */
const char bcd_to_pca[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ' ', '#', '@', ' ', ' ', ' ',
'0', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', ' ', ',', '%', ' ', ' ', ' ',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '-', '$', '*', ' ', ' ', ' ',
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '&', '.', ')', ' ', ' ', ' '
};
const char bcd_to_pch[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ' ', '=', '\'', ' ', ' ', ' ',
'0', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', ' ', ',', '(', ' ', ' ', ' ',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '-', '$', '*', ' ', ' ', ' ',
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '&', '.', ')', ' ', ' ', ' '
};
/* BCD to column binary conversion */
const uint32 bcd_to_colbin[64] = {
00000, 00400, 00200, 00100, 00040, 00020, 00010, 00004,
00002, 00001, 00202, 00102, 00042, 00022, 00012, 00006,
01000, 01400, 01200, 01100, 01040, 01020, 01010, 01004,
01002, 01001, 01202, 01102, 01042, 01022, 01012, 01006,
02000, 02400, 02200, 02100, 02040, 02020, 02010, 02004,
02002, 02001, 02202, 02102, 02042, 02022, 02012, 02006,
04000, 04400, 04200, 04100, 04040, 04020, 04010, 04004,
04002, 04001, 04202, 04102, 04042, 04022, 04012, 04006
};

474
I7094/i7094_defs.h Normal file
View File

@@ -0,0 +1,474 @@
/* i7094_defs.h: IBM 7094 simulator definitions
Copyright (c) 2003-2006, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This simulator incorporates prior work by Paul Pierce, Dave Pitts, and Rob
Storey. Tom Van Vleck, Stan Dunten, Jerry Saltzer, and other CTSS veterans
helped to reconstruct the CTSS hardware RPQ's. Dave Pitts gets special
thanks for patiently coaching me through IBSYS debug. */
#ifndef _I7094_DEFS_H_
#define _I7094_DEFS_H_ 0
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_HALT 1 /* halted */
#define STOP_IBKPT 2 /* breakpoint */
#define STOP_ILLEG 3 /* illegal instr */
#define STOP_DIVCHK 4 /* divide check */
#define STOP_XEC 5 /* XCT loop */
#define STOP_ASTOP 6 /* address stop */
#define STOP_NXCHN 7 /* nx channel */
#define STOP_7909 8 /* ill inst to 7909 */
#define STOP_NT7909 9 /* ill inst to !7909 */
#define STOP_NXDEV 10 /* nx device */
#define STOP_ILLCHI 11 /* illegal channel op */
#define STOP_WRP 12 /* write protect */
#define STOP_ILLIOP 13 /* illegal I/O op */
#define STOP_INVFMT 14 /* invalid disk format */
#define STOP_NOIFREE 15 /* 7750: no buf for inp */
#define STOP_NOOFREE 16 /* 7750: no buf for out */
#define STOP_INVLIN 17 /* 7750: invalid line# */
#define STOP_INVMSG 18 /* 7750: invalid message */
#define STOP_CHBKPT 19 /* channel breakpoint */
/* Simulator error codes */
#define ERR_STALL 40 /* stall */
#define ERR_ENDRC 41 /* end rec */
#define ERR_NRCF 42 /* no record found */
/* Instruction history - flags in left half of pc entry */
#define HIST_PC 0x04000000 /* CPU */
#define HIST_V_CH 28 /* chan + 1 */
#define HIST_M_CH 0xF
#define HIST_CH(x) (((x) >> HIST_V_CH) & HIST_M_CH)
typedef struct {
uint32 pc;
uint32 ea;
uint32 rpt;
t_uint64 ir;
t_uint64 ac;
t_uint64 mq;
t_uint64 si;
t_uint64 opnd;
} InstHistory;
/* Architectural constants */
#define A704_SIZE 14 /* addr width, 704 mode */
#define ASIZE 15 /* inst addr width */
#define PASIZE 16 /* phys addr width */
#define STDMEMSIZE (1u << ASIZE) /* standard memory */
#define MAXMEMSIZE (1u << PASIZE) /* maximum memory */
#define A704_MASK ((1u << A704_SIZE) - 1)
#define PAMASK ((1u << PASIZE) - 1)
#define MEMSIZE (cpu_unit.capac)
#define BCORE_V (ASIZE) /* (CTSS) A/B core sel */
#define BCORE_BASE (1u << BCORE_V) /* (CTSS) B core base */
/* Traps */
#define TRAP_STD_SAV 000000 /* trap save location */
#define TRAP_TRA_PC 000001 /* trap PC: transfer */
#define TRAP_STR_PC 000002 /* trap PC: STR */
#define TRAP_FP_PC 000010 /* trap PC: flt point */
#define TRAP_PROT_SAV 000032 /* protection trap save */
#define TRAP_PROT_PC 000033 /* protection trap PC */
#define TRAP_704_SAV 040000 /* 704 compat trap */
#define TRAP_SEL_PC 040001 /* 704 trap PC: select */
#define TRAP_CPY_PC 040002 /* 704 trap PC: copy */
#define TRAP_F_MQ 000001 /* MQ error */
#define TRAP_F_AC 000002 /* AC error */
#define TRAP_F_OVF 000004 /* overflow */
#define TRAP_F_SGL 000010 /* single precision */
#define TRAP_F_DVC 000020 /* fake: divide check */
#define TRAP_F_ODD 000040 /* odd address */
#define TRAP_F_BDATA 020000 /* (CTSS) data B core */
#define TRAP_F_BINST 040000 /* (CTSS) inst B core */
/* Integer */
#define DMASK 0777777777777 /* data mask */
#define SIGN 0400000000000 /* sign */
#define MMASK 0377777777777 /* magnitude mask */
#define LMASK 0777777000000 /* left mask */
#define RMASK 0000000777777 /* right mask */
#define PMASK 0700000000000 /* prefix */
#define XMASK 0077777000000 /* decrement */
#define TMASK 0000000700000 /* tag */
#define AMASK 0000000077777 /* address */
#define SCMASK 0000000000377 /* shift count mask */
#define B1 0200000000000 /* bit 1 */
#define B9 0000400000000 /* bit 9 */
/* Accumulator is actually 38b wide */
#define AC_S 02000000000000 /* sign */
#define AC_Q 01000000000000 /* Q */
#define AC_P 00400000000000 /* P */
#define AC_MMASK 01777777777777 /* Q+P+magnitude */
/* Floating point */
#define FP_N_FR 27 /* fraction bits */
#define FP_FMASK ((1u << FP_N_FR) - 1)
#define FP_N_DFR 54 /* double fraction bits */
#define FP_DFMASK ((((t_uint64) 1) << FP_N_DFR) - 1)
#define FP_FNORM (((t_uint64) 1u) << (FP_N_DFR - 1)) /* normalized bit */
#define FP_FCRY (((t_uint64) 1u) << FP_N_DFR) /* fraction carry */
#define FP_BIAS 0200 /* exponent bias */
#define FP_V_CH (FP_N_FR) /* exponent */
#define FP_M_CH 0377 /* SR char mask */
#define FP_M_ACCH 01777 /* AC char mask incl Q,P */
/* Instruction format */
#define INST_T_DEC 0300000000000 /* if nz, takes decr */
#define INST_T_CXR1 0000000100000 /* if nz, update XR1 */
#define INST_V_OPD 33 /* decrement opcode */
#define INST_M_OPD 07
#define INST_V_DEC 18 /* decrement */
#define INST_M_DEC 077777
#define INST_V_OPC 24 /* normal opcode */
#define INST_M_OPC 0777
#define INST_V_IND 22 /* indirect */
#define INST_IND (3 << INST_V_IND)
#define INST_V_CCNT 18 /* convert count */
#define INST_M_CCNT 0377
#define INST_V_VCNT 18 /* vlm/vdh count */
#define INST_M_VCNT 077
#define INST_V_TAG 15 /* index */
#define INST_M_TAG 07
#define INST_V_ADDR 0
#define INST_M_ADDR 077777
#define GET_OPD(x) ((uint32) (((x) >> INST_V_OPD) & INST_M_OPD))
#define GET_DEC(x) ((uint32) (((x) >> INST_V_DEC) & INST_M_DEC))
#define GET_OPC(x) (((uint32) (((x) >> INST_V_OPC) & INST_M_OPC)) | \
(((x) & SIGN)? 01000: 0))
#define TST_IND(x) (((x) & INST_IND) == INST_IND)
#define GET_CCNT(x) ((uint32) (((x) >> INST_V_CCNT) & INST_M_CCNT))
#define GET_VCNT(x) ((uint32) (((x) >> INST_V_VCNT) & INST_M_VCNT))
#define GET_TAG(x) ((uint32) (((x) >> INST_V_TAG) & INST_M_TAG))
/* Instruction decode flags */
#define I_4X 0x01 /* 7040, 7044 */
#define I_9X 0x02 /* 7090, 7094, CTSS */
#define I_94 0x04 /* 7094, CTSS */
#define I_CT 0x08 /* CTSS */
#define I_MODEL 0x0F /* option mask */
#define I_X 0x10 /* indexed */
#define I_N 0x20 /* indirect */
#define I_R 0x40 /* read */
#define I_D 0x80 /* double read */
#define I_XN (I_X|I_N)
#define I_XNR (I_X|I_N|I_R)
#define I_XND (I_X|I_N|I_D)
/* Memory protection (CTSS) */
#define VA_V_OFF 0 /* offset in block */
#define VA_N_OFF 8 /* width of offset */
#define VA_M_OFF ((1u << VA_N_OFF) - 1)
#define VA_OFF (VA_M_OFF << VA_V_OFF)
#define VA_V_BLK (VA_N_OFF) /* block */
#define VA_N_BLK (ASIZE - VA_N_OFF) /* width of block */
#define VA_M_BLK ((1u << VA_N_BLK) - 1)
#define VA_BLK (VA_M_BLK << VA_V_BLK)
/* Unsigned operations */
#define NEG(x) (~(x) + 1)
#define BIT_TST(w,b) (((w) >> (b)) & 1)
/* Device information block */
typedef struct {
t_stat (*chsel)(uint32 ch, uint32 sel, uint32 u);
t_stat (*write)(uint32 ch, t_uint64 val, uint32 flags);
} DIB;
/* BCD digits */
#define BCD_MASK 017
#define BCD_ZERO 012
#define BCD_ONE 001
#define BCD_TWO 002
#define BCD_AT 014
/* Channels */
#define NUM_CHAN 8 /* # channels */
#define CH_A 0 /* channel A */
#define CH_B 1
#define CH_C 2
#define CH_D 3
#define CH_E 4
#define CH_F 5
#define CH_G 6
#define CH_H 7
#define REQ_CH(x) (1u << (x))
/* All channel commands */
#define CHI_IND 0000000400000 /* ch inst indirect */
/* Channel selects - all channels */
#define CHSL_RDS 0001 /* data selects */
#define CHSL_WRS 0002
#define CHSL_SNS 0003
#define CHSL_CTL 0004
#define CHSL_FMT 0005
#define CHSL_WEF 0010 /* non-data selects */
#define CHSL_WBT 0011 /* 704X only */
#define CHSL_BSR 0012
#define CHSL_BSF 0013
#define CHSL_REW 0014
#define CHSL_RUN 0015
#define CHSL_SDN 0016
#define CHSL_2ND 0020 /* second state */
#define CHSL_3RD 0040 /* etc */
#define CHSL_4TH 0060
#define CHSL_5TH 0100
#define CHSL_NDS 0010 /* non-data sel flag */
#define CHSL_NUM 16
/* Channel commands - 7607/7289 - S12'19 */
#define CH6I_NST 0000000200000 /* ch inst no store */
#define CH6_IOCD 000
#define CH6_TCH 002
#define CH6_IORP 004
#define CH6_IORT 006
#define CH6_IOCP 010
#define CH6_IOCT 012
#define CH6_IOSP 014
#define CH6_IOST 016
#define CH6_OPMASK 016 /* without nostore */
#define TCH_LIMIT 5 /* TCH autoresolve limit */
/* Channel data flags - 7607 */
#define CH6DF_EOR 1 /* end of record */
#define CH6DF_VLD 2 /* input valid */
/* Channel commands - 7909 - S123'19 */
#define CH9_WTR 000
#define CH9_XMT 001
#define CH9_TCH 004
#define CH9_LIPT 005
#define CH9_CTL 010
#define CH9_CTLR 011
#define CH9_CTLW 012
#define CH9_SNS 013
#define CH9_LAR 014
#define CH9_SAR 015
#define CH9_TWT 016
#define CH9_CPYP 020
#define CH9_CPYD 024
#define CH9_TCM 025
#define CH9_LIP 031
#define CH9_TDC 032
#define CH9_LCC 033
#define CH9_SMS 034
#define CH9_ICC 035
#define CH9_ICCA 037 /* ignores bit <3> */
#define CH9_OPMASK 037
/* Channel data flags - 7909 */
#define CH9DF_STOP 1 /* stop */
#define CH9DF_VLD 2 /* input valid */
/* Extended parts of the command come from the decrement, stored in ch_wc */
#define CH9D_V_MASK 0 /* condition mask */
#define CH9D_M_MASK 077
#define CH9D_V_COND 12 /* condition select */
#define CH9D_M_COND 07
#define CH9D_MASK(x) (((x) >> CH9D_V_MASK) & CH9D_M_MASK)
#define CH9D_COND(x) (((x) >> CH9D_V_COND) & CH9D_M_COND)
#define CH9D_NST 020000 /* no store */
#define CH9D_B11 000100
/* Or from the effective address, stored in ch_ca */
#define CH9A_V_LCC 0 /* counter */
#define CH9A_M_LCC 077
#define CH9A_V_SMS 0 /* system mask */
#define CH9A_M_SMS 0177
#define CH9A_LCC(x) (((x) >> CH9A_V_LCC) & CH9A_M_LCC)
#define CH9A_SMS(x) (((x) >> CH9A_V_SMS) & CH9A_M_SMS)
/* Channel states - common */
#define CHXS_IDLE 0 /* idle */
#define CHXS_DSX 1 /* executing */
/* Channel states - 7607/7289 */
#define CH6S_PNDS 2 /* polling NDS */
#define CH6S_PDS 3 /* polling DS */
#define CH6S_NDS 4 /* nds, executing */
#define CH6S_DSW 5 /* ds, chan wait */
/* Channel traps - 7909 has only CMD (== TWT) */
#define CHTR_V_CME 0 /* cmd/eof enable */
#define CHTR_V_CLK 17 /* clock */
#define CHTR_V_TRC 18 /* tape check */
#define CHTR_V_TWT (CHTR_V_CME)
#define CHTR_CLK_SAV 006 /* clock */
#define CHTR_CHA_SAV 012 /* start of chan block */
#define CHTR_F_CMD 1 /* CMD flag (in decr) */
#define CHTR_F_TRC 2 /* TRC flag (in decr) */
#define CHTR_F_EOF 4 /* EOF flag (in decr) */
/* Channel interrupts - 7909 only */
#define CHINT_CHA_SAV 042 /* start of chan block */
/* Channel interrupt conditions - 7909 only */
#define CHINT_ADPC 001 /* adapter check */
#define CHINT_ATN2 002 /* attention 2 - ni */
#define CHINT_ATN1 004 /* attention 1 */
#define CHINT_UEND 010 /* unusual end */
#define CHINT_SEQC 020 /* sequence check */
#define CHINT_IOC 040 /* IO check */
/* Channel SMS flags - 7909 only */
#define CHSMS_SEL2 0001 /* select 2nd - ni */
#define CHSMS_IATN2 0002 /* inhibit atn2 - ni */
#define CHSMS_IATN1 0004 /* inhibit atn1 */
#define CHSMS_IUEND 0010 /* inhibit uend */
#define CHSMS_BCD 0020 /* BCD conversion - ni */
#define CHSMS_RBCK 0040 /* read backwards - ni */
#define CHSMS_ENCI 0100 /* enable noncon - ni */
/* Channel flags (7607 in right half, 7909 in left half) */
#define CHF_CMD 00000000001 /* cmd done */
#define CHF_TWT (CHF_CMD)
#define CHF_TRC 00000000002 /* tape check */
#define CHF_EOF 00000000004 /* end of file */
#define CHF_BOT 00000000010 /* beginning of tape */
#define CHF_EOT 00000000020 /* end of tape */
#define CHF_LDW 00000000040 /* LCH waiting */
#define CHF_EOR 00000000100 /* end of record */
#define CHF_IRQ 00001000000 /* intr request */
#define CHF_INT 00002000000 /* intr in prog */
#define CHF_WRS 00004000000 /* write */
#define CHF_RDS 00010000000 /* read */
#define CHF_PWR 00020000000 /* prepare to write */
#define CHF_PRD 00040000000 /* prepare to read */
#define CHF_V_COND 24 /* cond register */
#define CHF_M_COND 077
#define CHF_ADPC (CHINT_ADPC << CHF_V_COND) /* adapter check */
#define CHF_ATN2 (CHINT_ATN2 << CHF_V_COND) /* attention 2 */
#define CHF_ATN1 (CHINT_ATN1 << CHF_V_COND) /* attention 1 */
#define CHF_UEND (CHINT_UEND << CHF_V_COND) /* unusual end */
#define CHF_SEQC (CHINT_SEQC << CHF_V_COND) /* sequence check */
#define CHF_IOC (CHINT_IOC << CHF_V_COND) /* IO check */
#define CHF_V_LCC 30 /* loop ctrl counter */
#define CHF_M_LCC 077
#define CHF_CLR_7909 07775000177 /* 7909 clear flags */
#define CHF_SDC_7909 07776000000 /* 7909 SDC flags */
/* Channel characteristics (in dev.flags) */
#define DEV_7909 (1u << (DEV_V_UF + 0))
#define DEV_7289 (1u << (DEV_V_UF + 1))
#define DEV_CDLP (1u << (DEV_V_UF + 2))
#define DEV_7750 (1u << (DEV_V_UF + 3))
#define DEV_7631 (1u << (DEV_V_UF + 4))
/* Unit addresses - 7607/7289 only */
#define U_V_CH 9 /* channel number */
#define U_M_CH 077
#define U_V_UNIT 0
#define U_M_UNIT 0777
#define GET_U_CH(x) (((((uint32) (x)) >> U_V_CH) & U_M_CH) - 1)
#define GET_U_UNIT(x) ((((uint32) (x)) >> U_V_UNIT) & U_M_UNIT)
#define U_MTBCD 0201 /* BCD tape */
#define U_MTBIN 0221 /* binary tape */
#define U_CDR 0321 /* card reader */
#define U_CDP 0341 /* card punch */
#define U_LPBCD 0361 /* BCD print */
#define U_LPBIN 0362 /* binary print */
#define U_DRM 0330 /* 7320A drum */
#define MT_NUMDR 10
/* CTSS Chronolog clock */
#define CHRONO_CH (CH_A) /* channel A */
#define CHRONO_UNIT (7) /* unit 7 */
/* Interval timer */
#define CLK_CTR 05 /* counter */
#define CLK_TPS 60 /* 60Hz */
#define TMR_CLK 0 /* use timer 0 */
#define TMR_COM 1 /* 7750 timer */
/* Function prototypes and macros */
#define ReadP(p) M[p]
#define WriteP(p,d) M[p] = d
void cpu_ent_hist (uint32 pc, uint32 ea, t_uint64 ir, t_uint64 opnd);
t_stat ch_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat ch6_end_nds (uint32 ch);
uint32 ch6_set_flags (uint32 ch, uint32 unit, uint32 flags);
t_stat ch6_err_disc (uint32 ch, uint32 unit, uint32 flags);
t_stat ch6_req_rd (uint32 ch, uint32 unit, t_uint64 val, uint32 flags);
t_stat ch6_req_wr (uint32 ch, uint32 unit);
t_bool ch6_qconn (uint32 ch, uint32 unit);
t_stat ch9_req_rd (uint32 ch, t_uint64 val);
void ch9_set_atn (uint32 ch);
void ch9_set_ioc (uint32 ch);
void ch9_set_end (uint32 ch, uint32 ireq);
t_bool ch9_qconn (uint32 ch);
void ch_set_map (void);
t_bool ch_qidle (void);
#endif

286
I7094/i7094_drm.c Normal file
View File

@@ -0,0 +1,286 @@
/* i7094_drm.c: 7289/7320A drum simulator
Copyright (c) 2005-2006, 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.
drm 7289/7320A "fast" drum
Very little is known about this device; the behavior simulated here is
what is used by CTSS.
- The drum channel/controller behaves like a hybrid of the 7607 and the 7909.
It responds to SCD (like the 7909), gets its address from the channel
program (like the 7909), but responds to IOCD/IOCP (like the 7607) and
sets channel flags (like the 7607).
- The drum channel supports at least 2 drums. The maximum is 8 or less.
Physical drums are numbered from 0.
- Each drum has a capacity of 192K 36b words. This is divided into 6
"logical" drum of 32KW each. Each "logical" drum has 16 2048W "sectors".
Logical drums are numbered from 1.
- The drum's behavior if a sector boundary is crossed in mid-transfer is
unknown. CTSS never does this.
- The drum's behavior with record operations is unknown. CTSS only uses
IOCD and IOCP.
- The drum's error indicators are unknown. CTSS regards bits <0:2,13> of
the returned SCD data as errors, as well as the normal 7607 trap flags.
- The drum's rotational speed is unknown.
Assumptions in this simulator:
- Transfers may not cross a sector boundary. An attempt to do so sets
the EOF flag and causes an immediate disconnect.
- The hardware never sets end of record.
For speed, the entire drum is buffered in memory.
*/
#include "i7094_defs.h"
#include <math.h>
#define DRM_NUMDR 8 /* drums/controller */
/* Drum geometry */
#define DRM_NUMWDS 2048 /* words/sector */
#define DRM_SCMASK (DRM_NUMWDS - 1) /* sector mask */
#define DRM_NUMSC 16 /* sectors/log drum */
#define DRM_NUMWDL (DRM_NUMWDS * DRM_NUMSC) /* words/log drum */
#define DRM_NUMLD 6 /* log drums/phys drum */
#define DRM_SIZE (DRM_NUMLD * DRM_NUMWDL) /* words/phys drum */
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DRM_NUMWDS)))
/* Drum address from channel */
#define DRM_V_PHY 30 /* physical drum sel */
#define DRM_M_PHY 07
#define DRM_V_LOG 18 /* logical drum sel */
#define DRM_M_LOG 07
#define DRM_V_WDA 0 /* word address */
#define DRM_M_WDA (DRM_NUMWDL - 1)
#define DRM_GETPHY(x) (((uint32) ((x) >> DRM_V_PHY)) & DRM_M_PHY)
#define DRM_GETLOG(x) ((((uint32) (x)) >> DRM_V_LOG) & DRM_M_LOG)
#define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA)
#define DRM_GETDA(x) (((DRM_GETLOG(x) - 1) * DRM_NUMWDL) + DRM_GETWDA(x))
/* Drum controller states */
#define DRM_IDLE 0
#define DRM_1ST 1
#define DRM_DATA 2
#define DRM_EOS 3
uint32 drm_ch = CH_G; /* drum channel */
uint32 drm_da = 0; /* drum address */
uint32 drm_sta = 0; /* state */
uint32 drm_op = 0; /* operation */
t_uint64 drm_chob = 0; /* output buf */
uint32 drm_chob_v = 0; /* valid */
int32 drm_time = 10; /* inter-word time */
extern uint32 ind_ioc;
t_stat drm_svc (UNIT *uptr);
t_stat drm_reset (DEVICE *dptr);
t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit);
t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags);
t_bool drm_da_incr (void);
/* DRM data structures
drm_dev DRM device descriptor
drm_unit DRM unit descriptor
drm_reg DRM register list
*/
DIB drm_dib = { &drm_chsel, &drm_chwr };
UNIT drm_unit[] = {
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) },
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }
};
REG drm_reg[] = {
{ ORDATA (STATE, drm_sta, 2) },
{ ORDATA (DA, drm_da, 18) },
{ FLDATA (OP, drm_op, 0) },
{ ORDATA (CHOB, drm_chob, 36) },
{ FLDATA (CHOBV, drm_chob_v, 0) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
{ DRDATA (CHAN, drm_ch, 3), REG_HRO },
{ NULL }
};
MTAB drm_mtab[] = {
{ MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, NULL, &ch_show_chan },
{ 0 }
};
DEVICE drm_dev = {
"DRM", drm_unit, drm_reg, drm_mtab,
DRM_NUMDR, 8, 18, 1, 8, 36,
NULL, NULL, &drm_reset,
NULL, NULL, NULL,
&drm_dib, DEV_DIS
};
/* Channel select routine */
t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit)
{
drm_ch = ch; /* save channel */
if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */
switch (sel) { /* case on cmd */
case CHSL_RDS: /* read */
case CHSL_WRS: /* write */
if (drm_sta != DRM_IDLE) return ERR_STALL; /* busy? */
drm_sta = DRM_1ST; /* initial state */
if (sel == CHSL_WRS) drm_op = 1; /* set read/write */
else drm_op = 0; /* LCHx sends addr */
break; /* wait for addr */
default: /* other */
return STOP_ILLIOP;
}
return SCPE_OK;
}
/* Channel write routine */
t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags)
{
uint32 u, l;
int32 cp, dp;
if (drm_sta == DRM_1ST) {
u = DRM_GETPHY (val); /* get unit */
l = DRM_GETLOG (val); /* get logical address */
if ((u >= DRM_NUMDR) || /* invalid unit? */
(drm_unit[u].flags & UNIT_DIS) || /* disabled unit? */
(l == 0) || (l > DRM_NUMLD)) { /* invalid log drum? */
ch6_err_disc (ch, U_DRM, CHF_TRC); /* disconnect */
drm_sta = DRM_IDLE;
return SCPE_OK;
}
drm_da = DRM_GETDA (val); /* get drum addr */
cp = GET_POS (drm_time); /* current pos in sec */
dp = (drm_da & DRM_SCMASK) - cp; /* delta to desired pos */
if (dp <= 0) dp = dp + DRM_NUMWDS; /* if neg, add rev */
sim_activate (&drm_unit[u], dp * drm_time); /* schedule */
if (drm_op) ch6_req_wr (ch, U_DRM); /* if write, get word */
drm_sta = DRM_DATA;
drm_chob = 0; /* clr, inval buffer */
drm_chob_v = 0;
}
else {
drm_chob = val & DMASK;
drm_chob_v = 1;
}
return SCPE_OK;
}
/* Unit service - this code assumes the entire drum is buffered */
t_stat drm_svc (UNIT *uptr)
{
t_uint64 *fbuf = (t_uint64 *) uptr->filebuf;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? */
ch6_err_disc (drm_ch, U_DRM, CHF_TRC); /* set TRC, disc */
drm_sta = DRM_IDLE; /* drum is idle */
return SCPE_UNATT;
}
if (drm_da >= DRM_SIZE) { /* nx logical drum? */
ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */
drm_sta = DRM_IDLE; /* drum is idle */
return SCPE_OK;
}
switch (drm_sta) { /* case on state */
case DRM_DATA: /* data */
if (drm_op) { /* write? */
if (drm_chob_v) drm_chob_v = 0; /* valid? clear */
else if (ch6_qconn (drm_ch, U_DRM)) /* no, chan conn? */
ind_ioc = 1; /* io check */
fbuf[drm_da] = drm_chob; /* get data */
if (drm_da >= uptr->hwmark) uptr->hwmark = drm_da + 1;
if (!drm_da_incr ()) ch6_req_wr (drm_ch, U_DRM);
}
else{ /* read */
ch6_req_rd (drm_ch, U_DRM, fbuf[drm_da], 0); /* send word to channel */
drm_da_incr ();
}
sim_activate (uptr, drm_time); /* next word */
break;
case DRM_EOS: /* end sector */
if (ch6_qconn (drm_ch, U_DRM)) /* drum still conn? */
ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */
drm_sta = DRM_IDLE; /* drum is idle */
break;
} /* end case */
return SCPE_OK;
}
/* Increment drum address - return true, set new state if end of sector */
t_bool drm_da_incr (void)
{
drm_da = drm_da + 1;
if (drm_da & DRM_SCMASK) return FALSE;
drm_sta = DRM_EOS;
return TRUE;
}
/* Reset routine */
t_stat drm_reset (DEVICE *dptr)
{
uint32 i;
drm_da = 0;
drm_op = 0;
drm_sta = DRM_IDLE;
drm_chob = 0;
drm_chob_v = 0;
for (i = 0; i < dptr->numunits; i++) sim_cancel (dptr->units + i);
return SCPE_OK;
}

1172
I7094/i7094_dsk.c Normal file

File diff suppressed because it is too large Load Diff

1789
I7094/i7094_io.c Normal file

File diff suppressed because it is too large Load Diff

365
I7094/i7094_lp.c Normal file
View File

@@ -0,0 +1,365 @@
/* i7094_lp.c: IBM 716 line printer simulator
Copyright (c) 2003-2006, 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.
lpt 716 line printer
Internally, the 7094 works only with column binary and is limited to
72 columns of data. Each row of the printed line is represented by
72b of data (two 36b words). A complete print line consists of 12 rows
(24 36b words).
The printer can also echo part of what it prints, namely, the digit rows
plus the 8+3 and 8+4 combinations. This was intended for verification of
check printing. Echoed data is interspersed with output data in the
following order:
output row 9 to row 1
echo row "8+4"
output row 0
echo row "8+3"
output row 11
echo row 9
output row 12
echo row 8 to row 1
*/
#include "i7094_defs.h"
#define UNIT_V_CONS (UNIT_V_UF + 0) /* print to console */
#define UNIT_CONS (1u << UNIT_V_CONS)
#define UNIT_V_BZ (UNIT_V_UF + 1)
#define UNIT_V_48 (UNIT_V_UF + 2)
#define UNIT_BZ (1 << UNIT_V_BZ)
#define UNIT_48 (1 << UNIT_V_48)
#define GET_PCHAIN(x) (((x) >> UNIT_V_BZ) & (UNIT_BZ|UNIT_48))
#define LPT_BINLNT 24 /* bin buffer length */
#define LPT_ECHLNT 22 /* echo buffer length */
#define LPT_CHRLNT 80 /* char buffer length */
#define LPS_INIT 0 /* init state */
#define LPS_DATA 1 /* print data state */
#define ECS_DATA 2 /* echo data state */
#define LPS_END 3 /* end state */
#define LPB_9ROW 0 /* bin buf: 9 row */
#define LPB_8ROW 2 /* 8 row */
#define LPB_4ROW 10 /* 4 row */
#define LPB_3ROW 12 /* 3 row */
#define LPB_1ROW 16 /* 1 row */
#define LPB_12ROW 22 /* 12 row */
#define ECB_84ROW 0 /* echo buf: 8-4 row */
#define ECB_83ROW 2 /* 8-3 row */
#define ECB_9ROW 4 /* 9 row */
#define ECHO_F 0100 /* echo map: flag */
#define ECHO_MASK 0037 /* mask */
#define CMD_BIN 1 /* cmd: bcd/bin */
#define CMD_ECHO 2 /* cmd: wrs/rds */
uint32 lpt_sta = 0; /* state */
uint32 lpt_bptr = 0; /* buffer ptr */
uint32 lpt_cmd = 0; /* modes */
uint32 lpt_tstart = 27500; /* timing */
uint32 lpt_tstop = 27500;
uint32 lpt_tleft = 150;
uint32 lpt_tright = 4000;
t_uint64 lpt_chob = 0;
uint32 lpt_chob_v = 0;
t_uint64 lpt_bbuf[LPT_BINLNT]; /* binary buffer */
t_uint64 lpt_ebuf[LPT_ECHLNT]; /* echo buffer */
/* Echo ordering map */
static const uint8 echo_map[LPT_BINLNT + LPT_ECHLNT] = {
0, 1, 2, 3, 4, 5, 6, 7, /* write 9 to 1 */
8, 9, 10, 11, 12, 13, 14, 15,
16, 17,
0+ECHO_F, 1+ECHO_F, /* echo 8+4 */
18, 19, /* write 0 */
2+ECHO_F, 3+ECHO_F, /* echo 8+3 */
20, 21, /* write 11 */
4+ECHO_F, 5+ECHO_F, /* echo 9 */
22, 23, /* write 12 */
6+ECHO_F, 7+ECHO_F, 8+ECHO_F, 9+ECHO_F, /* echo 8 to 1 */
10+ECHO_F, 11+ECHO_F, 12+ECHO_F, 13+ECHO_F,
14+ECHO_F, 15+ECHO_F, 16+ECHO_F, 17+ECHO_F,
18+ECHO_F, 19+ECHO_F, 20+ECHO_F, 21+ECHO_F
};
extern uint32 ind_ioc;
extern t_uint64 bit_masks[36];
extern uint32 col_masks[12];
extern char bcd_to_ascii_a[64];
extern char bcd_to_ascii_h[64];
extern char bcd_to_pca[64];
extern char bcd_to_pch[64];
char *pch_table[4] = {
bcd_to_ascii_h, bcd_to_ascii_a, bcd_to_pch, bcd_to_pca,
};
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_chsel (uint32 ch, uint32 sel, uint32 unit);
t_stat lpt_chwr (uint32 ch, t_uint64 val, uint32 flags);
t_stat lpt_end_line (UNIT *uptr);
extern char colbin_to_bcd (uint32 colbin);
/* LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit descriptor
lpt_reg LPT register list
*/
DIB lpt_dib = { &lpt_chsel, &lpt_chwr };
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_CONS, 0)
};
REG lpt_reg[] = {
{ ORDATA (STATE, lpt_sta, 2) },
{ ORDATA (CMD, lpt_cmd, 2) },
{ ORDATA (CHOB, lpt_chob, 36) },
{ FLDATA (CHOBV, lpt_chob_v, 0) },
{ DRDATA (BPTR, lpt_bptr, 6), PV_LEFT },
{ BRDATA (BUF, lpt_bbuf, 8, 36, LPT_BINLNT) },
{ BRDATA (EBUF, lpt_ebuf, 8, 36, LPT_ECHLNT) },
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TSTART, lpt_tstart, 24), PV_LEFT + REG_NZ },
{ DRDATA (TSTOP, lpt_tstop, 24), PV_LEFT + REG_NZ },
{ DRDATA (TLEFT, lpt_tleft, 24), PV_LEFT + REG_NZ },
{ DRDATA (TRIGHT, lpt_tright, 24), PV_LEFT + REG_NZ },
{ NULL }
};
MTAB lpt_mod[] = {
{ UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT" },
{ UNIT_CONS, 0 , "no default device", "NODEFAULT" },
{ UNIT_48, UNIT_48, "48 character chain", "48" },
{ UNIT_48, 0, "64 character chain", "64" },
{ UNIT_BZ, UNIT_BZ, "business set", "BUSINESS" },
{ UNIT_BZ, 0, "Fortran set", "FORTRAN" },
{ 0 }
};
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 7,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL,
&lpt_dib, DEV_DISABLE
};
/* Channel select routine */
t_stat lpt_chsel (uint32 ch, uint32 sel, uint32 unit)
{
if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */
switch (sel) { /* case on cmd */
case CHSL_RDS: /* read */
case CHSL_WRS: /* write */
if (!(lpt_unit.flags & (UNIT_ATT|UNIT_CONS))) /* not attached? */
return SCPE_UNATT;
if (sim_is_active (&lpt_unit)) /* busy? */
return ERR_STALL;
lpt_cmd = ((unit & 02)? CMD_BIN: 0) | /* save modes */
((sel == CHSL_RDS)? CMD_ECHO: 0);
lpt_sta = LPS_INIT; /* initial state */
sim_activate (&lpt_unit, lpt_tstart); /* start reader */
break;
default: /* other */
return STOP_ILLIOP;
}
return SCPE_OK;
}
/* Channel write routine
- Normal mode is processed here
- Echo mode is processed in the service routine (like a read) */
t_stat lpt_chwr (uint32 ch, t_uint64 val, uint32 eorfl)
{
uint32 u = (lpt_cmd & CMD_BIN)? U_LPBIN: U_LPBCD; /* reconstruct unit */
lpt_chob = val & DMASK; /* store data */
lpt_chob_v = 1; /* set valid */
if (lpt_sta == ECS_DATA) return SCPE_OK;
if (lpt_sta == LPS_DATA) {
lpt_bbuf[lpt_bptr++] = lpt_chob; /* store data */
if (eorfl || /* end record, or */
((lpt_cmd & CMD_BIN)? /* last word in buffer? */
(lpt_bptr > (LPB_1ROW + 1)): /* (binary mode) */
(lpt_bptr > (LPB_12ROW + 1)))) { /* (normal mode) */
ch6_set_flags (CH_A, u, CHF_EOR); /* set eor */
return lpt_end_line (&lpt_unit);
}
return SCPE_OK;
}
return SCPE_IERR;
}
/* Unit timeout */
t_stat lpt_svc (UNIT *uptr)
{
uint32 u = (lpt_cmd & CMD_BIN)? U_LPBIN: U_LPBCD; /* reconstruct unit */
uint32 i, map;
switch (lpt_sta) { /* case on state */
case LPS_INIT: /* initial state */
for (i = 0; i < LPT_BINLNT; i++) /* clear data buffer */
lpt_bbuf[i] = 0;
for (i = 0; i < LPT_ECHLNT; i++) /* clear echo buffer */
lpt_ebuf[i] = 0;
if (lpt_cmd & CMD_BIN) lpt_bptr = LPB_1ROW; /* set buffer ptr */
else lpt_bptr = LPB_9ROW;
if (lpt_cmd & CMD_ECHO) lpt_sta = ECS_DATA; /* set data state */
else lpt_sta = LPS_DATA;
ch6_req_wr (CH_A, u); /* request channel */
lpt_chob = 0; /* clr, inval buffer */
lpt_chob_v = 0;
sim_activate (uptr, lpt_tleft); /* go again */
break;
case LPS_DATA: /* print data state */
if (!ch6_qconn (CH_A, u)) /* disconnect? */
return lpt_end_line (uptr); /* line is done */
if (lpt_chob_v) lpt_chob_v = 0; /* valid? clear */
else ind_ioc = 1; /* no, io check */
ch6_req_wr (CH_A, u); /* request chan again */
sim_activate (uptr, (lpt_bptr & 1)? lpt_tleft: lpt_tright);
break;
case ECS_DATA: /* echo data state */
map = echo_map[lpt_bptr++]; /* map column */
if (map == ECHO_F) { /* first echo? */
lpt_ebuf[ECB_84ROW] = lpt_bbuf[LPB_8ROW] & lpt_bbuf[LPB_4ROW];
lpt_ebuf[ECB_84ROW + 1] = lpt_bbuf[LPB_8ROW + 1] & lpt_bbuf[LPB_4ROW + 1];
lpt_ebuf[ECB_83ROW] = lpt_bbuf[LPB_8ROW] & lpt_bbuf[LPB_3ROW];
lpt_ebuf[ECB_83ROW + 1] = lpt_bbuf[LPB_8ROW + 1] & lpt_bbuf[LPB_3ROW + 1];
for (i = 0; i < 18; i++) /* copy rows 9.. 1 */
lpt_ebuf[ECB_9ROW + i] = lpt_bbuf[LPB_9ROW + i];
}
if (map & ECHO_F) { /* echo cycle */
ch6_req_rd (CH_A, u, lpt_ebuf[map & ECHO_MASK], 0);
if (lpt_bptr >= (LPT_BINLNT + LPT_ECHLNT))
return lpt_end_line (uptr); /* done? */
sim_activate (uptr, lpt_tleft); /* short timer */
}
else { /* print cycle */
if (lpt_chob_v) lpt_chob_v = 0; /* valid? clear */
else ind_ioc = 1; /* no, io check */
lpt_bbuf[map] = lpt_chob; /* store in buffer */
sim_activate (uptr, (lpt_bptr & 1)? lpt_tleft: lpt_tright);
}
if (!(echo_map[lpt_bptr] & ECHO_F)) /* print word next? */
ch6_req_wr (CH_A, u); /* req channel */
break;
case LPS_END: /* end state */
if (ch6_qconn (CH_A, u)) { /* lpt still conn? */
lpt_sta = LPS_INIT; /* initial state */
sim_activate (uptr, 1); /* next line */
}
break;
}
return SCPE_OK;
}
/* End line routine */
t_stat lpt_end_line (UNIT *uptr)
{
uint32 i, j, col, row, bufw, colbin;
char *pch, bcd, lpt_cbuf[LPT_CHRLNT + 1];
t_uint64 dat;
pch = pch_table[GET_PCHAIN (lpt_unit.flags)]; /* get print chain */
for (col = 0; col < (LPT_CHRLNT + 1); col++) /* clear ascii buf */
lpt_cbuf[col] = ' ';
for (col = 0; col < 72; col++) { /* proc 72 columns */
colbin = 0;
dat = bit_masks[35 - (col % 36)]; /* mask for column */
for (row = 0; row < 12; row++) { /* proc 12 rows */
bufw = (row * 2) + (col / 36); /* index to buffer */
if (lpt_bbuf[bufw] & dat) colbin |= col_masks[row];
}
bcd = colbin_to_bcd (colbin); /* column bin -> BCD */
lpt_cbuf[col] = pch[bcd]; /* -> ASCII */
}
for (i = LPT_CHRLNT; (i > 0) &&
(lpt_cbuf[i - 1] == ' '); --i) ; /* trim spaces */
lpt_cbuf[i++] = '\n'; /* append nl */
if (uptr->flags & UNIT_ATT) { /* file? */
fxwrite (lpt_cbuf, 1, i, uptr->fileref); /* write line */
if (ferror (uptr->fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR;
}
uptr->pos = ftell (uptr->fileref); /* update position */
}
else if (uptr->flags & UNIT_CONS) { /* print to console? */
for (j = 0; j < i; j++) sim_putchar (lpt_cbuf[j]);
sim_putchar ('\r');
}
else return SCPE_UNATT; /* otherwise error */
uptr->pos = uptr->pos + strlen (lpt_cbuf); /* count char */
lpt_sta = LPS_END; /* end line state */
sim_cancel (uptr); /* cancel current */
sim_activate (uptr, lpt_tstop); /* long timer */
return SCPE_OK;
}
/* Reset routine */
t_stat lpt_reset (DEVICE *dptr)
{
uint32 i;
for (i = 0; i < LPT_BINLNT; i++) lpt_bbuf[i] = 0; /* clear bin buf */
for (i = 0; i < LPT_ECHLNT; i++) lpt_ebuf[i] = 0; /* clear echo buf */
lpt_sta = 0; /* clear state */
lpt_cmd = 0; /* clear modes */
lpt_bptr = 0; /* clear buf ptr */
lpt_chob = 0;
lpt_chob_v = 0;
sim_cancel (&lpt_unit); /* stop printer */
return SCPE_OK;
}

826
I7094/i7094_mt.c Normal file
View File

@@ -0,0 +1,826 @@
/* i7094_mt.c: IBM 7094 magnetic tape simulator
Copyright (c) 2003-2006, 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 magtape simulator
*/
#include "i7094_defs.h"
#include "sim_tape.h"
#define UST u3 /* unit state */
#define UCH u4 /* channel number */
#define MTUF_V_LDN (MTUF_V_UF + 0)
#define MTUF_LDN (1 << MTUF_V_LDN)
#define MT_MAXFR ((1 << 18) + 2)
#define QCHRONO(c,u) ((cpu_model & I_CT) && \
((c) == CHRONO_CH) && ((u) == CHRONO_UNIT))
uint8 *mtxb[NUM_CHAN] = { NULL }; /* xfer buffer */
uint32 mt_unit[NUM_CHAN]; /* unit */
uint32 mt_bptr[NUM_CHAN];
uint32 mt_blnt[NUM_CHAN];
t_uint64 mt_chob[NUM_CHAN];
uint32 mt_chob_v[NUM_CHAN];
uint32 mt_tshort = 2;
uint32 mt_twef = 25000; /* 50 msec */
uint32 mt_tstart = 29000; /* 58 msec */
uint32 mt_tstop = 10000; /* 20 msec */
uint32 mt_tword = 50; /* 125 usec */
static const uint8 odd_par[64] = {
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1
};
static const char *tape_stat[] = {
"OK", "TMK", "UNATT", "IOERR", "INVRECLNT",
"FMT", "BOT", "EOM", "RECERR", "WRPROT"
};
extern uint32 PC;
extern uint32 cpu_model;
extern uint32 ind_ioc;
extern FILE *sim_deb;
extern char *sel_name[];
t_stat mt_chsel (uint32 ch, uint32 sel, uint32 unit);
t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 flags);
t_stat mt_rec_end (UNIT *uptr);
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_boot (int32 unitno, DEVICE *dptr);
t_stat mt_map_err (UNIT *uptr, t_stat st);
extern uint32 chrono_rd (uint8 *buf, uint32 bufsiz);
/* MT data structures
mt_dev MT device descriptor
mt_unit MT unit list
mt_reg MT register list
mt_mod MT modifier list
*/
DIB mt_dib = { &mt_chsel, &mt_chwr };
MTAB mt_mod[] = {
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
{ MTUF_LDN, 0, "high density", "HIGH", NULL },
{ MTUF_LDN, MTUF_LDN, "low density", "LOW", NULL },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ 0 }
};
UNIT mta_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mta_reg[] = {
{ ORDATA (UNIT, mt_unit[0], 5) },
{ ORDATA (CHOB, mt_chob[0], 36) },
{ FLDATA (CHOBV, mt_chob_v[0], 0) },
{ DRDATA (BPTR, mt_bptr[0], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[0], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mta_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mta_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtb_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtb_reg[] = {
{ ORDATA (UNIT, mt_unit[1], 5) },
{ ORDATA (CHOB, mt_chob[1], 36) },
{ FLDATA (CHOBV, mt_chob_v[1], 0) },
{ DRDATA (BPTR, mt_bptr[1], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[1], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtb_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtb_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtc_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtc_reg[] = {
{ ORDATA (UNIT, mt_unit[2], 5) },
{ ORDATA (CHOB, mt_chob[2], 36) },
{ FLDATA (CHOBV, mt_chob_v[2], 0) },
{ DRDATA (BPTR, mt_bptr[2], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[2], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtc_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtc_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtd_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtd_reg[] = {
{ ORDATA (UNIT, mt_unit[3], 5) },
{ ORDATA (CHOB, mt_chob[3], 36) },
{ FLDATA (CHOBV, mt_chob_v[3], 0) },
{ DRDATA (BPTR, mt_bptr[3], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[3], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtd_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtd_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mte_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mte_reg[] = {
{ ORDATA (UNIT, mt_unit[4], 5) },
{ ORDATA (CHOB, mt_chob[4], 36) },
{ FLDATA (CHOBV, mt_chob_v[4], 0) },
{ DRDATA (BPTR, mt_bptr[4], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[4], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mte_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mte_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtf_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtf_reg[] = {
{ ORDATA (UNIT, mt_unit[5], 5) },
{ ORDATA (CHOB, mt_chob[5], 36) },
{ FLDATA (CHOBV, mt_chob_v[5], 0) },
{ DRDATA (BPTR, mt_bptr[5], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[5], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtf_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtf_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mtg_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mtg_reg[] = {
{ ORDATA (UNIT, mt_unit[6], 5) },
{ ORDATA (CHOB, mt_chob[6], 36) },
{ FLDATA (CHOBV, mt_chob_v[6], 0) },
{ DRDATA (BPTR, mt_bptr[6], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[6], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mtg_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mtg_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
UNIT mth_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
};
REG mth_reg[] = {
{ ORDATA (UNIT, mt_unit[7], 5) },
{ ORDATA (CHOB, mt_chob[7], 36) },
{ FLDATA (CHOBV, mt_chob_v[7], 0) },
{ DRDATA (BPTR, mt_bptr[7], 16), PV_LEFT },
{ DRDATA (BLNT, mt_blnt[7], 16), PV_LEFT },
{ BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
{ DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
{ DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
{ DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
{ URDATA (UST, mth_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
{ URDATA (POS, mth_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR + 1, PV_LEFT | REG_RO) },
{ NULL }
};
DEVICE mt_dev[NUM_CHAN] = {
{
"MTA", mta_unit, mta_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
&mt_boot, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DEBUG
},
{
"MTB", mtb_unit, mtb_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTC", mtc_unit, mtc_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTD", mtd_unit, mtd_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTE", mte_unit, mte_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTF", mtf_unit, mtf_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTG", mtg_unit, mtg_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
},
{
"MTH", mth_unit, mth_reg, mt_mod,
MT_NUMDR + 1, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &sim_tape_detach,
&mt_dib, DEV_DIS|DEV_DEBUG
}
};
/* Select controller
Inputs:
ch = channel
cmd = select command
unit = unit
Outputs:
status = SCPE_OK if ok
STOP_STALL if busy
error code if error
*/
static const int mt_must_att[CHSL_NUM] = {
0, 1, 1, 0, 1, 1, 0, 0,
1, 1, 1, 1, 1, 1, 0, 0
};
static const int mt_will_wrt[CHSL_NUM] = {
0, 0, 1, 0, 0, 1, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0
};
t_stat mt_chsel (uint32 ch, uint32 cmd, uint32 unit)
{
UNIT *uptr;
uint32 u = unit & 017;
if ((ch >= NUM_CHAN) || (cmd == 0) || (cmd >= CHSL_NUM))
return SCPE_IERR; /* invalid arg? */
if (mt_dev[ch].flags & DEV_DIS) return STOP_NXDEV; /* disabled? */
if ((u == 0) || (u > MT_NUMDR)) return STOP_NXDEV; /* valid unit? */
uptr = mt_dev[ch].units + u; /* get unit ptr */
if (uptr->flags & UNIT_DIS) return STOP_NXDEV; /* disabled? */
if (mt_unit[ch] || sim_is_active (uptr)) /* ctrl or unit busy? */
return ERR_STALL; /* stall */
if (QCHRONO (ch, u)) { /* Chronolog clock? */
if (cmd != CHSL_RDS) return STOP_ILLIOP; /* only reads */
sim_activate (uptr, mt_tword); /* responds quickly */
}
else { /* real tape */
if (!(uptr->flags & UNIT_ATT) && mt_must_att[cmd]) /* unit unatt? */
return SCPE_UNATT;
if (sim_tape_wrp (uptr) && mt_will_wrt[cmd]) /* unit wrp && write? */
return STOP_WRP;
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d %s, pos = %d\n", mt_dev[ch].name, u, sel_name[cmd], uptr->pos);
switch (cmd) { /* case on cmd */
case CHSL_RDS:
case CHSL_WRS:
case CHSL_BSR:
case CHSL_BSF: /* rd, wr, backspace */
sim_activate (uptr, mt_tstart); /* schedule op */
break;
case CHSL_WEF: /* write eof? */
sim_activate (uptr, mt_twef); /* schedule op */
break;
case CHSL_RUN:
sim_activate (uptr, mt_tshort); /* schedule quick event */
break;
case CHSL_REW:
case CHSL_SDN: /* rew, rew/unl, set det */
sim_activate (uptr, mt_tshort); /* schedule quick event */
break;
default:
return SCPE_IERR;
} /* end switch */
} /* end else */
uptr->UST = cmd; /* set cmd */
mt_unit[ch] = unit & 0777; /* save unit */
return SCPE_OK;
}
/* Channel write routine */
t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 eorfl)
{
int32 k, u;
uint8 by, *xb;
UNIT *uptr;
if (ch >= NUM_CHAN) return SCPE_IERR; /* invalid chan? */
xb = mtxb[ch]; /* get xfer buf */
u = mt_unit[ch] & 017;
if ((xb == NULL) || (u > MT_NUMDR)) return SCPE_IERR; /* invalid args? */
uptr = mt_dev[ch].units + u; /* get unit */
mt_chob[ch] = val & DMASK; /* save word from chan */
mt_chob_v[ch] = 1; /* set valid */
if (uptr->UST == (CHSL_WRS|CHSL_2ND)) { /* data write? */
for (k = 30; /* proc 6 bytes */
(k >= 0) && (mt_bptr[ch] < MT_MAXFR);
k = k - 6) {
by = (uint8) ((val >> k) & 077); /* get byte */
if ((mt_unit[ch] & 020) == 0) { /* BCD? */
if (by == 0) by = BCD_ZERO; /* cvt bin 0 */
else if (by & 020) by = by ^ 040; /* invert zones */
if (!odd_par[by]) by = by | 0100; /* even parity */
}
else if (odd_par[by]) by = by | 0100; /* bin, odd par */
xb[mt_bptr[ch]++] = by; /* put in buffer */
}
if (eorfl) return mt_rec_end (uptr); /* EOR? write rec */
return SCPE_OK;
}
return SCPE_IERR;
}
/* Unit timeout */
t_stat mt_svc (UNIT *uptr)
{
uint32 i, u, ch = uptr->UCH; /* get channel number */
uint8 by, *xb = mtxb[ch]; /* get xfer buffer */
t_uint64 dat;
t_mtrlnt bc;
t_stat r;
if (xb == NULL) return SCPE_IERR; /* valid buffer? */
u = uptr - mt_dev[ch].units;
switch (uptr->UST) { /* case on state */
case CHSL_RDS: /* read start */
if (QCHRONO (ch, mt_unit[ch] & 017)) /* Chronolog clock? */
bc = chrono_rd (xb, MT_MAXFR); /* read clock */
else { /* real tape */
r = sim_tape_rdrecf (uptr, xb, &bc, MT_MAXFR); /* read record */
if (r = mt_map_err (uptr, r)) return r; /* map status */
if (mt_unit[ch] == 0) return SCPE_OK; /* disconnected? */
} /* end else Chrono */
if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */
mt_unit[ch] = 0; /* clr ctrl busy */
return SCPE_OK;
}
for (i = bc; i < (bc + 6); i++) xb[i] = 0; /* extra 0's */
mt_bptr[ch] = 0; /* set ptr, lnt */
mt_blnt[ch] = bc;
uptr->UST = CHSL_RDS|CHSL_2ND; /* next state */
sim_activate (uptr, mt_tword);
break;
case CHSL_RDS|CHSL_2ND: /* read word */
for (i = 0, dat = 0; i < 6; i++) { /* proc 6 bytes */
by = xb[mt_bptr[ch]++] & 077; /* get next byte */
if ((mt_unit[ch] & 020) == 0) { /* BCD? */
if (by == BCD_ZERO) by = 0; /* cvt BCD 0 */
else if (by & 020) by = by ^ 040; /* invert zones */
}
dat = (dat << 6) | ((t_uint64) by);
}
if (mt_bptr[ch] >= mt_blnt[ch]) { /* end of record? */
ch6_req_rd (ch, mt_unit[ch], dat, CH6DF_EOR);
uptr->UST = CHSL_RDS|CHSL_3RD; /* next state */
sim_activate (uptr, mt_tstop); /* long timing */
}
else {
ch6_req_rd (ch, mt_unit[ch], dat, 0); /* send to channel */
sim_activate (uptr, mt_tword); /* next word */
}
break;
case CHSL_RDS|CHSL_3RD: /* end record */
if (ch6_qconn (ch, mt_unit[ch])) { /* ch still conn? */
uptr->UST = CHSL_RDS; /* initial state */
sim_activate (uptr, mt_tshort); /* sched next record */
}
else mt_unit[ch] = 0; /* clr ctrl busy */
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d RDS complete, pos = %d, %s\n",
mt_dev[ch].name, u, uptr->pos, mt_unit[ch]? "continuing": "disconnecting");
return SCPE_OK;
case CHSL_WRS: /* write start */
if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */
mt_unit[ch] = 0; /* clr ctrl busy */
return SCPE_OK; /* (writes blank tape) */
}
mt_bptr[ch] = 0; /* init buffer */
uptr->UST = CHSL_WRS|CHSL_2ND; /* next state */
ch6_req_wr (ch, mt_unit[ch]); /* request channel */
mt_chob[ch] = 0; /* clr, inval buffer */
mt_chob_v[ch] = 0;
sim_activate (uptr, mt_tword); /* wait for word */
break;
case CHSL_WRS|CHSL_2ND: /* write word */
if (!ch6_qconn (ch, mt_unit[ch])) /* disconnected? */
return mt_rec_end (uptr); /* write record */
if (mt_chob_v[ch]) mt_chob_v[ch] = 0; /* valid? clear */
else ind_ioc = 1; /* no, io check */
ch6_req_wr (ch, mt_unit[ch]); /* request channel */
sim_activate (uptr, mt_tword); /* next word */
break;
case CHSL_WRS|CHSL_3RD: /* write stop */
if (ch6_qconn (ch, mt_unit[ch])) { /* chan active? */
uptr->UST = CHSL_WRS; /* initial state */
sim_activate (uptr, mt_tshort); /* sched next record */
}
else mt_unit[ch] = 0; /* clr ctrl busy */
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d WRS complete, pos = %d, %s\n",
mt_dev[ch].name, u, uptr->pos, mt_unit[ch]? "continuing": "disconnecting");
return SCPE_OK;
case CHSL_BSR: /* backspace rec */
r = sim_tape_sprecr (uptr, &bc); /* space backwards */
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d BSR complete, pos = %d\n", mt_dev[ch].name, u, uptr->pos);
if (r == MTSE_TMK) return SCPE_OK; /* allow tape mark */
return mt_map_err (uptr, r);
case CHSL_BSF: /* backspace file */
while ((r = sim_tape_sprecr (uptr, &bc)) == MTSE_OK) ;
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d BSF complete, pos = %d\n", mt_dev[ch].name, u, uptr->pos);
if (r == MTSE_TMK) return SCPE_OK; /* allow tape mark */
return mt_map_err (uptr, r); /* map others */
case CHSL_WEF: /* write eof */
r = sim_tape_wrtmk (uptr); /* write tape mark */
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d WEF complete, pos = %d\n", mt_dev[ch].name, u, uptr->pos);
return mt_map_err (uptr, r);
case CHSL_REW: case CHSL_RUN: /* rewind, unload */
uptr->UST = uptr->UST | CHSL_2ND; /* set 2nd state */
sim_activate (uptr, mt_tstart); /* reactivate */
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
return SCPE_OK;
case CHSL_REW | CHSL_2ND:
sim_tape_rewind (uptr);
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d REW complete, pos = %d\n", mt_dev[ch].name, u, uptr->pos);
return SCPE_OK;
case CHSL_RUN | CHSL_2ND:
sim_tape_detach (uptr);
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d RUN complete, pos = %d\n", mt_dev[ch].name, u, uptr->pos);
return SCPE_OK;
case CHSL_SDN:
if (mt_unit[ch] & 020) /* set density flag */
uptr->flags = uptr-> flags & ~MTUF_LDN;
else uptr->flags = uptr->flags | MTUF_LDN;
mt_unit[ch] = 0; /* clr ctrl busy */
ch6_end_nds (ch); /* disconnect */
if (DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d SDN complete, pos = %d\n", mt_dev[ch].name, u, uptr->pos);
return SCPE_OK;
default:
return SCPE_IERR;
}
return SCPE_OK;
}
/* End record routine */
t_stat mt_rec_end (UNIT *uptr)
{
uint32 ch = uptr->UCH;
uint8 *xb = mtxb[ch];
t_stat r;
if (mt_bptr[ch]) { /* any data? */
if (xb == NULL) return SCPE_IERR;
r = sim_tape_wrrecf (uptr, xb, mt_bptr[ch]); /* write record */
if (r = mt_map_err (uptr, r)) return r; /* map error */
}
uptr->UST = CHSL_WRS|CHSL_3RD; /* next state */
sim_cancel (uptr); /* cancel current */
sim_activate (uptr, mt_tstop); /* long timing */
return SCPE_OK;
}
/* Map tape error status */
t_stat mt_map_err (UNIT *uptr, t_stat st)
{
uint32 ch = uptr->UCH;
uint32 u = mt_unit[ch];
uint32 up = uptr - mt_dev[ch].units;
if ((st != MTSE_OK) && DEBUG_PRS (mt_dev[ch])) fprintf (sim_deb,
">>%s%d status = %s, pos = %d\n", mt_dev[ch].name, up, tape_stat[st], uptr->pos);
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* not attached */
ch6_err_disc (ch, u, CHF_TRC);
mt_unit[ch] = 0; /* disconnect */
return SCPE_IERR;
case MTSE_IOERR: /* IO error */
ch6_err_disc (ch, u, CHF_TRC);
mt_unit[ch] = 0; /* disconnect */
return SCPE_IOERR;
case MTSE_INVRL: /* invalid rec lnt */
ch6_err_disc (ch, u, CHF_TRC);
mt_unit[ch] = 0; /* disconnect */
return SCPE_MTRLNT;
case MTSE_WRP: /* write protect */
ch6_err_disc (ch, u, 0);
mt_unit[ch] = 0; /* disconnect */
return STOP_WRP;
case MTSE_EOM: /* end of medium */
case MTSE_TMK: /* tape mark */
ch6_err_disc (ch, u, CHF_EOF);
mt_unit[ch] = 0; /* disconnect */
break;
case MTSE_RECE: /* record in error */
ch6_set_flags (ch, u, CHF_TRC);
break;
case MTSE_BOT: /* reverse into BOT */
ch6_set_flags (ch, u, CHF_BOT);
break;
case MTSE_OK: /* no error */
break;
}
return SCPE_OK;
}
/* Magtape reset */
t_stat mt_reset (DEVICE *dptr)
{
uint32 ch = dptr - &mt_dev[0];
uint32 j;
REG *rptr;
UNIT *uptr;
if (mtxb[ch] == NULL) mtxb[ch] = (uint8 *) calloc (MT_MAXFR + 6, sizeof (uint8));
if (mtxb[ch] == NULL) return SCPE_MEM; /* allocate buffer */
rptr = find_reg ("BUF", NULL, dptr); /* update reg ptr */
if (rptr == NULL) return SCPE_IERR;
rptr->loc = (void *) mtxb[ch];
mt_unit[ch] = 0; /* clear busy */
mt_bptr[ch] = 0; /* clear buf ptrs */
mt_blnt[ch] = 0;
mt_chob[ch] = 0;
mt_chob_v[ch] = 0;
for (j = 1; j <= MT_NUMDR; j++) { /* for all units */
uptr = dptr->units + j;
uptr->UST = 0; /* clear state */
uptr->UCH = ch;
sim_cancel (uptr); /* stop activity */
} /* end for */
return SCPE_OK; /* done */
}
/* Magtape attach */
t_stat mt_attach (UNIT *uptr, char *cptr)
{
uptr->flags = uptr->flags & ~MTUF_LDN; /* start as hi den */
return sim_tape_attach (uptr, cptr);
}
/* Magtape boot */
#define BOOT_START 01000
static const t_uint64 boot_rom[5] = {
0076200000000 + U_MTBIN - 1, /* RDS MT_binary */
0054000000000 + BOOT_START + 4, /* RCHA *+3 */
0054400000000, /* LCHA 0 */
0002100000001, /* TTR 1 */
0500003000000, /* IOCT 0,,3 */
};
t_stat mt_boot (int32 unitno, DEVICE *dptr)
{
uint32 i, chan;
extern t_uint64 *M;
chan = dptr - &mt_dev[0] + 1;
WriteP (BOOT_START, boot_rom[0] + unitno + (chan << 9));
for (i = 1; i < 5; i++)
WriteP (BOOT_START + i, boot_rom[i]);
PC = BOOT_START;
return SCPE_OK;
}

718
I7094/i7094_sys.c Normal file
View File

@@ -0,0 +1,718 @@
/* i7094_sys.c: IBM 7094 simulator interface
Copyright (c) 2003-2006, 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 "i7094_defs.h"
#include <ctype.h>
#include "i7094_dat.h"
extern DEVICE cpu_dev;
extern DEVICE ch_dev[NUM_CHAN];
extern DEVICE mt_dev[NUM_CHAN];
extern DEVICE drm_dev;
extern DEVICE dsk_dev;
extern DEVICE com_dev, coml_dev;
extern DEVICE cdr_dev, cdp_dev;
extern DEVICE lpt_dev;
extern DEVICE clk_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
uint32 cvt_code_to_ascii (uint32 c, int32 sw);
uint32 cvt_ascii_to_code (uint32 c, int32 sw);
/* 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[] = "IBM 7094";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&clk_dev,
&ch_dev[0],
&ch_dev[1],
&ch_dev[2],
&ch_dev[3],
&ch_dev[4],
&ch_dev[5],
&ch_dev[6],
&ch_dev[7],
&mt_dev[0],
&mt_dev[1],
&mt_dev[2],
&mt_dev[3],
&mt_dev[4],
&mt_dev[5],
&mt_dev[6],
&mt_dev[7],
&cdr_dev,
&cdp_dev,
&lpt_dev,
&dsk_dev,
&drm_dev,
&com_dev,
&coml_dev,
NULL
};
char ch_bkpt_msg[] = "Channel A breakpoint, CLC: xxxxxx";
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Breakpoint",
"Undefined instruction",
"Divide check",
"Nested XEC limit exceeded",
"Address stop",
"Non-existent channel",
"Illegal instruction for 7909 channel",
"Illegal instruction for non-7909 channel",
"Non-existent device",
"Undefined channel instruction",
"Write to protected device",
"Illegal instruction for device",
"Invalid 7631 track format",
"7750 buffer pool empty on input",
"7750 buffer pool empty on output",
"7750 invalid line number",
"7750 invalid message",
ch_bkpt_msg
};
/* Modify channel breakpoint message */
t_stat ch_bkpt (uint32 ch, uint32 clc)
{
ch_bkpt_msg[8] = 'A' + ch;
sprintf (&ch_bkpt_msg[27], "%06o", clc);
return STOP_CHBKPT;
}
/* Binary loader, not implemented */
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
return SCPE_NOFNC;
}
/* Symbol tables */
#define I_V_FL 39 /* inst class */
#define I_M_FL 017 /* class mask */
#define I_NOP 0000000000000000 /* no operand */
#define I_MXR 0010000000000000 /* addr(tag) */
#define I_MXN 0020000000000000 /* *addr(tag) */
#define I_MXV 0030000000000000 /* var mul/div */
#define I_MXC 0040000000000000 /* convert */
#define I_DNP 0050000000000000 /* decr, no oper */
#define I_DEC 0060000000000000 /* decrement */
#define I_SNS 0070000000000000 /* sense */
#define I_IMM 0100000000000000 /* 18b immediate */
#define I_TAG 0110000000000000 /* tag only */
#define I_IOX 0120000000000000 /* IO channel */
#define I_TCH 0130000000000000 /* transfer channel */
#define I_I9N 0140000000000000 /* 7909 with nostore */
#define I_I9S 0150000000000000 /* 7909 */
#define IFAKE_7607 0001000000000000 /* fake op extensions */
#define IFAKE_7909 0002000000000000
#define DFAKE (DMASK|IFAKE_7607|IFAKE_7909)
#define I_N_NOP 000
#define I_N_MXR 001
#define I_N_MXN 002
#define I_N_MXV 003
#define I_N_MXC 004
#define I_N_DNP 005
#define I_N_DEC 006
#define I_N_SNS 007
#define I_N_IMM 010
#define I_N_TAG 011
#define I_N_IOX 012
#define I_N_TCH 013
#define I_N_I9N 014
#define I_N_I9S 015
#define INST_P_XIT 0 /* exit */
#define INST_P_SKP 1 /* do not print */
#define INST_P_PRA 2 /* print always */
#define INST_P_PNZ 3 /* print if nz */
#define INST_P_PNT 4 /* print if nz, term */
static const t_uint64 masks[14] = {
03777700000000, 03777700000000,
03777700000000, 03777700000000,
03777400000000, 03700000000000,
03700000000000, 03777700077777,
03777700000000, 03777700000000,
03700000200000, 03700000200000,
03760000200000, 03740000200000 };
static const uint32 fld_max[14][3] = { /* addr,tag,decr limit */
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, INST_M_TAG, INST_M_VCNT },
{ INST_M_ADDR, INST_M_TAG, INST_M_CCNT },
{ INST_M_ADDR, INST_M_TAG, INST_M_DEC },
{ INST_M_ADDR, INST_M_TAG, INST_M_DEC },
{ 0, INST_M_TAG, 0 },
{ RMASK, 0, 0 },
{ INST_M_ADDR, INST_M_TAG, 0 },
{ INST_M_ADDR, 1, INST_M_DEC },
{ INST_M_ADDR, 1, 0 },
{ INST_M_ADDR, 1, 0 },
{ INST_M_ADDR, 1, 0 }
};
static const uint32 fld_fmt[14][3] = { /* addr,tag,decr print */
{ INST_P_PNT, INST_P_PNT, INST_P_XIT }, /* nop: all optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxr: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxn: tag optional */
{ INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* mxv: tag optional */
{ INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* cvt: tag optional */
{ INST_P_PNT, INST_P_PNT, INST_P_PNT }, /* dnp: all optional */
{ INST_P_PRA, INST_P_PRA, INST_P_PRA }, /* dec: print all */
{ INST_P_SKP, INST_P_PNT, INST_P_XIT }, /* sns: skip addr, tag opt */
{ INST_P_PRA, INST_P_XIT, INST_P_XIT }, /* immediate: addr only */
{ INST_P_PNZ, INST_P_PRA, INST_P_XIT }, /* tag: addr optional */
{ INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* iox: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* tch: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* i9n: tag optional */
{ INST_P_PRA, INST_P_PNT, INST_P_XIT } /* i9s: tag optional */
};
static const t_uint64 ind_test[14] = {
0, 0, INST_IND, 0, 0, 0, 0,
0, 0, 0, CHI_IND, CHI_IND, CHI_IND, CHI_IND
};
static const char *opcode[] = {
"TXI", "TIX", "TXH",
"STR", "TNX", "TXL",
"HTR", "TRA", "TTR",
"CLM", "LBT", "CHS",
"SSP", "ENK", "IOT",
"COM", "ETM", "RND",
"FRN", "DCT", "RCT",
"LMTM", "SLF", "SLN1",
"SLN2", "SLN3", "SLN4",
"SWT1", "SWT2", "SWT3",
"SWT4", "SWT5", "SWT6",
"BTTA", "BTTB", "BTTC",
"BTTD", "BTTE", "BTTF",
"BTTG", "BTTH",
"RICA", "RICB", "RICC",
"RICD", "RICE", "RICF",
"RICG", "RICH",
"RDCA", "RDCB", "RDCC",
"RDCD", "RDCE", "RDCF",
"RDCG", "RDCH",
"TRCA", "TRCC",
"TRCE", "TRCG",
"TEFA", "TEFC",
"TEFE", "TEFG",
"TLQ", "IIA", "TIO",
"OAI", "PAI", "TIF",
"IIR", "RFT", "SIR",
"RNT", "RIR",
"TCOA", "TCOB", "TCOC",
"TCOD", "TCOE", "TCOF",
"TCOG", "TCOH", "TSX",
"TZE", "CVR", "TPL",
"XCA", "TOV",
"TQO", "TQP",
"MPY", "VLM", "VLM1",
"DVH", "DVP",
"VDH", "VDP",
"VDH2", "VDP2",
"FDH", "FDP",
"FMP", "DFMP",
"FAD", "DFAD",
"FSB", "DFSB",
"FAM", "DFAM",
"FSM", "DFSM",
"ANS", "ERA",
"CAS", "ACL",
"ADD", "ADM",
"SUB", "SBM",
"HPR", "IIS", "LDI",
"OSI", "DLD", "OFT",
"RIS", "ONT",
"CLA", "CLS",
"ZET", "XEC",
"LXA", "LAC",
"RCHA", "RCHC",
"RCHE", "RCHG",
"LCHA", "LCHC",
"LCHE", "LCHG",
"RSCA", "RSCC",
"RSCE", "RSCG",
"STCA", "STCC",
"STCE", "STCG",
"LDQ", "ENB",
"STZ", "STO", "SLW",
"STI", "STA", "STD",
"STT", "STP",
"SXA", "SCA",
"SCHA", "SCHC",
"SCHE", "SCHG",
"SCDA", "SCDC",
"SCDE", "SCDG",
"PAX", "PAC",
"PXA", "PCA",
"PSE", "NOP", "RDS",
"LLS", "BSR", "LRS",
"WRS", "ALS", "WEF",
"ARS", "REW", "AXT",
"SDN",
"CLM", "PBT", "EFTM",
"SSM", "LFTM", "ESTM",
"ECTM", "LTM", "LSNM",
"EMTM", "SLT1", "SLT2",
"SLT3", "SLT4",
"ETTA", "ETTB", "ETTC",
"ETTD", "ETTE", "ETTF",
"ETTG", "ETTH",
"ESNT",
"TRCB", "TRCD",
"TRCF", "TRCH",
"TEFB", "TEFD",
"TEFF", "TEFH",
"RIA", "PIA",
"IIL", "LFT", "SIL",
"LNT", "RIL",
"TCNA", "TCNB", "TCNC",
"TCND", "TCNE", "TCNF",
"TCNG", "TCNH",
"TNZ", "CVR", "TMI",
"XCL", "TNO", "CRQ",
"MPR", "DFDH", "DFDP",
"UFM", "DUFM",
"UFA", "DUFA",
"UFS", "DUFS",
"UAM", "DUAM",
"USM", "DUSM",
"ANA", "LAS",
"CAL", "ORA", "NZT",
"LXD", "LXC",
"RCHB", "RCHD",
"RCHF", "RCHH",
"LCHB", "LCHD",
"LCHF", "LCHH",
"RSCB", "RSCD",
"RSCF", "RSCH",
"STCB", "STCD",
"STCF", "STCH",
"STQ", "ORS", "DST",
"SLQ", "STL",
"SXD", "SCD",
"SCHB", "SCHD",
"SCHF", "SCHH",
"SCDB", "SCDD",
"SCDF", "SCDH",
"PDX", "PDC",
"PXD", "PCD",
"MSE", "LGL", "BSF",
"LGR", "RQL", "RUN",
"AXC",
"TIA", "TIB",
"LRI", "LPI",
"SEA", "SEB",
"IOCD", "IOCDN", "TCH",
"IORP", "IORPN",
"IORT", "IORTN",
"IOCP", "IOCPN",
"IOCT", "IOCTN",
"IOSP", "IOSPN",
"IOST", "IOSTN",
"WTR", "XMT",
"TCH", "LIPT",
"CTL", "CTLN",
"CTLR", "CTLRN",
"CTLW", "CTLWN",
"SNS",
"LAR", "SAR", "TWT",
"CPYP",
"CPYD", "TCM",
"LIP", "TDC", "LCC",
"SMS", "ICC",
NULL
};
static const t_uint64 opc_v[] = {
0100000000000+I_DEC, 0200000000000+I_DEC, 0300000000000+I_DEC,
0500000000000+I_DNP, 0600000000000+I_DEC, 0700000000000+I_DEC,
0000000000000+I_MXN, 0002000000000+I_MXN, 0002100000000+I_MXN,
0076000000000+I_SNS, 0076000000001+I_SNS, 0076000000002+I_SNS,
0076000000003+I_SNS, 0076000000004+I_SNS, 0076000000005+I_SNS,
0076000000006+I_SNS, 0076000000007+I_SNS, 0076000000010+I_SNS,
0076000000011+I_SNS, 0076000000012+I_SNS, 0076000000014+I_SNS,
0076000000016+I_SNS, 0076000000140+I_SNS, 0076000000141+I_SNS,
0076000000142+I_SNS, 0076000000143+I_SNS, 0076000000144+I_SNS,
0076000000161+I_SNS, 0076000000162+I_SNS, 0076000000163+I_SNS,
0076000000164+I_SNS, 0076000000165+I_SNS, 0076000000166+I_SNS,
0076000001000+I_SNS, 0076000002000+I_SNS, 0076000003000+I_SNS,
0076000004000+I_SNS, 0076000005000+I_SNS, 0076000006000+I_SNS,
0076000007000+I_SNS, 0076000010000+I_SNS,
0076000001350+I_SNS, 0076000002350+I_SNS, 0076000003350+I_SNS,
0076000004350+I_SNS, 0076000005350+I_SNS, 0076000006350+I_SNS,
0076000007350+I_SNS, 0076000010350+I_SNS,
0076000001352+I_SNS, 0076000002352+I_SNS, 0076000003352+I_SNS,
0076000004352+I_SNS, 0076000005352+I_SNS, 0076000006352+I_SNS,
0076000007352+I_SNS, 0076000010352+I_SNS,
0002200000000+I_MXN, 0002400000000+I_MXN,
0002600000000+I_MXN, 0002700000000+I_MXN,
0003000000000+I_MXN, 0003100000000+I_MXN,
0003200000000+I_MXN, 0003300000000+I_MXN,
0004000000000+I_MXN, 0004100000000+I_NOP, 0004200000000+I_MXR,
0004300000000+I_NOP, 0004400000000+I_NOP, 0004600000000+I_MXR,
0005100000000+I_IMM, 0005400000000+I_IMM, 0005500000000+I_IMM,
0005600000000+I_IMM, 0005700000000+I_IMM,
0006000000000+I_MXN, 0006100000000+I_MXN, 0006200000000+I_MXN,
0006300000000+I_MXN, 0006400000000+I_MXN, 0006500000000+I_MXN,
0006600000000+I_MXN, 0006700000000+I_MXN, 0007400000000+I_MXR,
0010000000000+I_MXN, 0011400000000+I_MXC, 0012000000000+I_MXN,
0013100000000+I_NOP, 0014000000000+I_MXN,
0016100000000+I_MXN, 0016200000000+I_MXN,
0020000000000+I_MXN, 0020400000000+I_MXV, 0020500000000+I_MXV,
0022000000000+I_MXN, 0022100000000+I_MXN,
0022400000000+I_MXV, 0022500000000+I_MXV,
0022600000000+I_MXV, 0022700000000+I_MXV,
0024000000000+I_MXN, 0024100000000+I_MXN,
0026000000000+I_MXN, 0026100000000+I_MXN,
0030000000000+I_MXN, 0030100000000+I_MXN,
0030200000000+I_MXN, 0030300000000+I_MXN,
0030400000000+I_MXN, 0030500000000+I_MXN,
0030600000000+I_MXN, 0030700000000+I_MXN,
0032000000000+I_MXN, 0032200000000+I_MXN,
0034000000000+I_MXN, 0036100000000+I_MXN,
0040000000000+I_MXN, 0040100000000+I_MXN,
0040200000000+I_MXN, 0440000000000+I_MXN,
0042000000000+I_NOP, 0044000000000+I_MXN, 0044100000000+I_MXN,
0044200000000+I_MXN, 0044300000000+I_MXN, 0044400000000+I_MXN,
0044500000000+I_MXN, 0044600000000+I_MXN,
0050000000000+I_MXN, 0050200000000+I_MXN,
0052000000000+I_MXN, 0052200000000+I_MXN,
0053400000000+I_MXR, 0053500000000+I_MXR,
0054000000000+I_MXN, 0054100000000+I_MXN,
0054200000000+I_MXN, 0054300000000+I_MXN,
0054400000000+I_MXN, 0054500000000+I_MXN,
0054600000000+I_MXN, 0054700000000+I_MXN,
0054000000000+I_MXN, 0054100000000+I_MXN,
0054200000000+I_MXN, 0054300000000+I_MXN,
0054400000000+I_MXN, 0054500000000+I_MXN,
0054600000000+I_MXN, 0054700000000+I_MXN,
0056000000000+I_MXN, 0056400000000+I_MXN,
0060000000000+I_MXN, 0060100000000+I_MXN, 0060200000000+I_MXN,
0060400000000+I_MXN, 0062100000000+I_MXN, 0062200000000+I_MXN,
0062500000000+I_MXN, 0063000000000+I_MXN,
0063400000000+I_MXR, 0063600000000+I_MXR,
0064000000000+I_MXN, 0064000000000+I_MXN,
0064200000000+I_MXN, 0064300000000+I_MXN,
0064400000000+I_MXN, 0064500000000+I_MXN,
0064600000000+I_MXN, 0064700000000+I_MXN,
0073400000000+I_TAG, 0073700000000+I_TAG,
0075400000000+I_TAG, 0075600000000+I_TAG,
0076000000000+I_MXR, 0076100000000+I_NOP, 0076200000000+I_MXR,
0076300000000+I_MXR, 0076400000000+I_MXR, 0076500000000+I_MXR,
0076600000000+I_MXR, 0076700000000+I_MXR, 0077000000000+I_MXR,
0077100000000+I_MXR, 0077200000000+I_MXR, 0077400000000+I_MXR,
0077600000000+I_MXR,
0476000000000+I_SNS, 0476000000001+I_SNS, 0476000000002+I_SNS,
0476000000003+I_SNS, 0476000000004+I_SNS, 0476000000005+I_SNS,
0476000000006+I_SNS, 0476000000007+I_SNS, 0476000000010+I_SNS,
0476000000016+I_SNS, 0476000000141+I_SNS, 0476000000142+I_SNS,
0476000000143+I_SNS, 0476000000144+I_SNS,
0476000001000+I_SNS, 0476000002000+I_SNS, 0476000003000+I_SNS,
0476000004000+I_SNS, 0476000005000+I_SNS, 0476000006000+I_SNS,
0476000007000+I_SNS, 0476000010000+I_SNS,
0402100000000+I_MXN,
0402200000000+I_MXN, 0402400000000+I_MXN,
0402600000000+I_MXN, 0402700000000+I_MXN,
0403000000000+I_MXN, 0403100000000+I_MXN,
0403200000000+I_MXN, 0403300000000+I_MXN,
0404200000000+I_NOP, 0404600000000+I_NOP,
0405100000000+I_IMM, 0405400000000+I_IMM, 0405500000000+I_IMM,
0405600000000+I_IMM, 0405700000000+I_IMM,
0406000000000+I_MXN, 0406100000000+I_MXN, 0406200000000+I_MXN,
0406300000000+I_MXN, 0406400000000+I_MXN, 0406500000000+I_MXN,
0406600000000+I_MXN, 0406700000000+I_MXN,
0410000000000+I_MXN, 0411400000000+I_MXC, 0412000000000+I_MXN,
0413000000000+I_NOP, 0414000000000+I_MXN, 0415400000000+I_MXC,
0420000000000+I_MXN, 0424000000000+I_MXN, 0424100000000+I_MXN,
0426000000000+I_MXN, 0426100000000+I_MXN,
0430000000000+I_MXN, 0430100000000+I_MXN,
0430200000000+I_MXN, 0430300000000+I_MXN,
0430400000000+I_MXN, 0430500000000+I_MXN,
0430600000000+I_MXN, 0430700000000+I_MXN,
0432000000000+I_MXN, 0434000000000+I_MXN,
0450000000000+I_MXN, 0450100000000+I_MXN, 0452000000000+I_MXN,
0453400000000+I_MXR, 0453500000000+I_MXR,
0454000000000+I_MXN, 0454100000000+I_MXN,
0454200000000+I_MXN, 0454300000000+I_MXN,
0454400000000+I_MXN, 0454500000000+I_MXN,
0454600000000+I_MXN, 0454700000000+I_MXN,
0454000000000+I_MXN, 0454100000000+I_MXN,
0454200000000+I_MXN, 0454300000000+I_MXN,
0454400000000+I_MXN, 0454500000000+I_MXN,
0454600000000+I_MXN, 0454700000000+I_MXN,
0460000000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN,
0462000000000+I_MXN, 0462500000000+I_MXN,
0463400000000+I_MXR, 0463600000000+I_MXR,
0464000000000+I_MXN, 0464000000000+I_MXN,
0464200000000+I_MXN, 0464300000000+I_MXN,
0464400000000+I_MXN, 0464500000000+I_MXN,
0464600000000+I_MXN, 0464700000000+I_MXN,
0473400000000+I_TAG, 0473700000000+I_TAG,
0475400000000+I_TAG, 0475600000000+I_TAG,
0476000000000+I_MXR, 0476300000000+I_MXR, 0476400000000+I_MXR,
0476500000000+I_MXR, 0477300000000+I_MXR, 0477200000000+I_MXR,
0477400000000+I_MXR,
0010100000000+I_MXN, 0410100000000+I_MXN,
0056200000000+I_MXN, 0456400000000+I_MXN,
0476100000041+I_SNS, 0476100000042+I_SNS,
01000000000000+I_IOX, 01000000200000+I_IOX, 01100000000000+I_TCH,
01200000000000+I_IOX, 01200000200000+I_IOX,
01300000000000+I_IOX, 01300000200000+I_IOX,
01400000000000+I_IOX, 01400000200000+I_IOX,
01500000000000+I_IOX, 01500000200000+I_IOX,
01600000000000+I_IOX, 01600000200000+I_IOX,
01700000000000+I_IOX, 01700000200000+I_IOX,
02000000000000+I_TCH, 02000000200000+I_IOX,
02100000000000+I_TCH, 02100000200000+I_TCH,
02200000000000+I_I9N, 02220000000000+I_TCH,
02200000200000+I_I9N, 02220000200000+I_TCH,
02240000000000+I_I9N, 02260000000000+I_TCH,
02240000200000+I_I9N,
02300000000000+I_I9S, 02300000200000+I_I9S,
02340000000000+I_I9S,
02400000000000+I_IOX,
02500000000000+I_IOX, 02500000200000+I_IOX,
02600000200000+I_I9S, 02640000000000+I_I9S, 02640000200000+I_I9S,
02700000000000+I_I9S, 02700000200000+I_IOX,
0
};
/* 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 i, j, k, l, fmt, c, fld[3];
DEVICE *dptr;
t_uint64 inst;
inst = val[0];
if (uptr == NULL) uptr = &cpu_unit;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
if (sw & SWMASK ('C')) { /* character? */
c = (uint32) (inst & 077);
fprintf (of, "%c", cvt_code_to_ascii (c, sw));
return SCPE_OK;
}
if (sw & SWMASK ('S')) { /* string? */
for (i = 36; i > 0; i = i - 6) {
c = (uint32) ((inst >> (i - 6)) & 077);
fprintf (of, "%c", cvt_code_to_ascii (c, sw));
}
return SCPE_OK;
}
if (!(sw & (SWMASK ('M')|SWMASK ('I')|SWMASK ('N'))) || /* M, N or I? */
(dptr->dwidth != 36)) return SCPE_ARG;
/* Instruction decode */
fld[0] = ((uint32) inst & 0777777);
fld[1] = GET_TAG (inst); /* get 3 fields */
fld[2] = GET_DEC (inst);
if (sw & SWMASK ('I')) inst |= IFAKE_7607; /* decode as 7607? */
if (sw & SWMASK ('N')) inst |= IFAKE_7909; /* decode as 7909? */
for (i = 0; opc_v[i] > 0; i++) { /* loop thru ops */
j = (int32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */
if ((opc_v[i] & DFAKE) == (inst & masks[j])) { /* match? */
if (inst & ind_test[j]) /* indirect? */
fprintf (of, "%s*", opcode[i]);
else fprintf (of, "%s", opcode[i]); /* opcode */
for (k = 0; k < 3; k++) fld[k] = fld[k] & fld_max[j][k];
for (k = 0; k < 3; k++) { /* loop thru fields */
fmt = fld_fmt[j][k]; /* get format */
if (fmt == INST_P_XIT) return SCPE_OK;
switch (fmt) { /* case on format */
case INST_P_PNT: /* print nz, else term */
for (l = k, c = 0; l < 3; l++) c |= fld[k];
if (c == 0) return SCPE_OK;
case INST_P_PNZ: /* print non-zero */
fputc (k? ',': ' ', of);
if (fld[k]) fprintf (of, "%-o", fld[k]);
break;
case INST_P_PRA: /* print always */
fputc (k? ',': ' ', of);
fprintf (of, "%-o", fld[k]);
break;
case INST_P_SKP: /* skip */
break;
} /* end switch */
} /* end for k */
return SCPE_OK; /* done */
} /* end if */
} /* end for i */
return SCPE_ARG;
}
/* Convert character to code to ASCII
-b BCD
-a business-chain */
uint32 cvt_code_to_ascii (uint32 c, int32 sw)
{
if (sw & SWMASK ('B')) {
if (sw & SWMASK ('A')) return bcd_to_ascii_a[c];
else return bcd_to_ascii_h[c];
}
else if (sw & SWMASK ('A')) return nine_to_ascii_a[c];
else return nine_to_ascii_h[c];
}
/* 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)
{
uint32 i, j, c;
t_uint64 fld[3];
t_bool ind;
t_stat r;
char gbuf[CBUFSIZE];
while (isspace (*cptr)) cptr++;
if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (t_value) cvt_ascii_to_code (cptr[0] & 0177, sw);
return SCPE_OK;
}
if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 6; i++) {
c = cptr[0] & 0177;
if (c) val[0] = (val[0] << 6) | ((t_value) cvt_ascii_to_code (c, sw));
else {
val[0] = val[0] << (6 * (6 - i));
break;
}
}
return SCPE_OK;
}
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
j = strlen (gbuf); /* get length */
if (gbuf[j - 1] == '*') { /* indirect? */
ind = TRUE;
gbuf[j - 1] = 0;
}
else ind = FALSE;
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
j = (uint32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */
val[0] = opc_v[i] & DMASK;
if (ind) {
if (ind_test[j]) val[0] |= ind_test[j];
else return SCPE_ARG;
}
for (i = 0; i < 3; i++) fld[i] = 0; /* clear inputs */
for (i = 0; (i < 3) && *cptr; i++) { /* parse inputs */
if (i < 2) cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
else cptr = get_glyph (cptr, gbuf, 0);
if (gbuf[0]) { /* anything? */
fld[i] = get_uint (gbuf, 8, fld_max[j][i], &r);
if ((r != SCPE_OK) || (fld_max[j][i] == 0)) return SCPE_ARG;
}
}
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
val[0] = val[0] | fld[0] | (fld[1] << INST_V_TAG) | (fld[2] << INST_V_DEC);
return SCPE_OK;
}
/* Convert ASCII to character code
-b BCD */
uint32 cvt_ascii_to_code (uint32 c, int32 sw)
{
if (sw & SWMASK ('B')) return ascii_to_bcd[c];
else return ascii_to_nine[c];
}