1
0
mirror of https://github.com/simh/simh.git synced 2026-02-21 14:48:53 +00:00

Notes For V2.10-0

WARNING: V2.10 has reorganized and renamed some of the definition
files for the PDP-10, PDP-11, and VAX.  Be sure to delete all
previous source files before you unpack the Zip archive, or
unpack it into a new directory structure.

WARNING: V2.10 has a new, more comprehensive save file format.
Restoring save files from previous releases will cause 'invalid
register' errors and loss of CPU option flags, device enable/
disable flags, unit online/offline flags, and unit writelock
flags.

WARNING: If you are using Visual Studio .NET through the IDE,
be sure to turn off the /Wp64 flag in the project settings, or
dozens of spurious errors will be generated.

WARNING: Compiling Ethernet support under Windows requires
extra steps; see the Ethernet readme file.  Ethernet support is
currently available only for Windows, Linux, NetBSD, and OpenBSD.

1. New Features

1.1 SCP and Libraries

- The VT emulation package has been replaced by the capability
  to remote the console to a Telnet session.  Telnet clients
  typically have more complete and robust VT100 emulation.
- Simulated devices may now have statically allocated buffers,
  in addition to dynamically allocated buffers or disk-based
  data stores.
- The DO command now takes substitutable arguments (max 9).
  In command files, %n represents substitutable argument n.
- The initial command line is now interpreted as the command
  name and substitutable arguments for a DO command.  This is
  backward compatible to prior versions.
- The initial command line parses switches.  -Q is interpreted
  as quiet mode; informational messages are suppressed.
- The HELP command now takes an optional argument.  HELP <cmd>
  types help on the specified command.
- Hooks have been added for implementing GUI-based consoles,
  as well as simulator-specific command extensions.  A few
  internal data structures and definitions have changed.
- Two new routines (tmxr_open_master, tmxr_close_master) have
  been added to sim_tmxr.c.  The calling sequence for
  sim_accept_conn has been changed in sim_sock.c.
- The calling sequence for the VM boot routine has been modified
  to add an additional parameter.
- SAVE now saves, and GET now restores, controller and unit flags.
- Library sim_ether.c has been added for Ethernet support.

1.2 VAX

- Non-volatile RAM (NVR) can behave either like a memory or like
  a disk-based peripheral.  If unattached, it behaves like memory
  and is saved and restored by SAVE and RESTORE, respectively.
  If attached, its contents are loaded from disk by ATTACH and
  written back to disk at DETACH and EXIT.
- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape) has been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from vax_stddev.c and
  now references a common implementation file, dec_pt.h.
- Examine and deposit switches now work on all devices, not just
  the CPU.
- Device address conflicts are not detected until simulation starts.

1.3 PDP-11

- SHOW <device> VECTOR displays the device's interrupt vector.
  Most devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk),
  RX211 (double density floppy), and KW11P programmable clock
  have been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from pdp11_stddev.c and
  now references a common implementation file, dec_pt.h.
- Device bootstraps now use the actual CSR specified by the
  SET ADDRESS command, rather than just the default CSR.  Note
  that PDP-11 operating systems may NOT support booting with
  non-standard addresses.
- Specifying more than 256KB of memory, or changing the bus
  configuration, causes all peripherals that are not compatible
  with the current bus configuration to be disabled.
- Device address conflicts are not detected until simulation starts.

1.4 PDP-10

- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The RX211 (double density floppy) has been added; it is off
  by default.
- The paper tape now references a common implementation file,
  dec_pt.h.
- Device address conflicts are not detected until simulation starts.

1.5 PDP-1

- DECtape (then known as MicroTape) support has been added.
- The line printer and DECtape can be disabled and enabled.

1.6 PDP-8

- The RX28 (double density floppy) has been added as an option to
  the existing RX8E controller.
- SHOW <device> DEVNO displays the device's device number.  Most
  devices allow the device number to be changed with SET <device>
  DEVNO=nnn.
- Device number conflicts are not detected until simulation starts.

1.7 IBM 1620

- The IBM 1620 simulator has been released.

1.8 AltairZ80

- A hard drive has been added for increased storage.
- Several bugs have been fixed.

1.9 HP 2100

- The 12845A has been added and made the default line printer (LPT).
  The 12653A has been renamed LPS and is off by default.  It also
  supports the diagnostic functions needed to run the DCPC and DMS
  diagnostics.
- The 12557A/13210A disk defaults to the 13210A (7900/7901).
- The 12559A magtape is off by default.
- New CPU options (EAU/NOEAU) enable/disable the extended arithmetic
  instructions for the 2116.  These instructions are standard on
  the 2100 and 21MX.
- New CPU options (MPR/NOMPR) enable/disable memory protect for the
  2100 and 21MX.
- New CPU options (DMS/NODMS) enable/disable the dynamic mapping
  instructions for the 21MX.
- The 12539 timebase generator autocalibrates.

1.10 Simulated Magtapes

- Simulated magtapes recognize end of file and the marker
  0xFFFFFFFF as end of medium.  Only the TMSCP tape simulator
  can generate an end of medium marker.
- The error handling in simulated magtapes was overhauled to be
  consistent through all simulators.

1.11 Simulated DECtapes

- Added support for RT11 image file format (256 x 16b) to DECtapes.

2. Release Notes

2.1 Bugs Fixed

- TS11/TSV05 was not simulating the XS0_MOT bit, causing failures
  under VMS.  In addition, two of the CTL options were coded
  interchanged.
- IBM 1401 tape was not setting a word mark under group mark for
  load mode reads.  This caused the diagnostics to crash.
- SCP bugs in ssh_break and set_logon were fixed (found by Dave
  Hittner).
- Numerous bugs in the HP 2100 extended arithmetic, floating point,
  21MX, DMS, and IOP instructions were fixed.  Bugs were also fixed
  in the memory protect and DMS functions.  The moving head disks
  (DP, DQ) were revised to simulate the hardware more accurately.
  Missing functions in DQ (address skip, read address) were added.

2.2 HP 2100 Debugging

- The HP 2100 CPU nows runs all of the CPU diagnostics.
- The peripherals run most of the peripheral diagnostics.  There
  is still a problem in overlapped seek operation on the disks.
  See the file hp2100_diag.txt for details.

3. In Progress

These simulators are not finished and are available in a separate
Zip archive distribution.

- Interdata 16b/32b: coded, partially tested.  See the file
  id_diag.txt for details.
- SDS 940: coded, partially tested.
This commit is contained in:
Bob Supnik
2002-11-17 15:54:00 -08:00
committed by Mark Pizzolato
parent df6475181c
commit 2c2dd5ea33
218 changed files with 44103 additions and 17112 deletions

403
I1620/i1620_cd.c Normal file
View File

