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:
committed by
Mark Pizzolato
parent
a12e4a1c39
commit
dc871fa631
72
I7094/i7094_bugs.txt
Normal file
72
I7094/i7094_bugs.txt
Normal 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
495
I7094/i7094_cd.c
Normal 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
124
I7094/i7094_clk.c
Normal 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
1149
I7094/i7094_com.c
Normal file
File diff suppressed because it is too large
Load Diff
2239
I7094/i7094_cpu.c
Normal file
2239
I7094/i7094_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
837
I7094/i7094_cpu1.c
Normal file
837
I7094/i7094_cpu1.c
Normal 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
152
I7094/i7094_dat.h
Normal 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
474
I7094/i7094_defs.h
Normal 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
286
I7094/i7094_drm.c
Normal 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
1172
I7094/i7094_dsk.c
Normal file
File diff suppressed because it is too large
Load Diff
1789
I7094/i7094_io.c
Normal file
1789
I7094/i7094_io.c
Normal file
File diff suppressed because it is too large
Load Diff
365
I7094/i7094_lp.c
Normal file
365
I7094/i7094_lp.c
Normal 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
826
I7094/i7094_mt.c
Normal 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
718
I7094/i7094_sys.c
Normal 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];
|
||||
}
|
||||
Reference in New Issue
Block a user