@@ -0,0 +1,403 @@
/* i1620_cd.c: IBM 1622 card reader/punch
Copyright (c) 2002, 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 1622 card reader
cdp 1622 card punch
Cards are represented as ASCII text streams terminated by newlines.
This allows cards to be created and edited as normal files.
*/
#include "i1620_defs.h"
#define CD_LEN 80
extern uint8 M[MAXMEMSIZE];
extern uint8 ind[NUM_IND];
extern UNIT cpu_unit;
extern int32 io_stop;
char cdr_buf[CD_LEN + 2];
char cdp_buf[CD_LEN + 2];
t_stat cdr_reset (DEVICE *dptr);
t_stat cdr_attach (UNIT *uptr, char *cptr);
t_stat cdr_boot (int32 unitno, DEVICE *dptr);
t_stat cdr_read (void);
t_stat cdp_reset (DEVICE *dptr);
t_stat cdp_write (uint32 len);
t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump);
/* Card reader data structures
cdr_dev CDR descriptor
cdr_unit CDR unit descriptor
cdr_reg CDR register list
*/
UNIT cdr_unit = {
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) };
REG cdr_reg[] = {
{ FLDATA (LAST, ind[IN_LAST], 0) },
{ DRDATA (POS, cdr_unit.pos, 32), PV_LEFT },
{ NULL } };
DEVICE cdr_dev = {
"CDR", &cdr_unit, cdr_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cdr_reset,
&cdr_boot, &cdr_attach, NULL };
/* CDP data structures
cdp_dev CDP device descriptor
cdp_unit CDP unit descriptor
cdp_reg CDP register list
*/
UNIT cdp_unit = {
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
REG cdp_reg[] = {
{ DRDATA (POS, cdp_unit.pos, 32), PV_LEFT },
{ NULL } };
DEVICE cdp_dev = {
"CDP", &cdp_unit, cdp_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cdp_reset,
NULL, NULL, NULL };
/* Data tables. The card reader presents unusual problems.
- Unique codes needed for 11-2-8 (uses !) and 12-7-8 (uses ") .
- Can punch both 11 (-) and 11-0 (uses ]).
On input, the nul and nl generated by C are converted to
spaces; tabs and line feeds are also converted to spaces.
/* Card reader (ASCII) to numeric (one digit) */
const char cdr_to_num[128] = {
0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */
-1, 0x00, 0x00, -1, -1, 0x00, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1,
0x00, 0x1A, 0x1F, 0x00, 0x1B, 0x0A, 0x0F, 0x0A, /* !"#$%&' */
0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x1B, 0x01, /* ()*+,-./ */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */
0x08, 0x09, 0x00, 0x1E, 0x1E, 0x0B, 0x0E, 0x1A, /* 89:;<=>? */
0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* @ABCDEFG */
0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* HIJKLMNO */
0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* PQRSTUVW */
0x07, 0x08, 0x09, 0x00, 0x0E, 0x10, 0x0F, 0x1F, /* XYZ[\]^_ */
-1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* abcdefg */
0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* hijklmno */
0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* pqrstuvw */
0x07, 0x08, 0x09, -1, -1, -1, -1, -1 }; /* xyz */
/* Numeric (flag + digit) to card punch (ASCII) */
const char num_to_cdp[32] = {
'0', '1', '2', '3', '4', '5', '6', '7', /* 0 */
'8', '9', '\'', ',', ' ', '&', ' ', '&',
']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* F + 0 */
'Q', 'R', '!', '$', -1, -1, -1, '"' };
/* Card reader (ASCII) to alphameric (two digits)
11-2-8 (!) reads as 5A
11-7-8 (_) reads as 5F
12-2-8 (?) reads inconsistently (here 02)
12-6-8 (<) reads inconsistently (here 5E)
12-7-8 (") reads as 5F
*/
const char cdr_to_alp[128] = {
0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */
-1, 0x00, 0x00, -1, -1, 0x00, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1,
0x00, 0x5A, 0x5F, 0x60, 0x13, 0x0A, 0x0F, 0x0A, /* !"#$%&' */
0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */
0x78, 0x79, 0x70, 0x5E, 0x5E, 0x33, 0x0E, 0x02, /* 89:;<=>? */
0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */
0x67, 0x68, 0x69, 0x40, 0x0E, 0x50, 0x0F, 0x5F, /* XYZ[\]^_ */
-1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */
0x67, 0x68, 0x69, -1, -1, -1, -1, -1 }; /* xyz */
/* Alphameric (two digits) to card punch (ASCII). Oddities:
02 -> 12-2-8 (?), symmetric
07 -> 12-7-8 ("), reads as 5F
12 -> 11-2-8 (!), reads as 5A
15 -> 11,0 (]), reads as 50
22 -> 0-2-8 ('), reads as 0A
32 -> 2-8 (%), reads as 0A
5B -> 11-3-8 (=), reads as 13
6A -> 0-2-8 ('), reads as 0A
6B -> 0-3-8 (,), reads as 23
AA -> 0-2-8 ('), reads as 0A
There is no way to punch 0-5-8 (#), 0-6-8 (\),
11-5-8 (]), 11-6-8 (;), 11-7-8 (_),
12-5-8 ([), or 12-6-8 (<)
*/
const char alp_to_cdp[256] = {
' ', -1, '?', '.', ')', -1, -1, '"', /* 00 */
-1, -1, '\'', -1, -1, -1, -1, '&',
'+', -1, '!', '$', '*', ']', -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1,
'-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, '%', '=', '@', ':', ' ', -1, /* 30 */
-1, -1, '\'', -1, -1, -1, -1, '&',
-1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
'H', 'I', -1, -1, -1, -1, -1, -1,
'_', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
'Q', 'R', '?', '=', -1, -1, -1, '"',
-1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
'Y', 'Z', '\'', ',', -1, -1, -1, -1,
'0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
'8', '9', -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
-1, -1, '\'', -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
-1, -1, -1, -1, -1, -1, -1, -1 };
/* Card reader IO routine
- Hard errors stop the operation and halt the system.
- Invalid characters place a blank in memory and set RDCHK.
If IO stop is set, the system halts at the end of the operation.
*/
t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
int32 i;
int8 cdc;
t_stat r, inv = SCPE_OK;
switch (op) { /* case on op */
case OP_RN: /* read numeric */
r = cdr_read (); /* fill reader buf */
if (r != SCPE_OK) return r; /* error? */
for (i = 0; i < CD_LEN; i++) { /* transfer to mem */
cdc = cdr_to_num[cdr_buf[i]]; /* translate */
if (cdc < 0) { /* invalid? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
cdc = 0; }
M[pa] = cdc; /* store digit */
PP (pa); } /* incr mem addr */
break;
case OP_RA: /* read alphameric */
r = cdr_read (); /* fill reader buf */
if (r != SCPE_OK) return r; /* error? */
for (i = 0; i < CD_LEN; i++) { /* transfer to mem */
cdc = cdr_to_alp[cdr_buf[i]]; /* translate */
if (cdc < 0) { /* invalid? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
cdc = 0; };
M[pa] = (M[pa] & FLAG) | (cdc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((cdc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
CRETIOE (io_stop, inv);
}
/* Fill card reader buffer - all errors are hard errors */
t_stat cdr_read (void)
{
int32 i;
ind[IN_LAST] = 0; /* clear last card */
if ((cdr_unit.flags & UNIT_ATT) == 0) { /* attached? */
ind[IN_RDCHK] = 1; /* no, error */
return SCPE_UNATT; }
for (i = 0; i < CD_LEN + 1; i++) cdr_buf[i] = ' '; /* clear buffer */
fgets (cdr_buf, CD_LEN, cdr_unit.fileref); /* read card */
if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */
if (ferror (cdr_unit.fileref)) { /* error? */
ind[IN_RDCHK] = 1; /* set read check */
perror ("CDR I/O error");
clearerr (cdr_unit.fileref);
return SCPE_IOERR; }
cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */
getc (cdr_unit.fileref); /* see if more */
if (feof (cdr_unit.fileref)) ind[IN_LAST] = 1; /* eof? set last */
fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); /* "backspace" */
return SCPE_OK;
}
/* Card reader attach */
t_stat cdr_attach (UNIT *uptr, char *cptr)
{
ind[IN_LAST] = 0; /* clear last card */
return attach_unit (uptr, cptr);
}
/* Card reader reset */
t_stat cdr_reset (DEVICE *dptr)
{
ind[IN_LAST] = 0; /* clear last card */
return SCPE_OK;
}
/* Bootstrap routine */
const static uint8 boot_rom[] = {
3, 6, 1, 9, 9, 0, 1, 0, 0, 5, 0, 0, /* RNCD 19901 */
2, 5, 0, 0, 0, 8, 0, 1, 9, 9, 1, 0x10, /* TD 80,-19910 */
3, 1, 1, 9, 9, 0, 0x15, 1, 9, 9, 2, 0, /* TR -19905,19920 */
2, 5, 1, 9, 9, 1, 0x10, 0, 0, 0, 8, 0, /* TD -19910,80 */
4, 9, 1, 9, 9, 1, 0x15, 0, 0, 0, 0, 0 }; /* BR -19915 */
#define BOOT_START 0
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
t_stat cdr_boot (int32 unitno, DEVICE *dptr)
{
int32 i;
extern int32 saved_PC;
if ((cpu_unit.flags & IF_IA) == 0) return SCPE_NOFNC; /* must have IA */
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;
return SCPE_OK;
}
/* Card punch IO routine
- Hard errors stop the operation and halt the system.
- Invalid characters stop the operation and set WRCHK.
If IO stop is set, the system halts.
*/
t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
int32 i;
int8 cdc;
uint8 z, d;
switch (op) { /* decode op */
case OP_DN:
return cdp_num (pa, 20000 - (pa % 20000), TRUE); /* dump numeric */
case OP_WN:
return cdp_num (pa, CD_LEN, FALSE); /* write numeric */
case OP_WA:
for (i = 0; i < CD_LEN; i++) { /* one card */
d = M[pa] & DIGIT; /* get digit pair */
z = M[pa - 1] & DIGIT;
cdc = alp_to_cdp[(z << 4) | d]; /* translate */
if (cdc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
CRETIOE (io_stop, STOP_INVCHR); }
cdp_buf[i] = cdc; /* store in buf */
pa = ADDR_A (pa, 2); } /* incr mem addr */
return cdp_write (CD_LEN); /* punch buffer */
default: /* invalid function */
return STOP_INVFNC; }
return SCPE_OK;
}
/* Punch card numeric */
t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump)
{
int32 i, ncd, len;
uint8 d;
int8 cdc;
t_stat r;
ncd = ndig / CD_LEN; /* number of cards */
while (ncd-- >= 0) { /* until done */
len = (ncd >= 0)? CD_LEN: (ndig % CD_LEN); /* card length */
if (len == 0) break;
for (i = 0; i < len; i++) { /* one card */
d = M[pa] & (FLAG | DIGIT); /* get char */
if (dump && (d == FLAG)) cdc = '-'; /* dump? F+0 is diff */
else cdc = num_to_cdp[d]; /* translate */
if (cdc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
CRETIOE (io_stop, STOP_INVCHR); } /* stop */
cdp_buf[i] = cdc; /* store in buf */
PP (pa); } /* incr mem addr */
r = cdp_write (len); /* punch card */
if (r != SCPE_OK) return r; } /* error? */
return SCPE_OK;
}
/* Write punch card buffer - all errors are hard errors */
t_stat cdp_write (uint32 len)
{
if ((cdp_unit.flags & UNIT_ATT) == 0) { /* attached? */
ind[IN_WRCHK] = 1; /* no, error */
return SCPE_UNATT; }
while ((len > 0) && (cdp_buf[len - 1] == ' ')) --len; /* trim spaces */
cdp_buf[len] = '\n'; /* newline, null */
cdp_buf[len + 1] = 0;
if (fputs (cdp_buf, cdp_unit.fileref) == EOF) { /* write card */
ind[IN_WRCHK] = 1; /* error? */
perror ("CDP I/O error");
clearerr (cdp_unit.fileref);
return SCPE_IOERR; }
cdp_unit.pos = ftell (cdp_unit.fileref); /* count char */
return SCPE_OK;
}
/* Reset card punch */
t_stat cdp_reset (DEVICE *dptr)
{
return SCPE_OK;
}

1861
I1620/i1620_cpu.c Normal file

File diff suppressed because it is too large Load Diff

221
I1620/i1620_defs.h Normal file
View File

@@ -0,0 +1,221 @@
/* i1620_defs.h: IBM 1620 simulator definitions
Copyright (c) 2002, 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 is based on the 1620 simulator written by Geoff Kuenning.
I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate
Archives for their help in gathering documentation about the IBM 1620.
18-Oct-02 RMS Fixed bug in ADDR_S macro (found by Hans Pufal)
*/
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_HALT 1 /* HALT */
#define STOP_IBKPT 2 /* breakpoint */
#define STOP_INVINS 3 /* invalid instruction */
#define STOP_INVDIG 4 /* invalid digit */
#define STOP_INVCHR 5 /* invalid char */
#define STOP_INVIND 6 /* invalid indicator */
#define STOP_INVPDG 7 /* invalid P addr digit */
#define STOP_INVPAD 8 /* invalid P addr */
#define STOP_INVPIA 9 /* invalid P indir addr */
#define STOP_INVQDG 10 /* invalid Q addr digits */
#define STOP_INVQAD 11 /* invalid Q addr */
#define STOP_INVQIA 12 /* invalid Q indir addr */
#define STOP_INVIO 13 /* invalid IO address */
#define STOP_INVRTN 14 /* invalid return */
#define STOP_INVFNC 15 /* invalid function */
#define STOP_INVIAD 16 /* invalid instr addr */
#define STOP_INVSEL 17 /* invalid select */
#define STOP_INVIDX 18 /* invalid index instr */
#define STOP_INVEAD 19 /* invalid even addr */
#define STOP_INVDCF 20 /* invalid DCF addr */
#define STOP_INVDRV 21 /* invalid disk drive */
#define STOP_INVDSC 22 /* invalid disk sector */
#define STOP_INVDCN 23 /* invalid disk count */
#define STOP_INVDBA 24 /* invalid disk buf addr */
#define STOP_DACERR 25 /* disk addr comp err */
#define STOP_DWCERR 26 /* disk wr check err */
#define STOP_CYOERR 27 /* cylinder ovflo err */
#define STOP_WRLERR 28 /* wrong rec lnt err */
#define STOP_CCT 29 /* runaway CCT */
#define STOP_FWRAP 30 /* field wrap */
#define STOP_RWRAP 31 /* record wrap */
#define STOP_NOCD 32 /* no card in reader */
#define STOP_OVERFL 33 /* overflow */
#define STOP_EXPCHK 34 /* exponent error */
#define STOP_WRADIS 35 /* write addr disabled */
#define STOP_FPLNT 36 /* invalid fp length */
#define STOP_FPUNL 37 /* fp lengths unequal */
#define STOP_FPMF 38 /* no flag on exp */
#define STOP_FPDVZ 39 /* divide by zero */
/* Memory */
#define MAXMEMSIZE 60000 /* max mem size */
#define MEMSIZE (cpu_unit.capac) /* act memory size */
/* Processor parameters */
#define INST_LEN 12 /* inst length */
#define ADDR_LEN 5 /* addr length */
#define MUL_TABLE 100 /* multiply table */
#define MUL_TABLE_LEN 200
#define ADD_TABLE 300 /* add table */
#define ADD_TABLE_LEN 100
#define IDX_A 300 /* index A base */
#define IDX_B 340 /* index B base */
#define PROD_AREA 80 /* product area */
#define PROD_AREA_LEN 20 /* product area */
#define PROD_AREA_END (PROD_AREA + PROD_AREA_LEN)
/* Branch indicator codes */
#define NUM_IND 100 /* number of indicators */
#define IN_SW1 1 /* sense switch 1 */
#define IN_SW2 2 /* sense switch 2 */
#define IN_SW3 3 /* sense switch 3 */
#define IN_SW4 4 /* sense switch 4 */
#define IN_RDCHK 6 /* read check (I/O error) */
#define IN_WRCHK 7 /* write check (I/O error) */
#define IN_LAST 9 /* last card was just read */
#define IN_HP 11 /* high or positive result */
#define IN_EZ 12 /* equal or zero result */
#define IN_HPEZ 13 /* high/positive or equal/zero */
#define IN_OVF 14 /* overflow */
#define IN_EXPCHK 15 /* floating exponent check */
#define IN_MBREVEN 16 /* even parity check */
#define IN_MBRODD 17 /* odd parity check */
#define IN_ANYCHK 19 /* any of read, write, even/odd */
#define IN_PRCHK 25 /* printer check */
#define IN_IXN 30 /* IX neither */
#define IN_IXA 31 /* IX A band */
#define IN_IXB 32 /* IX B band */
#define IN_PRCH9 33 /* printer chan 9 */
#define IN_PRCH12 34 /* printer chan 12 */
#define IN_PRBSY 35 /* printer busy */
#define IN_DACH 36 /* disk addr/data check */
#define IN_DWLR 37 /* disk rec length */
#define IN_DCYO 38 /* disk cyl overflow */
#define IN_DERR 39 /* disk any error */
/* I/O channel codes */
#define NUM_IO 100 /* number of IO chan */
#define IO_TTY 1 /* console typewriter */
#define IO_PTP 2 /* paper-tape punch */
#define IO_PTR 3 /* paper-tape reader */
#define IO_CDP 4 /* card punch */
#define IO_CDR 5 /* card reader */
#define IO_DSK 7 /* disk */
#define IO_LPT 9 /* line printer */
#define IO_BTP 32 /* binary ptp */
#define IO_BTR 33 /* binary ptr */
#define LPT_WIDTH 120 /* line print width */
#define CCT_LNT 132 /* car ctrl length */
#define CRETIOE(f,c) return ((f)? (c): SCPE_OK)
/* Memory representation: flag + BCD digit per byte */
#define FLAG 0x10
#define DIGIT 0x0F
#define REC_MARK 0xA
#define NUM_BLANK 0xC
#define GRP_MARK 0xF
#define BAD_DIGIT(x) ((x) > 9)
/* Instruction format */
#define I_OP 0 /* opcode */
#define I_P 2 /* P start */
#define I_PL 6 /* P end */
#define I_Q 7 /* Q start */
#define I_QL 11 /* Q end */
#define I_IO 8 /* IO select */
#define I_BR 8 /* indicator select */
#define I_CTL 10 /* control select */
#define I_SEL 11 /* BS select */
#define ADDR_A(x,a) ((((x) + (a)) >= MEMSIZE)? ((x) + (a) - MEMSIZE): ((x) + (a)))
#define ADDR_S(x,a) (((x) < (a))? ((x) - (a) + MEMSIZE): ((x) - (a)))
#define PP(x) x = ADDR_A(x,1)
#define MM(x) x = ADDR_S(x,1)
/* CPU options, stored in cpu_unit.flags */
/* Decoding flags must be part of the same definition set */
#define UNIT_SCP ((1 << UNIT_V_UF) - 1) /* mask of SCP flags */
#define IF_MII (1 << (UNIT_V_UF + 0)) /* model 2 */
#define IF_DIV (1 << (UNIT_V_UF + 1)) /* automatic divide */
#define IF_IA (1 << (UNIT_V_UF + 2)) /* indirect addressing */
#define IF_EDT (1 << (UNIT_V_UF + 3)) /* edit */
#define IF_FP (1 << (UNIT_V_UF + 4)) /* floating point */
#define IF_BIN (1 << (UNIT_V_UF + 5)) /* binary */
#define IF_IDX (1 << (UNIT_V_UF + 6)) /* indexing */
#define IF_VPA (1 << (UNIT_V_UF + 7)) /* valid P addr */
#define IF_VQA (1 << (UNIT_V_UF + 8)) /* valid Q addr */
#define IF_4QA (1 << (UNIT_V_UF + 9)) /* 4 char Q addr */
#define IF_NQX (1 << (UNIT_V_UF + 10)) /* no Q indexing */
#define IF_IMM (1 << (UNIT_V_UF + 11)) /* immediate */
#define UNIT_BCD (1 << (UNIT_V_UF + 12)) /* BCD coded */
#define UNIT_MSIZE (1 << (UNIT_V_UF + 13)) /* fake flag */
#define ALLOPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX)
#define MI_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP)
#define MI_STD (IF_DIV + IF_IA + IF_EDT)
#define MII_OPT (ALLOPT)
#define MII_STD (IF_DIV + IF_IA + IF_EDT + IF_BIN + IF_IDX)
/* Add status codes */
#define ADD_NOCRY 0 /* no carry out */
#define ADD_CARRY 1 /* carry out */
#define ADD_SIGNC 2 /* sign change */
/* Opcodes */
enum opcodes {
OP_FADD = 1, OP_FSUB, OP_FMUL, /* 00 - 09 */
OP_FSL = 5, OP_TFL, OP_BTFL, OP_FSR, OP_FDIV,
OP_BTAM = 10, OP_AM, OP_SM, OP_MM, OP_CM, /* 10 - 19 */
OP_TDM, OP_TFM, OP_BTM, OP_LDM, OP_DM,
OP_BTA = 20, OP_A, OP_S, OP_M, OP_C, /* 20 - 29 */
OP_TD, OP_TF, OP_BT, OP_LD, OP_D,
OP_TRNM = 30, OP_TR, OP_SF, OP_CF, OP_K, /* 30 - 39 */
OP_DN, OP_RN, OP_RA, OP_WN, OP_WA,
OP_NOP = 41, OP_BB, OP_BD, OP_BNF, /* 40 - 49 */
OP_BNR, OP_BI, OP_BNI, OP_H, OP_B,
OP_BNG = 55,
OP_BS = 60, OP_BX, OP_BXM, OP_BCX, OP_BCXM, /* 60 - 69 */
OP_BLX, OP_BLXM, OP_BSX,
OP_MA = 70, OP_MF, OP_TNS, OP_TNF, /* 70 - 79 */
/* 80 - 89 */
OP_BBT = 90, OP_BMK, OP_ORF, OP_ANDF, OP_CPLF, /* 90 - 99 */
OP_EORF, OP_OTD, OP_DTO };

518
I1620/i1620_doc.txt Normal file
View File

@@ -0,0 +1,518 @@
To: Users
From: Bob Supnik
Subj: IBM 1620 Simulator Usage
Date: 15-Nov-2002
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik
Copyright (c) 1993-2002, 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 memorandum documents the IBM 1620 simulator. This simulator is based on
Geoff Kuenning's 1620 simulator, which is used by permission.
1. Simulator Files
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tmxr.h
scp.c
scp_tty.c
sim_sock.c
sim_tmxr.c
sim/i1620/ i1620_defs.h
i1620_cpu.c
i1620_fp.c
i1620_tty.c
i1620_pt.c
i1620_cd.c
i1620_lp.c
i1620_dp.c
i1620_sys.c
2. IBM 1620 Features
The IBM 1620 simulator is configured as follows:
device simulates
name(s)
CPU IBM 1620 Model 1 or Model 2 CPU with 20K to 60K of memory
Model 1 options: indirect addressing, automatic divide,
edit instructions, floating point
Model 2 options: indexing, binary capability, floating point
TTY IBM console terminal
PTR IBM 1621 paper tape reader
PTP IBM 1624 paper tape punch
CDR,CDP IBM 1622 card reader/punch
LPT IBM 1443 line printer
DP IBM 1311 disk pack with four drives
The IBM 1620 simulator implements many unique stop conditions. On almost
any kind of error the simulator stops:
unimplemented opcode
reference to non-existent device
invalid digit
invalid alphameric character
invalid P address digit
invalid Q address digit
indirect address limit exceeded
invalid odd address
invalid even address
invalid function
invalid indicator
invalid return address register
skip to unpunched carriage control tape channel
card reader hopper empty
overflow with arithmetic stop switch set
I/O error with I/O stop switch set
invalid disk drive
invalid disk sector address
invalid disk sector count
invalid disk buffer address
disk address compare error
disk cylinder overflow error
disk write check error
field exceeds memory
record exceeds memory
floating point mantissa exceeds maximum length
floating point mantissas not the same length
floating point exponent check with arithmetic stop switch set
floating point exponent missing high flag
The LOAD command is used to load a line printer carriage-control tape.
The DUMP command is not implemented.
2.1 CPU
The CPU options include the CPU model (Model 1 or Model 2), a number of
special features, and the size of main memory.
SET CPU IA enable indirect addressing
SET CPU NOIA disable indirect addressing
SET CPU EDT enable extra editing instructions
SET CPU NOEDT disable extra editing instructions
SET CPU DIV enable divide instructions
SET CPU NODIV disable divide instructions
SET CPU IDX enable indexing
SET CPU NOIDX disable indexing
SET CPU BIN enable binary instructions
SET CPU NOBIN disable binary instructions
SET CPU FP enable floating point instructions
SET CPU NOFP disable floating point instructions
SET CPU MOD1 set Model 1
SET CPU MOD2 set Model 2
SET CPU 20K set memory size = 20K
SET CPU 40K set memory size = 40K
SET CPU 60K set memory size = 60K
Model 1 options include IA, EDT, DIV, and FP; the first three are on by
default. Model 2 options include IDX, BIN, and FP; IA, EDT, and DIV are
standard on the Model 2.
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initially, memory size is 16K, and all special
features are enabled.
Memory is implemented as 5 bit BCD characters, as follows:
4 3 2 1 0
flag 8 4 2 1
<-------- digit -------->
In BCD, the decimal digits 0-9 are (hex) values 0x0, 0x1, 0x2, 0x3, 0x4,
0x5, 0x6, 0x7, 0x8, 0x9, respectively. 0xA is record mark, 0xC non-
punching blank, and 0xF group mark, respectively.
CPU registers include the visible state of the processor. The 1620 has no
interrupt system.
name size comments
IR1 16 instruction storage address register (PC)
IR2 16 return register
PR1 16 processor register 1
PAR 16 P address register (OR2)
QAR 16 Q address register (OR1)
SS1 1 sense switch 1
SS2 1 sense switch 2
SS3 1 sense switch 3
SS4 1 sense switch 4
HP 1 high/positive indicator
EZ 1 equal/zero indicator
ARCHK 1 arithmetic check (overflow) indicator
EXPCHK 1 exponent check indicator
RDCHK 1 read check indicator
WRCHK 1 write check indicator
ARSTOP 1 arithmetic check stop switch
IOSTOP 1 I/O check stop switch
IND[0:99] 1 indicator array
IAE 1 indirect address enable (Model 2 only)
IDXE 1 indexing enable (Model 2 only)
IDXB 1 indexinb band select (Model 2 only)
IR1Q 1 IR1 prior to last branch;
most recent IR1 change first
WRU 8 interrupt character
2.2 Console Typewriter (TTY)
The console typewriter (TTY) is a half-duplex console. The typewriter
registers are:
name size comments
COL 7 current column
TIME 24 polling interval
When the 1620 CPU requests input from the keyboard, a reverse apostrophe
(`) is printed. The CPU hangs waiting for input until the return/enter
key is pressed. The typewriter has no errors.
2.3 1621 Paper Tape Reader (PTR)
The paper tape reader (PTR) reads data from a disk file. The POS
register specifies the number of the next data item to be read. Thus,
by changing POS, the user can backspace or advance the reader.
The paper tape reader supports the BOOT command. BOOT PTR starts the
specified instruction sequence at location 0.
The paper tape reader implements these registers:
name size comments
POS 32 position in the input file
Error handling is as follows:
error IOCHK processed as
not attached x set RDCHK indicator, report error, stop
end of file x set RDCHK indicator, report error, stop
OS I/O error x set RDCHK indicator, report error, stop
parity error 1 set RDCHK indicator, report error, stop
0 set RDCHK indicator
2.4 1624 Paper Tape Punch (PTP)
The paper tape punch (PTP) writes data to a disk file. The POS register
specifies the number of the next data item to bewritten. Thus, by
changing POS, the user can backspace or advance the punch.
The paper tape punch implements these registers:
name size comments
POS 32 position in the output file
Error handling is as follows:
error IOCHK processed as
not attached x set WRCHK indicator, report error, stop
OS I/O error x set WRCHK indicator, report error, stop
invalid char 1 set WRCHK indicator, report error, stop
0 set WRCHK indicator
2.5 1622 Card Reader/Punch (CDR, CDP)
The IBM 1402 card/reader punch is simulated as two independent devices:
the card reader (CDR) and the card punch (CDP).
The card reader supports the BOOT command. BOOT CDR starts the
specified instruction sequence at location 0.
The card reader reads data from a disk file, while the punch writes data
to a disk file. Cards are simulated as ASCII text lines with terminating
newlines. For each unit, the POS register specifies the number of the
next data item to be read or written. Thus, by changing POS, the user
can backspace or advance these devices.
The card reader registers are:
name size comments
LAST 1 last card indicator
POS 32 position
The card punch registes are:
name size comments
POS 32 position
Card reader error handling is as follows:
error IOCHK processed as
end of file x set RDCHK indicator, report error, stop
not attached x set RDCHK indicator, report error, stop
OS I/O error x set RDCHK indicator, report error, stop
invalid char 1 set RDCHK indicator, report error, stop
0 set RDCHK indicator
Card punch error handling is as follows:
error IOCHK processed as
not attached x set WRCHK indicator, report error, stop
OS I/O error x set WRCHK indicator, report error, stop
invalid char 1 set WRCHK indicator, report error, stop
0 set WRCHK indicator
2.6 1443 Line Printer (LPT)
The IBM 1443 line printer (LPT) writes its data, converted to ASCII, to
a disk file. The line printer can be programmed with a carriage control
tape. The LOAD command loads a new carriage control tape:
LOAD <file> load carriage control tape file
The format of a carriage control tape consists of multiple lines. Each
line contains an optional repeat count, enclosed in parentheses, optionally
followed by a series of column numbers separated by commas. Column numbers
must be between 1 and 12; a column number of zero denotes top of form. The
following are all legal carriage control specifications:
<blank line> no punch
(5) 5 lines with no punches
1,5,7,8 columns 1, 5, 7, 8 punched
(10)2 10 lines with column 2 punched
1,0 column 1 punched; top of form
The default form is 66 lines long, with column 1 and the top of form mark
on line 1, and the rest blank.
The line printer registers are:
name size comments
LBUF[0:119] 7 line buffer
BPTR 7 buffer pointer
PCTL 8 saved print control directive
PRCHK 1 print check indicator
PRCH9 1 channel 9 indicator
PRCH12 1 channel 12 indicator
POS 32 position
CCT[0:131] 32 carriage control tape array
CCTP 8 carriage control tape pointer
CCTL 8 carriage control tape length (read only)
Error handling is as follows:
error IOCHK processed as
not attached x set PRCHK, WRCHK indicators, report error, stop
OS I/O error x set PRCHK, WRCHK indicators, report error, stop
invalid char 1 set PRCHK, WRCHK indicator, report error, stop
0 set PRCHK, WRCHK indicator
2.7 1311 Disk Pack (DP)
The disk pack controller supports 4 drives, numbered 0 through 3. Disk
pack options include the ability to enable address writing (formatting).
SET DPn ADDROFF set unit n address enable off
SET DPn ADDRON set unit n address enable on
Units can also be set ONLINE or OFFLINE.
Unlike most simulated disks, the 1311 includes explicit representation
for sector addresses. This is to support non-standard formats, such as
the inclusion of the drive number in the sector address. As a result,
1311 sectors are 105 digits long: 5 address digits and 100 data digits.
If the 1311 has not been formatted, the addresses are zeroes and are
synthesized, if needed, based on the sector number.
The disk pack controller implements these registers:
name size comments
ADCHK 1 address check (compare error) indicator
WLRC 1 wrong length record check indicator
CYLO 1 cylinder overflow check indicator
ERR 1 disk error indicator
DPSTOP 1 disk check stop
Error handling is as follows:
error DPCHK processed as
not attached x set ERR indicator, report error, stop
1311 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.8 Symbolic Display and Input
The IBM 1620 simulator implements symbolic display and input. Display is
controlled by command line switches:
-c display as single character (alphameric
for CPU and DP, ASCII for others)
-s display as flag terminated numeric string
(CPU and DP only)
-m display instruction mnemonics
(CPU and only)
-d display 50 characters per line, with word
marks denoted by "_" on the line above
In a CPU string display, word marks are denoted by ~.
Input parsing is controlled by the first character typed in or by command
line switches:
' or -c character (alphameric for CPU and DP, ASCII
for others)
" or -s numeric string (CPU and DP only)
alphabetic instruction mnemonic (CPU and DP only)
numeric octal number
Instruction input is free format and consists of an opcode and up to
three operands:
op {+/-}ppppp{(idx)},{+-}qqqqq{(idx)},flags
The p address and, if present, the q address, are always decimal. A
plus sign is ignored; a minus sign denotes indirect addressing (or a
negative immediate operand). If indexing is enabled, addresses may
be indexed; index registers are decimal numbers between 1 and 7. The
flags field is used to set extra flags on the instruction. It consists
of digit numbers in ascending order, with no separators. For example,
AM -12345(5),67890,110
translates into
_ _ ___ _
111234567890
The flag over digits 3 and 5 specify the P index register; the flag
over digit 6 specifies the P indirect address; the flag over digit 7
marks the end of the immediate Q operand; and the flags over digits
1 and 10 are specified by the third field.
2.9 Character Sets
The IBM 1620 uses single digits to represent numbers, and pairs of
digits to represent characters (alphameric coding). Only a small
number of the 256 possible alphameric codings have legitimate values.
Further, the translation between alphameric and devices varied
from device to device. The simulator implements a code called
which allows all 64 possible card codes to be represented by upper
case ASCII characters. In addition, lower case alphabetic
characters are accepted on input as equivalent to upper case.
Card code PT code RA RN LPT WA ASCII representation
<blank> C 0 0 blank blank
12 XOC 10 0 + +
11 X 20 F+0 - -
0 O 70 0 0 0
1 1 71 1 1 1
2 2 72 2 2 2
3 C21 73 3 3 3
4 4 74 4 4 4
5 C41 75 5 5 5
6 C42 76 6 6 6
7 421 77 7 7 7
8 8 78 8 8 8
9 C81 79 9 9 9
12 + 1 XO1 41 1 A A
12 + 2 XO2 42 2 B B
12 + 3 XOC21 43 3 C C
12 + 4 XO4 44 4 D D
12 + 5 XOC41 45 5 E E
12 + 6 XOC42 46 6 F F
12 + 7 XO421 47 7 G G
12 + 8 XO8 48 8 H H
12 + 9 XOC81 49 9 I I
11 + 1 XC1 51 F+1 J J
11 + 2 XC2 52 F+2 K K
11 + 3 X21 53 F+3 L L
11 + 4 XC4 54 F+4 M M
11 + 5 X41 55 F+5 N N
11 + 6 X42 56 F+6 O O
11 + 7 XC421 57 F+7 P P
11 + 8 XC8 58 F+8 Q Q
11 + 9 X81 59 F+9 R R
0 + 1 OC1 21 1 / /
0 + 2 OC2 62 2 S S
0 + 3 O21 63 3 T T
0 + 4 OC4 64 4 U U
0 + 5 O41 65 5 V V
0 + 6 O42 66 6 W W
0 + 7 OC421 67 7 X X
0 + 8 OC8 68 8 Y Y
0 + 9 O81 69 9 Z Z
2 + 8 C82 ? 0A A na %
3 + 8 821 33 B = =
4 + 8 C84 34 C @ @
5 + 8 841 70 0 0 :
6 + 8 842 ? 0E E na >
7 + 8 C8421 ? 0F F na ^
12 + 2 + 8 XOC82 ? 5A ? F+A na ?
12 + 3 + 8 XO821 3 ? F+B . .
12 + 4 + 8 XOC84 4 C ) )
12 + 5 + 8 XO841 40 0 na [
12 + 6 + 8 XO842 ? 5E ? F+E na <
12 + 7 + 8 XOC8421 5F F+F na "
11 + 2 + 8 X82 5A F+A na !
11 + 3 + 8 XC821 13 F+B $ $
11 + 4 + 8 X84 14 F+C * *
11 + 5 + 8 XC841 50 F+0 - ]
11 + 6 + 8 XC842 ? 5E ? F+E na ;
11 + 7 + 8 X8421 5F F+F na _
0 + 2 + 8 O82 0A A na '
0 + 3 + 8 OC821 23 B , ,
0 + 4 + 8 O84 24 C ( (
0 + 5 + 8 OC841 60 0 na #
0 + 6 + 8 OC842 0E E na \
0 + 7 + 8 O8421 0F F na &
2 ?
12 !
22 '
32 0
35 :
36 blank
11 + 0 50 - ]

463
I1620/i1620_dp.c Normal file
View File

@@ -0,0 +1,463 @@
/* i1620_dp.c: IBM 1311 disk simulator
Copyright (c) 2002, 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.
dp 1311 disk pack
The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track.
Each sector contains 105 characters of information:
5c sector address
100c sector data
By default, a sector's address field will be '00000', which is interpreted
to mean the implied sector number that would be in place if the disk pack
had been formatted with sequential sector numbers.
18-Oct-02 RMS Fixed bug in error testing (found by Hans Pufal)
*/
#include "i1620_defs.h"
#define DP_NUMDR 4 /* #drives */
#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */
#define UNIT_WAE (1 << UNIT_V_WAE)
/* Disk format */
#define DP_ADDR 5 /* address */
#define DP_DATA 100 /* data */
#define DP_NUMCH (DP_ADDR + DP_DATA)
#define DP_NUMSC 20 /* #sectors */
#define DP_NUMSF 10 /* #surfaces */
#define DP_NUMCY 100 /* #cylinders */
#define DP_TOTSC (DP_NUMCY * DP_NUMSF * DP_NUMSC)
#define DP_SIZE (DP_TOTSC * DP_NUMCH)
/* Disk control field */
#define DCF_DRV 0 /* drive select */
#define DCF_SEC 1 /* sector addr */
#define DCF_SEC_LEN 5
#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */
#define DCF_CNT_LEN 3
#define DCF_ADR (DCF_CNT + DCF_CNT_LEN) /* buffer address */
#define DCF_ADR_LEN 5
#define DCF_LEN (DCF_ADR + DCF_ADR_LEN)
/* Functions */
#define FNC_SEEK 1 /* seek */
#define FNC_SEC 0 /* sectors */
#define FNC_WCH 1 /* write check */
#define FNC_NRL 2 /* no rec lnt chk */
#define FNC_TRK 4 /* tracks */
#define FNC_WRI 8 /* write offset */
#define CYL u3 /* current cylinder */
extern uint8 M[MAXMEMSIZE]; /* memory */
extern uint8 ind[NUM_IND];
extern UNIT cpu_unit;
int32 dp_stop = 1; /* disk err stop */
t_addr dp_ba = 0; /* buffer addr */
t_stat dp_reset (DEVICE *dptr);
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr);
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr);
int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd);
t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd);
t_bool dp_zeroad (uint8 *ap);
int32 dp_cvt_ad (uint8 *ap);
int32 dp_trkop (int32 drv, int32 sec);
int32 dp_cvt_bcd (uint32 ad, int32 len);
void dp_fill (UNIT *uptr, uint32 da, int32 cnt);
t_stat dp_tstgm (uint32 c, int32 qnr);
/* DP data structures
dp_dev DP device descriptor
dp_unit DP unit list
dp_reg DP register list
dp_mod DP modifier list
*/
UNIT dp_unit[] = {
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } };
REG dp_reg[] = {
{ FLDATA (ADCHK, ind[IN_DACH], 0) },
{ FLDATA (WLRC, ind[IN_DWLR], 0) },
{ FLDATA (CYLO, ind[IN_DCYO], 0) },
{ FLDATA (ERR, ind[IN_DERR], 0) },
{ FLDATA (DPSTOP, dp_stop, 0) },
{ URDATA (CYL, dp_unit[0].CYL, 10, 8, 0,
DP_NUMDR, PV_LEFT + REG_RO) },
{ NULL } };
MTAB dp_mod[] = {
{ UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL },
{ UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL },
{ 0 } };
DEVICE dp_dev = {
"DP", dp_unit, dp_reg, dp_mod,
DP_NUMDR, 10, 21, 1, 16, 5,
NULL, NULL, &dp_reset,
NULL, NULL, NULL };
/* Disk IO routine */
t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
int32 drv, sa, sec, psec, cnt, qwc, qnr, t;
UNIT *uptr;
t_stat r;
if (pa & 1) return STOP_INVDCF; /* dcf must be even */
ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */
ind[IN_DERR] = ind[IN_DCYO] = 0;
sa = ADDR_A (pa, DCF_SEC); /* ptr to sector */
if (((dp_unit[0].flags & UNIT_DIS) == 0) && /* only drive 0? */
(dp_unit[1].flags & UNIT_DIS) &&
(dp_unit[2].flags & UNIT_DIS) &&
(dp_unit[3].flags & UNIT_DIS)) drv = 0; /* ignore drv select */
else drv = (((M[pa] & 1)? M[pa]: M[sa]) & 0xE) >> 1; /* drive # */
if (drv >= DP_NUMDR) return STOP_INVDRV; /* invalid? */
uptr = dp_dev.units + drv; /* get unit ptr */
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
ind[IN_DERR] = 1; /* no, error */
CRETIOE (dp_stop, SCPE_UNATT); }
sec = dp_cvt_bcd (sa, DCF_SEC_LEN); /* cvt sector */
if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */
return STOP_INVDSC;
if (op == OP_K) { /* seek? */
if (f1 != FNC_SEEK) return STOP_INVFNC; /* really? */
uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */
DP_NUMCY;
return SCPE_OK; } /* done! */
cnt = dp_cvt_bcd (ADDR_A (pa, DCF_CNT), DCF_CNT_LEN); /* get count */
t = dp_cvt_bcd (ADDR_A (pa, DCF_ADR), DCF_ADR_LEN); /* get address */
if ((t < 0) || (t & 1)) return STOP_INVDBA; /* bad address? */
dp_ba = t; /* save addr */
if (f1 >= FNC_WRI) return STOP_INVFNC; /* invalid func? */
if (op == OP_RN) qwc = f1 & FNC_WCH; /* read? set wch */
else if (op == OP_WN) { /* write? */
if (op & FNC_WCH) return STOP_INVFNC; /* cant check */
f1 = f1 + FNC_WRI; } /* offset fnc */
else return STOP_INVFNC; /* not R or W */
qnr = f1 & FNC_NRL; /* no rec check? */
switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */
case FNC_SEC: /* read sectors */
if (cnt <= 0) return STOP_INVDCN; /* bad count? */
psec = dp_fndsec (uptr, sec, TRUE); /* find sector */
if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */
do { /* loop on count */
if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read sector */
break;
sec++; psec++; } /* next sector */
while ((--cnt > 0) &&
((r = dp_nexsec (uptr, sec, psec, TRUE)) == SCPE_OK));
break; /* done, clean up */
case FNC_TRK: /* read track */
psec = dp_trkop (drv, sec); /* start of track */
for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */
if (r = dp_rdadr (uptr, psec, qnr, qwc)) /* read addr */
break; /* error? */
if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read data */
break; /* error? */
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
break; /* done, clean up */
case FNC_SEC + FNC_WRI: /* write */
if (cnt <= 0) return STOP_INVDCN; /* bad count? */
psec = dp_fndsec (uptr, sec, FALSE); /* find sector */
if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */
do { /* loop on count */
if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */
if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */
sec++; psec++; } /* next sector */
while ((--cnt > 0) &&
((r = dp_nexsec (uptr, sec, psec, FALSE)) == SCPE_OK));
break; /* done, clean up */
case FNC_TRK + FNC_WRI: /* write track */
if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */
return STOP_WRADIS;
psec = dp_trkop (drv, sec); /* start of track */
for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */
if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */
if (r = dp_wradr (uptr, psec, qnr)) break; /* write addr */
if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
break; /* done, clean up */
default: /* unknown */
return STOP_INVFNC; }
if ((r == SCPE_OK) && !qnr) { /* eor check? */
if ((M[dp_ba] & DIGIT) != GRP_MARK) { /* GM at end? */
ind[IN_DWLR] = ind[IN_DERR] = 1; /* no, error */
r = STOP_WRLERR; } }
if ((r != SCPE_OK) && /* error? */
(dp_stop || !ind[IN_DERR])) return r; /* iochk or stop? */
return SCPE_OK; /* continue */
}
/* Read or compare address with memory */
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)
{
int32 i;
uint8 ad;
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
t_bool zad = dp_zeroad (ap); /* zero address */
static const int32 dec_tab[DP_ADDR] = /* powers of 10 */
{ 10000, 1000, 100, 10, 1} ;
for (i = 0; i < DP_ADDR; i++) { /* copy/check addr */
if (zad) { /* addr zero? */
ad = sec / dec_tab[i]; /* get addr digit */
sec = sec % dec_tab[i]; } /* get remainder */
else ad = *ap; /* addr digit */
if (qwc) { /* write check? */
if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */
return STOP_WRLERR; /* yes, error */
if (!zad && (M[dp_ba] != ad)) { /* digits equal? */
ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */
return STOP_DWCERR; } }
else M[dp_ba] = ad & (FLAG | DIGIT); /* store digit */
if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */
ap++; PP (dp_ba); } /* adv ptrs */
return SCPE_OK;
}
/* Read or compare data with memory */
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)
{
int32 i;
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */
for (i = 0; i < DP_DATA; i++) { /* copy data */
if (qwc) { /* write check? */
if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */
return STOP_WRLERR; /* yes, error */
if (M[dp_ba] != *ap) { /* dig+flags equal? */
ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */
return STOP_DWCERR; } }
else M[dp_ba] = *ap & (FLAG | DIGIT); /* flag + digit */
if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */
ap++; PP (dp_ba); } /* adv ptrs */
return SCPE_OK;
}
/* Write address to disk */
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr)
{
int32 i;
uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
for (i = 0; i < DP_ADDR; i++) { /* copy address */
*ap = M[dp_ba] & (FLAG | DIGIT); /* flag + digit */
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */
dp_fill (uptr, da + 1, DP_NUMCH - i - 1); /* fill addr+data */
return STOP_WRLERR; } /* error */
da++; ap++; PP (dp_ba); /* adv ptrs */
}
return SCPE_OK;
}
/* Write data to disk */
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr)
{
int32 i;
uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
for (i = 0; i < DP_DATA; i++) { /* copy data */
*ap = M[dp_ba] & (FLAG | DIGIT); /* get character */
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */
dp_fill (uptr, da + 1, DP_DATA - i - 1); /* fill data */
return STOP_WRLERR; } /* error */
da++; ap++; PP (dp_ba); /* adv ptrs */
}
return SCPE_OK;
}
/* Find sector */
int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd)
{
int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk;
int32 da = psec * DP_NUMCH; /* char number */
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
int32 dskad, i;
if (dp_zeroad (ap)) return psec; /* addr zero? ok */
dskad = dp_cvt_ad (ap); /* cvt addr */
if (dskad == sec) { /* match? */
if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */
ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */
return -1; }
psec = psec - (psec % DP_NUMSC); /* sector 0 */
for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */
da = psec * DP_NUMCH; /* char number */
ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */
if (dp_zeroad (ap)) continue; /* no implicit match */
dskad = dp_cvt_ad (ap); /* cvt addr */
if (dskad == sec) { /* match? */
if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */
ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */
return -1; } }
ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */
return -1;
}
/* Find next sector - must be sequential, cannot cross cylinder boundary */
t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd)
{
int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
int32 da = psec * DP_NUMCH; /* word number */
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
int32 dskad;
if (ctrk) { /* not trk zero? */
if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */
dskad = dp_cvt_ad (ap); /* cvt addr */
if ((dskad == sec) && /* match? */
(rd || ((*ap & FLAG) == 0))) return SCPE_OK; /* read or !wprot? */
ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */
return STOP_DACERR; }
ind[IN_DCYO] = ind[IN_DERR] = 1; /* cyl overflow */
return STOP_CYOERR;
}
/* Test for zero address */
t_bool dp_zeroad (uint8 *ap)
{
int32 i;
for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
if (*ap & DIGIT) return FALSE; } /* nonzero? lose */
return TRUE; /* all zeroes */
}
/* Test for group mark when enabled */
t_stat dp_tstgm (uint32 c, int32 qnr)
{
if (!qnr && ((c & DIGIT) == GRP_MARK)) { /* premature GM? */
ind[IN_DWLR] = ind[IN_DERR] = 1; /* error */
return STOP_WRLERR; }
return SCPE_OK;
}
/* Convert disk address to binary - invalid char force bad address */
int32 dp_cvt_ad (uint8 *ap)
{
int32 i, r;
uint8 c;
for (i = r = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
c = *ap & DIGIT; /* get digit */
if (BAD_DIGIT (c)) return -1; /* bad digit? */
r = (r * 10) + c; } /* bcd to binary */
return r;
}
/* Track operation setup */
int32 dp_trkop (int32 drv, int32 sec)
{
int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF;
return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) +
(ctrk * DP_NUMSC));
}
/* Convert DCF BCD field to binary */
int32 dp_cvt_bcd (uint32 ad, int32 len)
{
uint8 c;
int32 r;
for (r = 0; len > 0; len--) { /* loop thru char */
c = M[ad] & DIGIT; /* get digit */
if (BAD_DIGIT (c)) return -1; /* invalid? */
r = (r * 10) + c; /* cvt to bin */
PP (ad); } /* next digit */
return r;
}
/* Fill sector buffer with zero */
void dp_fill (UNIT *uptr, uint32 da, int32 cnt)
{
while (cnt-- > 0) { /* fill with zeroes*/
*(((uint8 *) uptr->filebuf) + da) = 0;
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
da++; }
return;
}
/* Reset routine */
t_stat dp_reset (DEVICE *dptr)
{
int32 i;
for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */
ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */
ind[IN_DERR] = ind[IN_DCYO] = 0;
return SCPE_OK;
}

388
I1620/i1620_fp.c Normal file
View File

@@ -0,0 +1,388 @@
/* i1620_fp.c: IBM 1620 floating point simulator
Copyright (c) 2002, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
The IBM 1620 uses a variable length floating point format, with a fixed
two digit decimal exponent and a variable length decimal mantissa:
_ S_S
M.......MEE
where S represents flag bits if the mantissa or exponent are negative.
*/
#include "i1620_defs.h"
#define FP_LMAX 100 /* max fp mant lnt */
#define FP_EMAX 99 /* max fp exponent */
/* Unpacked floating point operand */
struct fp_opnd {
int32 sign; /* 0 => +, 1 => - */
int32 exp; /* binary exponent */
uint32 lnt; /* mantissa length */
uint32 addr; /* mantissa addr */
uint32 zero; /* 0 => nz, 1 => zero */
};
typedef struct fp_opnd FPA;
extern uint8 M[MAXMEMSIZE]; /* main memory */
extern uint8 ind[NUM_IND]; /* indicators */
extern UNIT cpu_unit;
t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro);
t_stat fp_zero (FPA *fp);
extern t_stat xmt_field (uint32 d, uint32 s, uint32 skp);
extern t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, int32 *sta);
extern t_stat mul_field (uint32 d, uint32 s);
extern t_stat xmt_divd (uint32 d, uint32 s);
extern t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez);
/* Unpack and validate a floating point argument */
t_stat fp_unpack (uint32 ad, FPA *fp)
{
uint8 d0, d1, esign;
esign = M[ad] & FLAG; /* get exp sign */
d0 = M[ad] & DIGIT; /* get exp lo digit */
MM (ad);
if ((M[ad] & FLAG) == 0) return STOP_FPMF; /* no flag on hi exp? */
d1 = M[ad] & DIGIT; /* get exp hi digit */
MM (ad);
fp->addr = ad; /* save mant addr */
if (BAD_DIGIT (d1) || BAD_DIGIT (d0)) return STOP_INVDIG; /* exp bad dig? */
fp->exp = ((d1 * 10) + d0) * (esign? -1: 1); /* convert exponent */
fp->sign = (M[ad] & FLAG)? 1: 0; /* get mantissa sign */
return fp_scan_mant (fp->addr, &(fp->lnt), &(fp->zero));
}
/* Unpack and validate source and destination arguments */
t_stat fp_unpack_two (uint32 dad, uint32 sad, FPA *dfp, FPA *sfp)
{
t_stat r;
if ((r = fp_unpack (dad, dfp)) != SCPE_OK) return r; /* unpack dst */
if ((r = fp_unpack (sad, sfp)) != SCPE_OK) return r; /* unpack src */
if (sfp->lnt != dfp->lnt) return STOP_FPUNL; /* lnts must be equal */
return SCPE_OK;
}
/* Pack floating point result */
t_stat fp_pack (FPA *fp)
{
int32 e;
uint32 i, mad;
e = (fp->exp >= 0)? fp->exp: -fp->exp; /* get |exp| */
if (e > FP_EMAX) { /* too big? */
ind[IN_EXPCHK] = 1; /* set indicator */
if (fp->exp < 0) return fp_zero (fp); /* underflow? */
mad = fp->addr;
for (i = 0; i < fp->lnt; i++) { /* mant = 99...99 */
M[mad] = (M[mad] & FLAG) | 9;
MM (mad); }
e = FP_EMAX; } /* cap at max */
M[ADDR_A (fp->addr, 1)] = (e / 10) | FLAG; /* high exp digit */
M[ADDR_A (fp->addr, 2)] = (e % 10) | /* low exp digit */
((fp->exp < 0)? FLAG: 0);
return SCPE_OK;
}
/* Shift mantissa right n positions */
void fp_rsh (FPA *fp, uint32 n)
{
uint32 i, sad, dad;
if (n == 0) return; /* zero? done */
sad = ADDR_S (fp->addr, n); /* src = addr - n */
dad = fp->addr; /* dst = n */
for (i = 0; i < fp->lnt; i++) { /* move digits */
if (i >= (fp->lnt - n)) M[dad] = M[dad] & FLAG;
else M[dad] = (M[dad] & FLAG) | (M[sad] & DIGIT);
MM (dad);
MM (sad); }
return;
}
/* Shift mantissa left 1 position */
void fp_lsh_1 (FPA *fp)
{
uint32 i, mad, nxt;
mad = ADDR_S (fp->addr, fp->lnt - 1); /* hi order digit */
for (i = 0; i < (fp->lnt - 1); i++) { /* move lnt-1 digits */
nxt = ADDR_A (mad, 1);
M[mad] = (M[mad] & FLAG) | (M[nxt] & DIGIT);
mad = nxt; }
M[mad] = M[mad] & FLAG; /* clear last digit */
return;
}
/* Clear floating point number */
t_stat fp_zero (FPA *fp)
{
uint32 i, mad = fp->addr;
for (i = 0; i < fp->lnt; i++) { /* clear mantissa */
M[mad] = (i? M[mad] & FLAG: 0); /* clear sign bit */
MM (mad); }
M[ADDR_A (fp->addr, 1)] = FLAG + 9; /* exp = -99 */
M[ADDR_A (fp->addr, 2)] = FLAG + 9; /* exp = -99 */
ind[IN_EZ] = 1; /* result = 0 */
ind[IN_HP] = 0;
return SCPE_OK;
}
/* Scan floating point mantissa for length and (optionally) zero */
t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro)
{
uint8 d, l, z;
z = 1; /* assume zero */
for (l = 1; l <= FP_LMAX; l++) { /* scan to get length */
d = M[ad] & DIGIT; /* get mant digit */
if (d) z = 0; /* non-zero? */
if ((l != 1) && (M[ad] & FLAG)) { /* flag past first dig? */
*lnt = l; /* set returns */
if (zro) *zro = z;
return SCPE_OK; }
MM (ad); }
return STOP_FPLNT; /* too long */
}
/* Copy floating point mantissa */
void fp_copy_mant (uint32 d, uint32 s, uint32 l)
{
uint32 i;
if (ind[IN_HP]) M[d] = M[d] & ~FLAG; /* clr/set sign */
else M[d] = M[d] | FLAG;
for (i = 0; i < l; i++) { /* copy src */
M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* preserve flags */
MM (d);
MM (s); }
return;
}
/* Compare floating point mantissa */
int32 fp_comp_mant (uint32 d, uint32 s, uint32 l)
{
uint8 i, dd, sd;
d = ADDR_S (d, l - 1); /* start of mantissa */
s = ADDR_S (s, l - 1);
for (i = 0; i < l; i++) { /* compare dst:src */
dd = M[d] & DIGIT; /* get dst digit */
sd = M[s] & DIGIT; /* get src digit */
if (dd > sd) return 1; /* >? done */
if (dd < sd) return -1; /* <? done */
PP (d); /* =? continue */
PP (s); }
return 0; /* done, equal */
}
/* Floating point add */
t_stat fp_add (uint32 d, uint32 s, t_bool sub)
{
FPA sfp, dfp;
uint32 i, sad, hi;
int32 dif, sta;
uint8 sav_src[FP_LMAX];
t_stat r;
r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */
if (r != SCPE_OK) return r; /* error? */
dif = dfp.exp - sfp.exp; /* exp difference */
if (sfp.zero || (dif >= ((int32) dfp.lnt))) { /* src = 0, or too small? */
if (dfp.zero) return fp_zero (&dfp); /* res = dst, zero? */
ind[IN_EZ] = 0; /* res nz, set EZ, HP */
ind[IN_HP] = (dfp.sign == 0);
return SCPE_OK; }
if (dfp.zero || (dif <= -((int32) dfp.lnt))) { /* dst = 0, or too small? */
if (sfp.zero) return fp_zero (&dfp); /* res = src, zero? */
r = xmt_field (d, s, 3); /* copy src to dst */
ind[IN_EZ] = 0; /* res nz, set EZ, HP */
ind[IN_HP] = (dfp.sign == 0);
return r; }
if (dif > 0) { /* dst exp > src exp? */
sad = sfp.addr; /* save src in save area */
for (i = 0; i < sfp.lnt; i++) {
sav_src[i] = M[sad];
MM (sad); }
fp_rsh (&sfp, dif); } /* denormalize src */
else if (dif < 0) { /* dst exp < src exp? */
dfp.exp = sfp.exp; /* res exp = src exp */
fp_rsh (&dfp, -dif); } /* denormalize dst */
r = add_field (dfp.addr, sfp.addr, sub, TRUE, &sta); /* add mant, set EZ, HP */
if (dif > 0) { /* src denormalized? */
sad = sfp.addr; /* restore src from */
for (i = 0; i < sfp.lnt; i++) { /* save area */
M[sad] = sav_src[i];
MM (sad); } }
if (r != SCPE_OK) return r; /* add error? */
hi = ADDR_S (dfp.addr, dfp.lnt - 1); /* addr of hi digit */
if (sta == ADD_CARRY) { /* carry out? */
fp_rsh (&dfp, 1); /* shift mantissa */
M[hi] = FLAG + 1; /* high order 1 */
dfp.exp = dfp.exp + 1;
ind[IN_EZ] = 0; /* not zero */
ind[IN_HP] = (dfp.sign == 0); } /* set HP */
else if (ind[IN_EZ]) return fp_zero (&dfp); /* result zero? */
else { while ((M[hi] & DIGIT) == 0) { /* until normalized */
fp_lsh_1 (&dfp); /* left shift */
dfp.exp = dfp.exp - 1; } } /* decr exponent */
return fp_pack (&dfp); /* pack and exit */
}
/* Floating point multiply */
t_stat fp_mul (uint32 d, uint32 s)
{
FPA sfp, dfp;
uint32 pad;
t_stat r;
r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */
if (r != SCPE_OK) return r; /* error? */
if (sfp.zero || dfp.zero) return fp_zero (&dfp); /* either zero? */
r = mul_field (dfp.addr, sfp.addr); /* mul, set EZ, HP */
if (r != SCPE_OK) return r;
if (M[ADDR_S (PROD_AREA_END, 2 * dfp.lnt)] & DIGIT) { /* hi prod dig set? */
pad = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* no normalization */
dfp.exp = dfp.exp + sfp.exp; } /* res exp = sum */
else { pad = ADDR_S (PROD_AREA_END, dfp.lnt); /* 'normalize' 1 */
dfp.exp = dfp.exp + sfp.exp - 1; } /* res exp = sum - 1 */
fp_copy_mant (dfp.addr, pad, dfp.lnt); /* copy prod to mant */
return fp_pack (&dfp); /* pack and exit */
}
/* Floating point divide */
t_stat fp_div (uint32 d, uint32 s)
{
FPA sfp, dfp;
uint32 i, pad, a100ml, a99ml;
int32 ez;
t_stat r;
r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */
if (r != SCPE_OK) return r; /* error? */
if (sfp.zero) { /* divide by zero? */
ind[IN_OVF] = 1; /* dead jim */
return SCPE_OK; }
if (dfp.zero) return fp_zero (&dfp); /* divide into zero? */
for (i = 0; i < PROD_AREA_LEN; i++) /* clear prod area */
M[PROD_AREA + i] = 0;
a100ml = ADDR_S (PROD_AREA_END, dfp.lnt); /* 100 - lnt */
a99ml = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* 99 - lnt */
if (fp_comp_mant (dfp.addr, sfp.addr, dfp.lnt) >= 0) { /* |Mdst| >= |Msrc|? */
pad = a100ml;
dfp.exp = dfp.exp - sfp.exp + 1; } /* res exp = diff + 1 */
else { pad = a99ml;
dfp.exp = dfp.exp - sfp.exp; } /* res exp = diff */
r = xmt_divd (pad, dfp.addr); /* xmt dividend */
if (r != SCPE_OK) return r; /* error? */
r = div_field (a100ml, sfp.addr, &ez); /* divide fractions */
if (r != SCPE_OK) return r; /* error? */
if (ez) return fp_zero (&dfp); /* result zero? */
ind[IN_HP] = ((dfp.sign ^ sfp.sign) == 0); /* set res sign */
ind[IN_EZ] = 0; /* not zero */
fp_copy_mant (dfp.addr, a99ml, dfp.lnt); /* copy result */
return fp_pack (&dfp);
}
/* Floating shift right */
t_stat fp_fsr (uint32 d, uint32 s)
{
uint32 cnt;
uint8 t;
if (d == s) return SCPE_OK; /* no move? */
cnt = 0;
M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* move 1st wo flag */
do { MM (d); /* decr ptrs */
MM (s);
t = M[d] = M[s] & (FLAG | DIGIT); /* copy others */
if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */
while ((t & FLAG) == 0); /* until src flag */
cnt = 0;
do { MM (d); /* decr pointer */
t = M[d]; /* save old val */
M[d] = 0; /* zero field */
if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */
while ((t & FLAG) == 0); /* until dst flag */
return SCPE_OK;
}
/* Floating shift left - note that dst is addr of high order digit */
t_stat fp_fsl (uint32 d, uint32 s)
{
uint32 i, lnt;
uint8 sign;
t_stat r;
if (d == s) return SCPE_OK;
sign = M[s] & FLAG; /* get src sign */
r = fp_scan_mant (s, &lnt, NULL); /* get src length */
if (r != SCPE_OK) return r; /* error? */
s = ADDR_S (s, lnt - 1); /* hi order src */
M[d] = M[s] & (FLAG | DIGIT); /* move 1st w flag */
M[s] = M[s] & ~FLAG; /* clr flag from src */
for (i = 1; i < lnt; i++) { /* move src to dst */
PP (d); /* incr ptrs */
PP (s);
M[d] = M[s] & DIGIT; } /* move just digit */
PP (d); /* incr pointer */
while ((M[d] & FLAG) == 0) { /* until flag */
M[d] = 0; /* clear field */
PP (d); }
if (sign) M[d] = FLAG; /* -? zero under sign */
return SCPE_OK;
}

314
I1620/i1620_lp.c Normal file
View File

@@ -0,0 +1,314 @@
/* i1620_lp.c: IBM 1443 line printer simulator
Copyright (c) 2002, 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 1443 line printer
*/
#include "i1620_defs.h"
#define LPT_BSIZE 197 /* buffer size */
#define K_IMM 0x10 /* control now */
#define K_LIN 0x20 /* spc lines */
#define K_CH10 0x40 /* chan 10 */
#define K_LCNT 0x03 /* line count */
#define K_CHAN 0x0F /* channel */
extern uint8 M[MAXMEMSIZE];
extern uint8 ind[NUM_IND];
extern UNIT cpu_unit;
extern uint32 io_stop;
uint32 cct[CCT_LNT] = { 03 }; /* car ctrl tape */
int32 cct_lnt = 66, cct_ptr = 0; /* cct len, ptr */
int32 lpt_bptr = 0; /* lpt buf ptr */
char lpt_buf[LPT_BSIZE + 1]; /* lpt buf */
int32 lpt_savctrl = 0; /* saved spc ctrl */
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
void lpt_buf_init (void);
t_stat lpt_num (uint32 pa, uint32 len, uint32 f1);
t_stat lpt_print (void);
t_stat lpt_space (int32 lines, int32 lflag);
#define CHP(ch,val) ((val) & (1 << (ch)))
/* LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit descriptor
lpt_reg LPT register list
*/
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 50) };
REG lpt_reg[] = {
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE + 1) },
{ DRDATA (BPTR, lpt_bptr, 8) },
{ HRDATA (PCTL, lpt_savctrl, 8) },
{ FLDATA (PRCHK, ind[IN_PRCHK], 0) },
{ FLDATA (PRCH9, ind[IN_PRCH9], 0) },
{ FLDATA (PRCH12, ind[IN_PRCH12], 0) },
{ FLDATA (PRBSY, ind[IN_PRBSY], 0) },
{ DRDATA (POS, lpt_unit.pos, 32), PV_LEFT },
{ BRDATA (CCT, cct, 8, 32, CCT_LNT) },
{ DRDATA (CCTP, cct_ptr, 8), PV_LEFT },
{ DRDATA (CCTL, cct_lnt, 8), REG_RO + PV_LEFT },
{ NULL } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, NULL };
/* Data tables */
/* Numeric (flag plus digit) to lineprinter (ASCII) */
const char num_to_lpt[32] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '\'', ' ', '@', ':', ' ', 'G',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'W', ' ', '*', ' ', -1, 'X' };
/* Alphameric (digit pair) to lineprinter (ASCII) */
const char alp_to_lpt[256] = {
' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */
-1, -1, -1, -1, -1, -1, -1, -1,
'+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1,
'-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, '0', '=', '@', ':', -1, -1, /* 30 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
'H', 'I', -1, -1, -1, -1, -1, -1,
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
'Q', 'R', -1, -1, -1, -1, -1, -1,
-1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
'Y', 'Z', -1, -1, -1, -1, -1, -1,
'0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
'8', '9', -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
-1, -1, -1, -1, -1, -1, -1, -1 };
/* Line printer IO routine
- Hard errors halt the system.
- Invalid characters print a blank, set the WRCHK and PRCHK
flags, and halt the system if IO stop is set.
*/
t_stat lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
int8 lpc;
uint8 z, d;
t_stat r, inv = SCPE_OK;
sim_cancel (&lpt_unit); /* "stall" until */
ind[IN_PRBSY] = 0; /* printer free */
switch (op) { /* decode op */
case OP_K: /* control */
lpt_savctrl = (f0 << 4) | f1; /* form ctrl */
if (lpt_savctrl & K_IMM) return lpt_print (); /* immediate? */
break;
case OP_DN:
return lpt_num (pa, 20000 - (pa % 20000), f1); /* dump numeric */
case OP_WN:
return lpt_num (pa, 0, f1); /* write numeric */
case OP_WA:
for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) break; /* 8-2 char? */
lpc = alp_to_lpt[(z << 4) | d]; /* translate pair */
if (lpc < 0) { /* bad char? */
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
inv = STOP_INVCHR; } /* set return status */
lpt_buf[lpt_bptr] = lpc & 0x7F; /* fill buffer */
pa = ADDR_A (pa, 2); } /* incr mem addr */
if ((f1 & 1) == 0) { ; /* print now? */
r = lpt_print (); /* print line */
if (r != SCPE_OK) return r; }
CRETIOE (io_stop, inv);
default: /* invalid function */
return STOP_INVFNC; }
return SCPE_OK;
}
/* Print numeric */
t_stat lpt_num (uint32 pa, uint32 len, uint32 f1)
{
uint32 end;
uint8 d;
int8 lpc;
t_stat r, inv = SCPE_OK;
end = pa + len;
for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */
d = M[pa]; /* get digit */
if (len? (pa >= end): /* end reached? */
((d & REC_MARK) == REC_MARK)) break;
lpc = num_to_lpt[d]; /* translate */
if (lpc < 0) { /* bad char? */
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
inv = STOP_INVCHR; } /* set return status */
lpt_buf[lpt_bptr++] = lpc & 0x7F; /* fill buffer */
PP (pa); } /* incr mem addr */
if ((f1 & 1) == 0) { /* print now? */
r = lpt_print (); /* print line */
if (r != SCPE_OK) return r; }
CRETIOE (io_stop, inv);
}
/* Print and space */
t_stat lpt_print (void)
{
int32 i, chan, ctrl = lpt_savctrl;
if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
return SCPE_UNATT; }
ind[IN_PRBSY] = 1; /* print busy */
sim_activate (&lpt_unit, lpt_unit.time); /* start timer */
for (i = LPT_WIDTH; i <= LPT_BSIZE; i++) /* clear unprintable */
lpt_buf[i] = ' ';
while ((lpt_bptr > 0) && (lpt_buf[lpt_bptr - 1] == ' '))
lpt_buf[--lpt_bptr] = 0; /* trim buffer */
if (lpt_bptr) { /* any line? */
fputs (lpt_buf, lpt_unit.fileref); /* print */
lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */
lpt_buf_init (); /* reinit buf */
if (ferror (lpt_unit.fileref)) { /* error? */
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; } }
lpt_savctrl = 0x61; /* reset ctrl */
if ((ctrl & K_LIN) == ((ctrl & K_IMM)? 0: K_LIN)) /* space lines? */
return lpt_space (ctrl & K_LCNT, FALSE);
chan = lpt_savctrl & K_CHAN; /* basic chan */
if (lpt_savctrl & K_CH10) { /* chan 10-12? */
if (chan == 0) chan = 10;
else if (chan == 3) chan = 11;
else if (chan == 4) chan = 12;
else chan = 0; }
if ((chan == 0) || (chan > 12)) return STOP_INVFNC;
for (i = 1; i < cct_lnt + 1; i++) { /* sweep thru cct */
if (CHP (chan, cct[(cct_ptr + i) % cct_lnt]))
return lpt_space (i, TRUE); }
return STOP_CCT; /* runaway channel */
}
/* Space routine - space or skip n lines
Inputs:
count = number of lines to space or skip
sflag = skip (TRUE) or space (FALSE)
*/
t_stat lpt_space (int32 count, int32 sflag)
{
int32 i;
cct_ptr = (cct_ptr + count) % cct_lnt; /* adv cct, mod lnt */
if (sflag && CHP (0, cct[cct_ptr])) /* skip, top of form? */
fputs ("\n\f", lpt_unit.fileref); /* nl, ff */
else { for (i = 0; i < count; i++) /* count lines */
fputc ('\n', lpt_unit.fileref); }
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
ind[IN_PRCH9] = CHP (9, cct[cct_ptr]) != 0; /* set indicators */
ind[IN_PRCH12] = CHP (12, cct[cct_ptr]) != 0;
if (ferror (lpt_unit.fileref)) { /* error? */
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
return SCPE_OK;
}
/* Unit service - clear printer busy */
t_stat lpt_svc (UNIT *uptr)
{
ind[IN_PRBSY] = 0;
return SCPE_OK;
}
/* Initialize lpt buffer */
void lpt_buf_init (void)
{
int32 i;
lpt_bptr = 0;
for (i = 0; i < LPT_WIDTH + 1; i++) lpt_buf[i] = 0;
return;
}
/* Reset routine */
t_stat lpt_reset (DEVICE *dptr)
{
lpt_buf_init (); /* clear buffer */
cct_ptr = 0; /* clear cct ptr */
lpt_savctrl = 0x61; /* clear cct action */
ind[IN_PRCHK] = ind[IN_PRBSY] = 0; /* clear indicators */
ind[IN_PRCH9] = ind[IN_PRCH12] = 0;
return SCPE_OK;
}
/* Attach routine */
t_stat lpt_attach (UNIT *uptr, char *cptr)
{
lpt_reset (&lpt_dev);
return attach_unit (uptr, cptr);
}

434
I1620/i1620_pt.c Normal file
View File

@@ -0,0 +1,434 @@
/* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator
Copyright (c) 2002, 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.
ptr 1621 paper tape reader
ptp 1624 paper tape punch
*/
#include "i1620_defs.h"
#define PT_EL 0x80 /* end record */
#define PT_X 0x40 /* X */
#define PT_O 0x20 /* O */
#define PT_C 0x10 /* C */
#define PT_FD 0x7F /* deleted */
extern uint8 M[MAXMEMSIZE];
extern uint8 ind[NUM_IND];
extern UNIT cpu_unit;
extern uint32 io_stop;
t_stat ptr_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
t_stat ptr_read (uint8 *c, t_bool ignfeed);
t_stat ptp_reset (DEVICE *dptr);
t_stat ptp_write (uint32 c);
t_stat ptp_num (uint32 pa, uint32 len);
/* PTR data structures
ptr_dev PTR device descriptor
ptr_unit PTR unit descriptor
ptr_reg PTR register list
*/
UNIT ptr_unit = {
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) };
REG ptr_reg[] = {
{ DRDATA (POS, ptr_unit.pos, 32), PV_LEFT },
{ NULL } };
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
&ptr_boot, NULL, NULL };
/* PTP data structures
ptp_dev PTP device descriptor
ptp_unit PTP unit descriptor
ptp_reg PTP register list
*/
UNIT ptp_unit = {
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
REG ptp_reg[] = {
{ DRDATA (POS, ptp_unit.pos, 32), PV_LEFT },
{ NULL } };
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL };
/* Data tables */
/* Paper tape reader odd parity chart: 1 = bad, 0 = ok */
const int8 bad_par[128] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 00 */
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 10 */
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 20 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 30 */
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 40 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 50 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 60 */
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; /* 70 */
/* Paper tape read (7b) to numeric (one digit) */
const int8 ptr_to_num[128] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* - */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* C */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* O */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* OC */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* X */
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* XC */
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XO */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XOC */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F };
/* Paper tape read (7b) to alphameric (two digits)
Codes XO82, 82, XO842, 842 do not have consistent translations
*/
const int8 ptr_to_alp[128] = {
0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* - */
0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* C */
0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */
0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */
0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* X */
0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* XC */
0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XO */
0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F,
0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XOC */
0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F };
/* Numeric (flag + digit) to paper tape punch */
const int8 num_to_ptp[32] = {
0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 0 */
0x08, 0x19, 0x2A, 0x3B, 0x1C, 0x0D, 0x3E, 0x3F,
0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* F + 0 */
0x58, 0x49, 0x4A, 0x5B, 0x4C, 0x5D, 0x5E, 0x4F };
/* Alphameric (two digits) to paper tape punch */
const int8 alp_to_ptp[256] = {
0x10, -1, 0x7A, 0x6B, 0x7C, -1, -1, 0x7F, /* 00 */
-1, -1, 0x2A, -1, -1, -1, -1, 0x1F,
0x70, -1, 0x4A, 0x5B, 0x4C, -1, -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1,
0x40, 0x31, 0x2A, 0x3B, 0x2C, -1, -1, -1, /* 20 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 0x1A, 0x0B, 0x1C, 0x0D, 0x0E, -1, /* 30 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, 0x61, 0x62, 0x73, 0x64, 0x75, 0x76, 0x67, /* 40 */
0x68, 0x79, -1, -1, -1, -1, -1, -1,
0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* 50 */
0x58, 0x49, 0x4A, -1, -1, -1, -1, 0x4F,
-1, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */
0x38, 0x29, -1, -1, -1, -1, -1, -1,
0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 70 */
0x08, 0x19, 0x7A, -1, -1, -1, -1, 0x7F,
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
-1, -1, -1, -1, -1, -1, -1, -1 };
/* Paper tape reader IO routine
- Hard errors halt the operation and the system.
- Parity errors place an invalid character in memory and set
RDCHK, but the read continues until end of record. If IO
stop is set, the system then halts.
*/
t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
t_addr i;
int8 mc;
uint8 ptc;
t_stat r, inv = SCPE_OK;
switch (op) { /* case on op */
case OP_RN: /* read numeric */
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
CRETIOE (io_stop, inv); } /* done */
if (bad_par[ptc]) { /* bad parity? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
M[pa] = 0; } /* store zero */
else M[pa] = ptr_to_num[ptc]; /* translate, store */
PP (pa); } /* incr mem addr */
break;
case OP_RA: /* read alphameric */
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
M[pa - 1] = 0;
CRETIOE (io_stop, inv); } /* done */
mc = ptr_to_alp[ptc]; /* translate */
if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; /* set return status */
mc = 0; } /* store blank */
M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
return STOP_RWRAP;
}
/* Binary paper tape reader IO routine - see above for error handling */
t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
t_addr i;
uint8 ptc;
t_stat r, inv = SCPE_OK;
if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
switch (op) { /* case on op */
case OP_RA: /* read alphameric */
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = ptr_read (&ptc, FALSE); /* read frame */
if (r != SCPE_OK) return r; /* error? */
if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */
M[pa - 1] = 0;
CRETIOE (io_stop, inv); } /* done */
if (bad_par[ptc]) { /* bad parity? */
ind[IN_RDCHK] = 1; /* set read check */
inv = STOP_INVCHR; } /* set return status */
M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) |
(((ptc >> 5) & 06) | ((ptc >> 3) & 1));
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
return STOP_RWRAP;
}
/* Read ptr frame - all errors are 'hard' errors and halt the system */
t_stat ptr_read (uint8 *c, t_bool ignfeed)
{
int32 temp;
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
ind[IN_RDCHK] = 1; /* no, error */
return SCPE_UNATT; }
do { if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */
ind[IN_RDCHK] = 1; /* err, rd chk */
if (feof (ptr_unit.fileref))
printf ("PTR end of file\n");
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
*c = temp & 0377; /* save char */
ptr_unit.pos = ptr_unit.pos + 1; } /* incr file addr */
while (ignfeed && (*c == PT_FD)); /* until not feed */
return SCPE_OK;
}
/* Reset routine */
t_stat ptr_reset (DEVICE *dptr)
{
return SCPE_OK;
}
/* Bootstrap routine */
const static uint8 boot_rom[] = {
4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NOP */
3, 6, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, /* RNPT 31 */
2, 5, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, /* TD 71,loc */
3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT loc1 */
2, 6, 0, 0, 0, 6, 6, 0, 0, 0, 3, 5, /* TF 66,35 */
1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* TDM loc2,loc3 */
4, 9, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0 }; /* BR 12 */
#define BOOT_START 0
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
int32 i;
extern int32 saved_PC;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;
return SCPE_OK;
}
/* Paper tape punch IO routine
- Hard errors halt the operation and the system.
- Parity errors stop the operation and set WRCHK.
If IO stop is set, the system then halts.
*/
t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
t_addr i;
int8 ptc;
uint8 z, d;
t_stat r;
switch (op) { /* decode op */
case OP_DN:
return ptp_num (pa, 20000 - (pa % 20000)); /* dump numeric */
case OP_WN:
return ptp_num (pa, 0); /* punch numeric */
case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */
ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */
if (ptc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* write check */
CRETIOE (io_stop, STOP_INVCHR); }
r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) return r; /* error? */
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
return STOP_RWRAP;
}
/* Binary paper tape punch IO routine - see above for error handling */
t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
t_addr i;
uint8 ptc, z, d;
t_stat r;
if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
switch (op) { /* decode op */
case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */
ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07);
if (bad_par[ptc]) ptc = ptc | PT_C; /* set parity */
r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) return r; /* error? */
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
return STOP_RWRAP;
}
/* Punch tape numeric - cannot generate parity errors */
t_stat ptp_num (uint32 pa, uint32 len)
{
t_stat r;
uint8 d;
uint32 i, end;
end = pa + len;
for (i = 0; i < MEMSIZE; i++) { /* stop runaway */
d = M[pa] & (FLAG | DIGIT); /* get char */
if (len? (pa >= end): /* dump: end reached? */
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
return ptp_write (PT_EL); /* end record */
r = ptp_write (num_to_ptp[d]); /* write */
if (r != SCPE_OK) return r; /* error? */
PP (pa); } /* incr mem addr */
return STOP_RWRAP;
}
/* Write ptp frame - all errors are hard errors */
t_stat ptp_write (uint32 c)
{
if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
ind[IN_WRCHK] = 1; /* no, error */
return SCPE_UNATT; }
if (putc (c, ptp_unit.fileref) == EOF) { /* write char */
ind[IN_WRCHK] = 1; /* error? */
perror ("PTP I/O error");
clearerr (ptp_unit.fileref);
return SCPE_IOERR; }
ptp_unit.pos = ptp_unit.pos + 1; /* count char */
return SCPE_OK;
}
/* Reset routine */
t_stat ptp_reset (DEVICE *dptr)
{
return SCPE_OK;
}

491
I1620/i1620_sys.c Normal file
View File

@@ -0,0 +1,491 @@
/* i1620_sys.c: IBM 1620 simulator interface
Copyright (c) 2002, 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 "i1620_defs.h"
#include <ctype.h>
#define LINE_LNT 50
extern DEVICE cpu_dev, tty_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE lpt_dev;
extern DEVICE cdr_dev, cdp_dev;
extern DEVICE dp_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern uint8 M[MAXMEMSIZE];
extern char cdr_to_alp[128], alp_to_cdp[256];
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax maximum number of words for examine/deposit
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 1620";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = LINE_LNT;
DEVICE *sim_devices[] = {
&cpu_dev,
&tty_dev,
&ptr_dev,
&ptp_dev,
&cdr_dev,
&cdp_dev,
&lpt_dev,
&dp_dev,
NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Breakpoint",
"Invalid instruction",
"Invalid digit",
"Invalid character",
"Invalid indicator",
"Invalid digit in P address",
"Invalid P address",
"P address exceeds indirect address limit",
"Invalid digit in Q address",
"Invalid Q address",
"Q address exceeds indirect address limit",
"Invalid IO device",
"Invalid return register",
"Invalid IO function",
"Instruction address must be even",
"Invalid select code",
"Index instruction with no band selected",
"P address must be odd",
"DCF address must be even",
"Invalid disk drive",
"Invalid disk sector address",
"Invalid disk sector count",
"Invalid disk buffer address",
"Disk address compare error",
"Disk write check error",
"Disk cylinder overflow error",
"Disk wrong length record error",
"Invalid CCT",
"Field exceeds memory",
"Record exceeds memory",
"No card in reader",
"Overflow check",
"Exponent check",
"Write address function disabled",
"Floating point mantissa too long",
"Floating point mantissa lengths unequal",
"Floating point exponent flag missing",
"Floating point divide by zero" };
/* Binary loader -- load carriage control tape
A carriage control tape consists of entries of the form
(repeat count) column number,column number,column number,...
The CCT entries are stored in cct[0:lnt-1], cctlnt contains the
number of entries
*/
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];
t_stat r;
extern int32 cct_lnt, cct_ptr, cct[CCT_LNT];
char cbuf[CBUFSIZE], gbuf[CBUFSIZE];
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
ptr = 0;
for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
mask = 0;
if (*cptr == '(') { /* repeat count? */
cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
if (r != SCPE_OK) return SCPE_FMT; }
else rpt = 1;
while (*cptr != 0) { /* get col no's */
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
col = get_uint (gbuf, 10, 12, &r); /* column number */
if (r != SCPE_OK) return SCPE_FMT;
mask = mask | (1 << col); } /* set bit */
for ( ; rpt > 0; rpt--) { /* store vals */
if (ptr >= CCT_LNT) return SCPE_FMT;
cctbuf[ptr++] = mask; } }
if (ptr == 0) return SCPE_FMT;
cct_lnt = ptr;
cct_ptr = 0;
for (rpt = 0; rpt < cct_lnt; rpt++) cct[rpt] = cctbuf[rpt];
return SCPE_OK;
}
/* Symbol table */
struct opc {
char *str; /* mnemonic */
uint32 opv; /* opcode & flags */
uint32 qv; /* q field */
};
#define I_V_FL 16 /* flags */
#define I_M_QX 0x01 /* Q indexable */
#define I_M_QM 0x02 /* Q immediate */
#define I_M_QNP 0x00 /* Q no print */
#define I_M_QCP 0x04 /* Q cond print */
#define I_M_QP 0x08 /* Q print */
#define I_M_PCP 0x00 /* P cond print */
#define I_M_PP 0x10 /* P print */
#define I_GETQF(x) (((x) >> I_V_FL) & 0x03)
#define I_GETQP(x) (((x) >> I_V_FL) & 0x0C)
#define I_GETPP(x) (((x) >> I_V_FL) & 0x10)
#define I_2 ((I_M_PP | I_M_QP | I_M_QX) << I_V_FL)
#define I_2M ((I_M_PP | I_M_QP | I_M_QM) << I_V_FL)
#define I_2X ((I_M_PP | I_M_QP | I_M_QX | I_M_QM) << I_V_FL)
#define I_2S ((I_M_PP | I_M_QP) << I_V_FL)
#define I_1 ((I_M_PP | I_M_QCP) << I_V_FL)
#define I_1E ((I_M_PP | I_M_QNP) << I_V_FL)
#define I_0 ((I_M_PCP | I_M_QCP) << I_V_FL)
#define I_0E ((I_M_PCP | I_M_QNP) << I_V_FL)
struct opc opcode[] = {
{ "RNTY", 36+I_1E, 100 }, { "RATY", 37+I_1E, 100 },
{ "WNTY", 38+I_1E, 100 }, { "WATY", 39+I_1E, 100 },
{ "DNTY", 35+I_1E, 100 }, { "SPTY", 34+I_0E, 101 },
{ "RCTY", 34+I_0E, 102 }, { "BKTY", 34+I_0E, 103 },
{ "IXTY", 34+I_0E, 104 }, { "TBTY", 34+I_0E, 108 },
{ "RNPT", 36+I_1E, 300 }, { "RAPT", 37+I_1E, 300 },
{ "WNPT", 38+I_1E, 200 }, { "WAPT", 39+I_1E, 200 },
{ "DNPT", 35+I_1E, 200 },
{ "RNCD", 36+I_1E, 500 }, { "RACD", 37+I_1E, 500 },
{ "WNCD", 38+I_1E, 400 }, { "WACD", 39+I_1E, 400 },
{ "DNCD", 35+I_1E, 400 },
{ "PRN", 38+I_1E, 900 }, { "PRNS", 38+I_1E, 901 },
{ "PRA", 39+I_1E, 900 }, { "PRAS", 39+I_1E, 901 },
{ "PRD", 35+I_1E, 900 }, { "PRDS", 35+I_1E, 901 },
{ "SK", 34+I_1E, 701 },
{ "RDGN", 36+I_1E, 700 }, { "CDGN", 36+I_1E, 701 },
{ "RDN", 36+I_1E, 702 }, { "CDN", 36+I_1E, 703 },
{ "RTGN", 36+I_1E, 704 }, { "CTGN", 36+I_1E, 705 },
{ "RTN", 36+I_1E, 706 }, { "CTN", 36+I_1E, 707 },
{ "WDGN", 38+I_1E, 700 }, { "WDN", 38+I_1E, 702 },
{ "WTGN", 38+I_1E, 704 }, { "WTN", 38+I_1E, 706 },
{ "RBPT", 37+I_1E, 3300 }, { "WBPT", 39+I_1E, 3200 },
{ "BC1", 46+I_1E, 100 }, { "BNC1", 47+I_1E, 100 },
{ "BC2", 46+I_1E, 200 }, { "BNC2", 47+I_1E, 200 },
{ "BC3", 46+I_1E, 300 }, { "BNC3", 47+I_1E, 300 },
{ "BC4", 46+I_1E, 400 }, { "BNC4", 47+I_1E, 400 },
{ "BLC", 46+I_1E, 900 }, { "BNLC", 47+I_1E, 900 },
{ "BH", 46+I_1E, 1100 }, { "BNH", 47+I_1E, 1100 },
{ "BP", 46+I_1E, 1100 }, { "BNP", 47+I_1E, 1100 },
{ "BE", 46+I_1E, 1200 }, { "BNE", 47+I_1E, 1200 },
{ "BZ", 46+I_1E, 1200 }, { "BNZ", 47+I_1E, 1200 },
{ "BNL", 46+I_1E, 1300 }, { "BL", 47+I_1E, 1300 },
{ "BNN", 46+I_1E, 1300 }, { "BN", 47+I_1E, 1300 },
{ "BV", 46+I_1E, 1400 }, { "BNV", 47+I_1E, 1400 },
{ "BXV", 46+I_1E, 1500 }, { "BNXV", 47+I_1E, 1500 },
{ "BA", 46+I_1E, 1900 }, { "BNA", 47+I_1E, 1900 },
{ "BNBS", 46+I_1E, 3000 }, { "BEBS", 47+I_1E, 3000 },
{ "BBAS", 46+I_1E, 3100 }, { "BANS", 47+I_1E, 3100 },
{ "BBBS", 46+I_1E, 3200 }, { "BBNS", 47+I_1E, 3200 },
{ "BCH9", 46+I_1E, 3300 },
{ "BCOV", 46+I_1E, 3400 },
{ "BSNX", 60+I_1E, 0 }, { "BSBA", 60+I_1E, 1 },
{ "BSBB", 60+I_1E, 2 },
{ "BSNI", 60+I_1E, 8 }, { "BSIA", 60+I_1E, 9 },
{ "FADD", 1+I_2, 0 }, { "FSUB", 2+I_2, 0 },
{ "FMUL", 3+I_2, 0 }, { "FSL", 5+I_2, 0 },
{ "TFL", 6+I_2, 0 }, { "BTFL", 7+I_2, 0 },
{ "FSR", 8+I_2, 0 }, { "FDIV", 9+I_2, 0 },
{ "BTAM", 10+I_2M, 0 }, { "AM", 11+I_2M, 0 },
{ "SM", 12+I_2M, 0 }, { "MM", 13+I_2M, 0 },
{ "CM", 14+I_2M, 0 }, { "TDM", 15+I_2S, 0 },
{ "TFM", 16+I_2M, 0 }, { "BTM", 17+I_2M, 0 },
{ "LDM", 18+I_2M, 0 }, { "DM", 19+I_2M, 0 },
{ "BTA", 20+I_2, 0 }, { "A", 21+I_2, 0 },
{ "S", 22+I_2, 0 }, { "M", 23+I_2, 0 },
{ "C", 24+I_2, 0 }, { "TD", 25+I_2, 0 },
{ "TF", 26+I_2, 0 }, { "BT", 27+I_2, 0 },
{ "LD", 28+I_2, 0 }, { "D", 29+I_2, 0 },
{ "TRNM", 30+I_2, 0 }, { "TR", 31+I_2, 0 },
{ "SF", 32+I_1, 0 }, { "CF", 33+I_1, 0 },
{ "K", 34+I_2S, 0 }, { "DN", 35+I_2S, 0 },
{ "RN", 36+I_2S, 0 }, { "RA", 37+I_2S, 0 },
{ "WN", 38+I_2S, 0 }, { "WA", 39+I_2S, 0 },
{ "NOP", 41+I_0, 0 }, { "BB", 42+I_0, 0 },
{ "BD", 43+I_2, 0 }, { "BNF", 44+I_2, 0 },
{ "BNR", 45+I_2, 0 }, { "BI", 46+I_2S, 0 },
{ "BNI", 47+I_2S, 0 }, { "H", 48+I_0, 0 },
{ "B", 49+I_1, 0 }, { "BNG", 55+I_2, 0 },
{ "BS", 60+I_2S, 0 }, { "BX", 61+I_2, 0 },
{ "BXM", 62+I_2X, 0 }, { "BCX", 63+I_2, 0 },
{ "BCXM", 64+I_2X, 0 }, { "BLX", 65+I_2, 0 },
{ "BLXM", 66+I_2X, 0 }, { "BSX", 67+I_2, 0 },
{ "MA", 70+I_2, 0 }, { "MF", 71+I_2, 0 },
{ "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 },
{ "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 },
{ "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 },
{ "CPFL", 94+I_2, 0 }, { "EORF", 95+I_2, 0 },
{ "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 },
{ NULL, 0, 0 } };
/* Print an address from five characters */
void fprint_addr (FILE *of, int32 spc, t_value *dig, t_bool flg)
{
int32 i, idx;
fputc (spc, of); /* spacer */
if (dig[ADDR_LEN - 1] & FLAG) { /* signed? */
fputc ('-', of); /* print minus */
dig[ADDR_LEN - 1] = dig[ADDR_LEN - 1] & ~FLAG; }
for (i = 0; i < ADDR_LEN; i++) /* print digits */
fprintf (of, "%X", dig[i] & DIGIT);
if ((cpu_unit.flags & IF_IDX) && flg) { /* indexing? */
for (i = idx = 0; i < ADDR_LEN - 2; i++) { /* get index reg */
if (dig[ADDR_LEN - 2 - i] & FLAG)
idx = idx | (1 << i);
dig[ADDR_LEN - 2 - i] = dig[ADDR_LEN - 2 - i] & ~FLAG; }
if (idx) fprintf (of, "(%d)", idx); } /* print */
return;
}
/* Symbolic decode
Inputs:
*of = output stream
addr = current address
*val = values to decode
*uptr = pointer to unit
sw = switches
Outputs:
return = if >= 0, error code
if < 0, number of extra words retired
*/
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
int32 pmp, qmp, i, c, d, any;
uint32 op, qv, opfl;
if (uptr == NULL) uptr = &cpu_unit;
if (sw & SWMASK ('C')) { /* character? */
if (uptr->flags & UNIT_BCD) {
if (addr & 1) return SCPE_ARG; /* must be even */
c = ((val[0] & DIGIT) << 4) | (val[1] & DIGIT);
if (alp_to_cdp[c] > 0)
fprintf (of, "%c", alp_to_cdp[c]);
else fprintf (of, "<%02x>", c);
return -1; }
else fprintf (of, FMTASC (val[0] & 0177));
return SCPE_OK; }
if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */
if (sw & SWMASK ('D')) { /* dump? */
for (i = d = 0; i < LINE_LNT; i++) d = d | val[i];
if (d & FLAG) { /* any flags? */
for (i = 0; i < LINE_LNT; i++) /* print flags */
fprintf (of, (val[i] & FLAG)? "_": " ");
fprintf (of, "\n\t"); }
for (i = 0; i < LINE_LNT; i++) /* print digits */
fprintf (of, "%X", val[i] & DIGIT) ;
return -(i - 1); }
if (sw & SWMASK ('S')) { /* string? */
if (addr & 1) return SCPE_ARG; /* must be even */
for (i = 0; i < LINE_LNT; i = i + 2) {
c = ((val[i] & DIGIT) << 4) | (val[i + 1] & DIGIT);
if (alp_to_cdp[c] < 0) break;
fprintf (of, "%c", alp_to_cdp[c]); }
if (i == 0) {
fprintf (of, "<%02X>", c);
return -1; }
return -(i - 1); }
if ((sw & SWMASK ('M')) == 0) return SCPE_ARG;
if (addr & 1) return SCPE_ARG; /* must be even */
op = ((val[0] & DIGIT) * 10) + (val[1] & DIGIT); /* get opcode */
for (i = qv = pmp = qmp = 0; i < ADDR_LEN; i++) { /* test addr */
if (val[I_P + i]) pmp = 1;
if (val[I_Q + i]) qmp = 1;
qv = (qv * 10) + (val[I_Q + i] & DIGIT); }
if ((val[0] | val[1]) & FLAG) pmp = qmp = 1; /* flags force */
for (i = 0; opcode[i].str != NULL; i++) { /* find opcode */
opfl = opcode[i].opv & 0xFF0000;
if ((op == (opcode[i].opv & 0xFF)) &&
((qv == opcode[i].qv) ||
((opfl != I_1E) && (opfl != I_0E)))) break; }
if (opcode[i].str == NULL) return SCPE_ARG;
if (I_GETQP (opfl) == I_M_QNP) qmp = 0; /* Q no print? */
fprintf (of, opcode[i].str); /* print opcode */
if (I_GETPP (opfl) == I_M_PP) /* P required? */
fprint_addr (of, ' ', &val[I_P], I_M_QX);
else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */
fprint_addr (of, ' ', &val[I_P], 0);
if (I_GETQP (opfl) == I_M_QP) { /* Q required? */
fprint_addr (of, ',', &val[I_Q], I_GETQF (opfl));
if (I_GETQF (opfl) & I_M_QM) /* immediate? */
val[I_Q] = val[I_Q] & ~FLAG; } /* clr hi Q flag */
else if ((I_GETQP (opfl) == I_M_QCP) && (pmp || qmp)) /* Q opt & needed? */
fprint_addr (of, ',', &val[I_Q], 0);
for (i = any = 0; i < INST_LEN; i++) { /* print rem flags */
if (val[i] & FLAG) {
if (!any) fputc (',', of);
any = 1;
fprintf (of, "%d", i); } }
return -(INST_LEN - 1);
}
/* parse_addr - get sign + address + index */
t_stat parse_addr (char *cptr, t_value *val, int32 flg)
{
int32 i, sign = 0, addr, index;
static int32 idx_tst[ADDR_LEN] = { 0, 4, 2, 1, 0 };
char *tptr;
if (*cptr == '+') cptr++; /* +? skip */
else if (*cptr == '-') { /* -? skip, flag */
sign = 1;
cptr++; }
errno = 0; /* get address */
addr = strtoul (cptr, &tptr, 16);
if (errno || (cptr == tptr) || (addr > 0xFFFFF)) /* err or too big? */
return SCPE_ARG;
if ((cpu_unit.flags & IF_IDX) && (flg & I_M_QX) && /* index allowed? */
(*tptr == '(')) { /* index specified */
errno = 0;
index = strtoul (cptr = tptr + 1, &tptr, 10); /* get index */
if (errno || (cptr == tptr) || (index > 7)) /* err or too big? */
return SCPE_ARG;
if (*tptr++ != ')') return SCPE_ARG; }
else index = 0;
if (*tptr != 0) return SCPE_ARG; /* all done? */
for (i = ADDR_LEN - 1; i >= 0; i--) { /* cvt addr to dig */
val[i] = (addr & 0xF) | ((index & idx_tst[i])? FLAG: 0);
addr = addr >> 4; }
if (sign) val[ADDR_LEN - 1] = val[ADDR_LEN - 1] | FLAG; /* set sign */
if (flg & I_M_QM) val[0] = val[0] | FLAG; /* set immediate */
return SCPE_OK;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
*uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = > 0 error code
<= 0 -number of extra words
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 i, qv, opfl, last;
char t, la, *fptr, gbuf[CBUFSIZE];
while (isspace (*cptr)) cptr++; /* absorb spaces */
if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */
if ((t = *cptr & 0x7F) == 0) return SCPE_ARG; /* get char */
if (uptr->flags & UNIT_BCD) { /* BCD? */
if (addr & 1) return SCPE_ARG;
t = cdr_to_alp[t]; /* convert */
if (t < 0) return SCPE_ARG; /* invalid? */
val[0] = (t >> 4) & DIGIT; /* store */
val[1] = t & DIGIT;
return -1; }
else val[0] = t; /* store ASCII */
return SCPE_OK; }
if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */
if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* string? */
if (addr & 1) return SCPE_ARG; /* must be even */
for (i = 0; (i < sim_emax) && (*cptr != 0); i = i + 2) {
t = *cptr++ & 0x7F; /* get character */
t = cdr_to_alp[t]; /* convert */
if (t < 0) return SCPE_ARG; /* invalid? */
val[i] = (t >> 4) & DIGIT; /* store */
val[i + 1] = t & DIGIT; }
if (i == 0) return SCPE_ARG; /* final check */
return -(i - 1); }
if (addr & 1) return SCPE_ARG; /* even addr? */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; opcode[i].str != NULL; i++) { /* look it up */
if (strcmp (gbuf, opcode[i].str) == 0) break; }
if (opcode[i].str == NULL) return SCPE_ARG; /* successful? */
opfl = opcode[i].opv & 0xFF0000; /* get flags */
val[0] = (opcode[i].opv & 0xFF) / 10; /* store opcode */
val[1] = (opcode[i].opv & 0xFF) % 10;
qv = opcode[i].qv;
for (i = ADDR_LEN - 1; i >= 0; i--) { /* set P,Q fields */
val[I_P + i] = 0;
val[I_Q + i] = qv % 10;
qv = qv /10; }
cptr = get_glyph (cptr, gbuf, ','); /* get P field */
if (gbuf[0]) { /* any? */
if (parse_addr (gbuf, &val[I_P], (I_GETPP (opfl)?
I_M_QX: 0))) return SCPE_ARG; }
else if (I_GETPP (opfl) == I_M_PP) return SCPE_ARG;
if (I_GETQP (opfl) != I_M_QNP) { /* Q field allowed? */
cptr = get_glyph (cptr, gbuf, ','); /* get Q field */
if (gbuf[0]) { /* any? */
if (parse_addr (gbuf, &val[I_Q], I_GETQF (opfl)))
return SCPE_ARG; }
else if (I_GETQP (opfl) == I_M_QP) return SCPE_ARG; }
cptr = get_glyph (cptr, fptr = gbuf, ' '); /* get flag field */
last = -1; /* none yet */
while (t = *fptr++) { /* loop through */
if ((t < '0') || (t > '9')) return SCPE_ARG; /* must be digit */
t = t - '0'; /* convert */
if (t == 1) { /* ambiguous? */
la = *fptr++; /* get next */
if (la == '0') t = 10; /* 10? */
else if ((la == '1') && (*fptr == 0)) t = 11; /* 11 & end field? */
else --fptr; } /* dont lookahead */
if (t <= last) return SCPE_ARG; /* in order? */
val[t] = val[t] | FLAG; /* set flag */
last = t; } /* continue */
if (*cptr != 0) return SCPE_ARG;
return -(INST_LEN - 1);
}

345
I1620/i1620_tty.c Normal file
View File

@@ -0,0 +1,345 @@
/* i1620_tty.c: IBM 1620 typewriter
Copyright (c) 2002, 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.
tty console typewriter
*/
#include "i1620_defs.h"
#define TTO_COLMAX 80
int32 tto_col = 0;
extern uint8 M[MAXMEMSIZE];
extern uint8 ind[NUM_IND];
extern UNIT cpu_unit;
extern uint32 io_stop;
void tti_unlock (void);
t_stat tti_rnum (int8 *c);
t_stat tti_ralp (int8 *c);
t_stat tti_read (int8 *c);
t_stat tto_num (uint32 pa, uint32 len);
t_stat tto_write (uint32 c);
t_stat tty_svc (UNIT *uptr);
t_stat tty_reset (DEVICE *dptr);
/* TTY data structures
tty_dev TTY device descriptor
tty_unit TTY unit descriptor
tty_reg TTY register list
*/
UNIT tty_unit = { UDATA (&tty_svc, 0, 0), KBD_POLL_WAIT };
REG tty_reg[] = {
{ DRDATA (COL, tto_col, 7) },
{ DRDATA (TIME, tty_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL } };
DEVICE tty_dev = {
"TTY", &tty_unit, tty_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &tty_reset,
NULL, NULL, NULL };
/* Data tables */
/* Keyboard to numeric */
const char *tti_to_num = "0123456789'=@:;\"";
/* Keyboard to alphameric (digit pair) - translates LC to UC */
const int8 tti_to_alp[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, /* 00 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1,
0x00, 0x02, 0x0F, -1, 0x13, -1, -1, -1, /* !"#$%&' */
0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */
0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89:;<=>? */
0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */
0x67, 0x68, 0x69, -1, -1, -1, -1, -1, /* XYZ[\]^_ */
-1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */
0x67, 0x68, 0x69, -1, -1, -1, -1, -1 }; /* xyz */
/* Numeric (digit) to typewriter */
const char num_to_tto[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '\'', '=', '@', ':', ';', '"' };
/* Alphameric (digit pair) to typewriter */
const char alp_to_tto[256] = {
' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */
-1, -1, -1, -1, -1, -1, -1, -1,
'+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1,
'-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, '0', '=', '@', ':', -1, -1, /* 30 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
'H', 'I', -1, -1, -1, -1, -1, -1,
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
'Q', 'R', -1, -1, -1, -1, -1, -1,
-1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
'Y', 'Z', -1, -1, -1, -1, -1, -1,
'0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
'8', '9', -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
-1, -1, -1, -1, -1, -1, -1, -1 };
/* Terminal IO
- On input, parity errors cannot occur.
- On input, release-start does NOT cause a record mark to be stored.
- On output, invalid characters type an invalid character and set WRCHK.
If IO stop is set, the system halts at the end of the operation.
*/
t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
t_addr i;
uint8 d;
int8 ttc;
t_stat r, inv = SCPE_OK;
switch (op) { /* case on op */
case OP_K: /* control */
switch (f1) { /* case on control */
case 1: /* space */
tto_write (' ');
break;
case 2: /* return */
tto_write ('\r');
break;
case 3: /* backspace */
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
tto_write ('\b');
break;
case 4: /* index */
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
tto_write ('\n');
break;
case 8: /* tab */
tto_write ('\t');
break;
default:
return STOP_INVFNC; }
return SCPE_OK;
case OP_RN: /* read numeric */
tti_unlock (); /* unlock keyboard */
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
r = tti_rnum (&ttc); /* read char */
if (r != SCPE_OK) return r; /* error? */
if (ttc == 0x7F) return SCPE_OK; /* end record? */
M[pa] = ttc & (FLAG | DIGIT); /* store char */
PP (pa); } /* incr mem addr */
break;
case OP_RA: /* read alphameric */
tti_unlock ();
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = tti_ralp (&ttc); /* read char */
if (r != SCPE_OK) return r; /* error? */
if (ttc == 0x7F) return SCPE_OK; /* end record? */
M[pa] = (M[pa] & FLAG) | (ttc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((ttc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
case OP_DN:
return tto_num (pa, 20000 - (pa % 20000)); /* dump numeric */
case OP_WN:
return tto_num (pa, 0); /* type numeric */
case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
d = M[pa] & DIGIT; /* get digit */
if ((d & 0xA) == REC_MARK) /* 8-2 char? */
CRETIOE (io_stop, inv); /* end record */
d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */
ttc = alp_to_tto[d]; /* translate */
if (ttc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
inv = STOP_INVCHR; } /* set return status */
tto_write (ttc & 0x7F); /* write */
pa = ADDR_A (pa, 2); } /* incr mem addr */
break;
default: /* invalid function */
return STOP_INVFNC; }
return STOP_RWRAP;
}
/* Read numerically - cannot generate parity errors */
t_stat tti_rnum (int8 *c)
{
int8 flg = 0;
char *cp, raw;
t_stat r;
*c = -1; /* no char yet */
do { r = tti_read (&raw); /* get char */
if (r != SCPE_OK) return r; /* error? */
if (raw == '\r') *c = 0x7F; /* return? mark */
else if (raw == '~') flg = FLAG; /* flag? mark */
else if (cp = strchr (tti_to_num, raw)) /* legal? */
*c = ((int8) (cp - tti_to_num)) | flg; /* assemble char */
else raw = 007; /* beep! */
tto_write (raw); } /* echo */
while (*c == -1);
return SCPE_OK;
}
/* Read alphamerically - cannot generate parity errors */
t_stat tti_ralp (int8 *c)
{
char raw;
t_stat r;
*c = -1; /* no char yet */
do { r = tti_read (&raw); /* get char */
if (r != SCPE_OK) return r; /* error? */
if (raw == '\r') *c = 0x7F; /* return? mark */
else if (tti_to_alp[raw] >= 0) /* legal char? */
*c = tti_to_alp[raw]; /* xlate */
else raw = 007; /* beep! */
tto_write (raw); } /* echo */
while (*c == -1);
return SCPE_OK;
}
/* Read from keyboard */
t_stat tti_read (int8 *c)
{
int32 t;
do { t = sim_poll_kbd (); } /* get character */
while (t == SCPE_OK);
if (t < SCPE_KFLAG) return t; /* error? */
*c = t & 0177; /* store character */
return SCPE_OK;
}
/* Write numerically - cannot generate parity errors */
t_stat tto_num (uint32 pa, uint32 len)
{
t_stat r;
uint8 d;
uint32 i, end;
end = pa + len;
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
d = M[pa]; /* get char */
if (len? (pa >= end): /* dump: end reached? */
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
return SCPE_OK; /* end operation */
if (d & FLAG) tto_write ('~'); /* flag? */
r = tto_write (num_to_tto[d & DIGIT]); /* write */
if (r != SCPE_OK) return r; /* error? */
PP (pa); } /* incr mem addr */
return STOP_RWRAP;
}
/* Write, maintaining position */
t_stat tto_write (uint32 c)
{
int32 rpt;
if (c == '\t') { /* tab? */
rpt = 8 - (tto_col % 8); /* distance to next */
tto_col = tto_col + rpt; /* tab over */
while (rpt-- > 0) sim_putchar (' '); /* use spaces */
return SCPE_OK; }
if (c == '\r') { /* return? */
sim_putchar ('\r'); /* crlf */
sim_putchar ('\n');
tto_col = 0; /* clear colcnt */
return SCPE_OK; }
if ((c == '\n') || (c == 007)) { /* non-spacing? */
sim_putchar (c);
return SCPE_OK; }
if (c == '\b') tto_col = tto_col? tto_col - 1: 0; /* backspace? */
else tto_col++; /* normal */
if (tto_col > TTO_COLMAX) { /* line wrap? */
sim_putchar ('\r');
sim_putchar ('\n');
tto_col = 0; }
sim_putchar (c);
return SCPE_OK;
}
/* Unit service - polls for WRU */
t_stat tty_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&tty_unit, tty_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
return SCPE_OK;
}
/* Reset routine */
t_stat tty_reset (DEVICE *dptr)
{
sim_activate (&tty_unit, tty_unit.wait); /* activate poll */
tto_col = 0;
return SCPE_OK;
}
/* TTI unlock - signals that we are ready for keyboard input */
void tti_unlock (void)
{
tto_write ('`');
return;
}